obsidian-e2e 0.5.0 → 0.6.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 +21 -18
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/matchers.d.mts +1 -1
- package/dist/matchers.mjs +5 -1
- package/dist/matchers.mjs.map +1 -1
- package/dist/{test-context-BprSx6U1.mjs → test-context-Bl-e-83H.mjs} +150 -355
- package/dist/test-context-Bl-e-83H.mjs.map +1 -0
- package/dist/{types-C4cj443K.d.mts → types-BUXaueDI.d.mts} +2 -4
- package/dist/{vault-lock-CYyOdRP1.d.mts → vault-lock-XcBHtwm9.d.mts} +2 -2
- package/dist/vitest.d.mts +1 -1
- package/dist/vitest.mjs +1 -1
- package/package.json +1 -1
- package/dist/test-context-BprSx6U1.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-context-Bl-e-83H.mjs","names":["DEFAULT_TIMEOUT_MS","DEFAULT_TIMEOUT_MS","sleep","sleep","pathPosix","pathPosix"],"sources":["../src/core/args.ts","../src/core/exec-options.ts","../src/core/internals.ts","../src/core/errors.ts","../src/dev/eval-json.ts","../src/metadata/metadata.ts","../src/vault/json-file.ts","../src/plugin/plugin.ts","../src/core/transport.ts","../src/dev/diagnostics.ts","../src/core/wait.ts","../src/core/client.ts","../src/core/path-slug.ts","../src/vault/paths.ts","../src/vault/vault.ts","../src/artifacts/failure-artifacts.ts","../src/vault/sandbox.ts","../src/fixtures/vault-lock.ts","../src/fixtures/base-fixtures.ts","../src/fixtures/test-context.ts"],"sourcesContent":["import type { ObsidianArg } from \"./types\";\n\nexport function buildCommandArgv(\n vaultName: string,\n command: string,\n args: Record<string, ObsidianArg> = {},\n): string[] {\n const argv = [`vault=${vaultName}`, command];\n\n for (const [key, value] of Object.entries(args)) {\n if (value === false || value === null || value === undefined) {\n continue;\n }\n\n if (value === true) {\n argv.push(key);\n continue;\n }\n\n argv.push(`${key}=${String(value)}`);\n }\n\n return argv;\n}\n","import type { ExecOptions } from \"./types\";\n\nexport function mergeExecOptions(\n defaults: ExecOptions | undefined,\n overrides: ExecOptions | undefined,\n): ExecOptions {\n if (!defaults) {\n return overrides ? { ...overrides } : {};\n }\n\n if (!overrides) {\n return { ...defaults };\n }\n\n return {\n ...defaults,\n ...overrides,\n env: mergeEnvironments(defaults.env, overrides.env),\n };\n}\n\nfunction mergeEnvironments(\n defaults: NodeJS.ProcessEnv | undefined,\n overrides: NodeJS.ProcessEnv | undefined,\n): NodeJS.ProcessEnv | undefined {\n if (!defaults) {\n return overrides ? { ...overrides } : undefined;\n }\n\n if (!overrides) {\n return { ...defaults };\n }\n\n return {\n ...defaults,\n ...overrides,\n };\n}\n","import { rm, writeFile } from \"node:fs/promises\";\n\nimport type { ObsidianClient } from \"./types\";\n\ninterface SnapshotEntry {\n exists: boolean;\n value: string;\n}\n\ninterface ClientInternals {\n restoreAll(): Promise<void>;\n restoreFile(filePath: string): Promise<void>;\n snapshotFileOnce(filePath: string): Promise<void>;\n}\n\nconst clientInternals = new WeakMap<ObsidianClient, ClientInternals>();\n\nexport function attachClientInternals(client: ObsidianClient, internals: ClientInternals): void {\n clientInternals.set(client, internals);\n}\n\nexport function getClientInternals(client: ObsidianClient): ClientInternals {\n const internals = clientInternals.get(client);\n\n if (!internals) {\n throw new Error(\"Missing obsidian client internals.\");\n }\n\n return internals;\n}\n\nexport function createRestoreManager(readFile: (filePath: string) => Promise<string>) {\n const snapshots = new Map<string, SnapshotEntry>();\n\n return {\n async restoreAll() {\n const entries = [...snapshots.entries()].reverse();\n\n for (const [filePath, snapshot] of entries) {\n await restoreSnapshot(filePath, snapshot);\n }\n\n snapshots.clear();\n },\n async restoreFile(filePath: string) {\n const snapshot = snapshots.get(filePath);\n\n if (!snapshot) {\n return;\n }\n\n await restoreSnapshot(filePath, snapshot);\n snapshots.delete(filePath);\n },\n async snapshotFileOnce(filePath: string) {\n if (snapshots.has(filePath)) {\n return;\n }\n\n try {\n snapshots.set(filePath, {\n exists: true,\n value: await readFile(filePath),\n });\n } catch (error) {\n if (isMissingFileError(error)) {\n snapshots.set(filePath, {\n exists: false,\n value: \"\",\n });\n return;\n }\n\n throw error;\n }\n },\n };\n}\n\nasync function restoreSnapshot(filePath: string, snapshot: SnapshotEntry): Promise<void> {\n if (snapshot.exists) {\n await writeFile(filePath, snapshot.value, \"utf8\");\n return;\n }\n\n await rm(filePath, { force: true, recursive: true });\n}\n\nfunction isMissingFileError(error: unknown): error is NodeJS.ErrnoException {\n return Boolean(error && typeof error === \"object\" && \"code\" in error && error.code === \"ENOENT\");\n}\n","import type { ExecResult } from \"./types\";\nimport type { DevEvalErrorPayload } from \"./types\";\n\nexport class ObsidianCommandError extends Error {\n readonly result: ExecResult;\n\n constructor(message: string, result: ExecResult) {\n super(message);\n this.name = \"ObsidianCommandError\";\n this.result = result;\n }\n}\n\nexport class WaitForTimeoutError extends Error {\n readonly causeError?: unknown;\n\n constructor(message: string, causeError?: unknown) {\n super(message);\n this.name = \"WaitForTimeoutError\";\n this.causeError = causeError;\n }\n}\n\nexport class DevEvalError extends Error {\n readonly remote: DevEvalErrorPayload;\n\n constructor(message: string, remote: DevEvalErrorPayload) {\n super(message);\n this.name = \"DevEvalError\";\n this.remote = remote;\n\n if (remote.stack) {\n this.stack = `${this.name}: ${message}\\nRemote stack:\\n${remote.stack}`;\n }\n }\n}\n","import { DevEvalError } from \"../core/errors\";\nimport type { DevEvalErrorPayload, ExecOptions, ObsidianDevHandle } from \"../core/types\";\n\ninterface EvalJsonSuccess {\n ok: true;\n value: unknown;\n}\n\ninterface EvalJsonFailure {\n error: DevEvalErrorPayload;\n ok: false;\n}\n\ntype EvalJsonEnvelope = EvalJsonFailure | EvalJsonSuccess;\n\ninterface UndefinedSentinel {\n __obsidianE2EType: \"undefined\";\n}\n\nexport async function runEvalJson<T>(\n dev: Pick<ObsidianDevHandle, \"evalRaw\">,\n code: string,\n execOptions: ExecOptions = {},\n): Promise<T> {\n return parseEvalJsonEnvelope<T>(await dev.evalRaw(buildEvalJsonCode(code), execOptions));\n}\n\nexport function buildEvalJsonCode(code: string): string {\n return [\n \"(()=>{\",\n `const __obsidianE2ECode=${JSON.stringify(code)};`,\n \"const __obsidianE2ESerialize=(value,path='$')=>{\",\n \"if(value===null){return null;}\",\n \"if(value===undefined){return {__obsidianE2EType:'undefined'};}\",\n \"const valueType=typeof value;\",\n \"if(valueType==='string'||valueType==='boolean'){return value;}\",\n \"if(valueType==='number'){if(!Number.isFinite(value)){throw new Error(`Cannot serialize non-finite number at ${path}.`);}return value;}\",\n \"if(valueType==='bigint'||valueType==='function'||valueType==='symbol'){throw new Error(`Cannot serialize ${valueType} at ${path}.`);}\",\n \"if(Array.isArray(value)){return value.map((item,index)=>__obsidianE2ESerialize(item,`${path}[${index}]`));}\",\n \"const prototype=Object.getPrototypeOf(value);\",\n \"if(prototype!==Object.prototype&&prototype!==null){throw new Error(`Cannot serialize non-plain object at ${path}.`);}\",\n \"const next={};\",\n \"for(const [key,entry] of Object.entries(value)){next[key]=__obsidianE2ESerialize(entry,`${path}.${key}`);}\",\n \"return next;\",\n \"};\",\n \"try{\",\n \"return JSON.stringify({ok:true,value:__obsidianE2ESerialize((0,eval)(__obsidianE2ECode))});\",\n \"}catch(error){\",\n \"return JSON.stringify({ok:false,error:{message:error instanceof Error?error.message:String(error),name:error instanceof Error?error.name:'Error',stack:error instanceof Error?error.stack:undefined}});\",\n \"}\",\n \"})()\",\n ].join(\"\");\n}\n\nexport function parseDevEvalOutput<T>(raw: string): T {\n const normalized = normalizeEvalOutput(raw);\n\n try {\n return JSON.parse(normalized) as T;\n } catch {\n return normalized as T;\n }\n}\n\nexport function parseEvalJsonEnvelope<T>(raw: string): T {\n const envelope = JSON.parse(normalizeEvalOutput(raw)) as EvalJsonEnvelope;\n\n if (!envelope.ok) {\n throw new DevEvalError(`Failed to evaluate Obsidian code: ${envelope.error.message}`, {\n ...envelope.error,\n });\n }\n\n return decodeEvalJsonValue(envelope.value) as T;\n}\n\nfunction normalizeEvalOutput(raw: string): string {\n return raw.startsWith(\"=> \") ? raw.slice(3) : raw;\n}\n\nfunction decodeEvalJsonValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map((entry) => decodeEvalJsonValue(entry));\n }\n\n if (!value || typeof value !== \"object\") {\n return value;\n }\n\n if (isUndefinedSentinel(value)) {\n return undefined;\n }\n\n return Object.fromEntries(\n Object.entries(value).map(([key, entry]) => [key, decodeEvalJsonValue(entry)]),\n );\n}\n\nfunction isUndefinedSentinel(value: object): value is UndefinedSentinel {\n return \"__obsidianE2EType\" in value && value.__obsidianE2EType === \"undefined\";\n}\n","import type {\n ExecOptions,\n MetadataFileCache,\n MetadataPredicate,\n MetadataWaitOptions,\n NoteFrontmatter,\n ObsidianClient,\n ObsidianMetadataHandle,\n} from \"../core/types\";\nimport { runEvalJson } from \"../dev/eval-json\";\n\nexport function createObsidianMetadataHandle(client: ObsidianClient): ObsidianMetadataHandle {\n return {\n async fileCache<T = MetadataFileCache>(path: string, execOptions?: ExecOptions) {\n return readMetadata<T | null>(client, \"metadata\", path, execOptions);\n },\n async frontmatter<T extends NoteFrontmatter = NoteFrontmatter>(\n path: string,\n execOptions?: ExecOptions,\n ) {\n return readMetadata<T | null>(client, \"frontmatter\", path, execOptions);\n },\n async waitForFileCache<T = MetadataFileCache>(\n path: string,\n predicate?: MetadataPredicate<T>,\n options?: MetadataWaitOptions,\n ) {\n return waitForPresentValue(\n client,\n path,\n () => client.metadata.fileCache<T>(path),\n predicate,\n \"metadata cache\",\n options,\n );\n },\n async waitForFrontmatter<T extends NoteFrontmatter = NoteFrontmatter>(\n path: string,\n predicate?: MetadataPredicate<T>,\n options?: MetadataWaitOptions,\n ) {\n return waitForPresentValue(\n client,\n path,\n () => client.metadata.frontmatter<T>(path),\n predicate,\n \"frontmatter\",\n options,\n );\n },\n async waitForMetadata<T = MetadataFileCache>(\n path: string,\n predicate?: MetadataPredicate<T>,\n options?: MetadataWaitOptions,\n ) {\n return waitForPresentValue(\n client,\n path,\n () => client.metadata.fileCache<T>(path),\n predicate,\n \"metadata\",\n options,\n );\n },\n };\n}\n\nasync function readMetadata<T>(\n client: ObsidianClient,\n method: \"frontmatter\" | \"metadata\",\n path: string,\n execOptions?: ExecOptions,\n): Promise<T> {\n return runEvalJson<T>(client.dev, buildMetadataReadCode(method, path), execOptions);\n}\n\nfunction buildMetadataReadCode(method: \"frontmatter\" | \"metadata\", path: string): string {\n return [\n \"(()=>{\",\n `const __obsidianE2EPath=${JSON.stringify(path)};`,\n \"const __obsidianE2EFile=app?.vault?.getAbstractFileByPath?.(__obsidianE2EPath);\",\n \"if(!__obsidianE2EFile){return null;}\",\n method === \"frontmatter\"\n ? \"return app?.metadataCache?.getFileCache?.(__obsidianE2EFile)?.frontmatter ?? null;\"\n : \"return app?.metadataCache?.getFileCache?.(__obsidianE2EFile) ?? null;\",\n \"})()\",\n ].join(\"\");\n}\n\nasync function waitForPresentValue<T>(\n client: ObsidianClient,\n path: string,\n readValue: () => Promise<T | null>,\n predicate: MetadataPredicate<T> | undefined,\n label: string,\n options: MetadataWaitOptions = {},\n): Promise<T> {\n return client.waitFor(\n async () => {\n const value = await readValue();\n\n if (value === null) {\n return false;\n }\n\n return (await (predicate?.(value) ?? true)) ? value : false;\n },\n {\n ...options,\n message: options.message ?? `vault path \"${path}\" to expose ${label}`,\n },\n );\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { JsonFile, JsonFileUpdater } from \"../core/types\";\n\nexport function createJsonFile<T = unknown>(\n filePath: string,\n beforeMutate?: () => Promise<void>,\n): JsonFile<T> {\n return {\n async patch(updater: JsonFileUpdater<T>) {\n await beforeMutate?.();\n\n const currentValue = await this.read();\n const draft = structuredClone(currentValue);\n const result = await updater(draft);\n const nextValue = result ?? draft;\n\n await this.write(nextValue);\n\n return nextValue;\n },\n async read() {\n const value = await readFile(filePath, \"utf8\");\n return JSON.parse(value) as T;\n },\n async write(value: T) {\n await beforeMutate?.();\n await mkdir(path.dirname(filePath), { recursive: true });\n await writeFile(filePath, `${JSON.stringify(value, null, 2)}\\n`, \"utf8\");\n },\n };\n}\n","import path from \"node:path\";\n\nimport { getClientInternals } from \"../core/internals\";\nimport type {\n JsonFile,\n JsonFileUpdater,\n ObsidianClient,\n PluginDataPredicate,\n PluginHandle,\n PluginReloadOptions,\n PluginToggleOptions,\n PluginUpdateDataOptions,\n PluginWithPatchedDataOptions,\n PluginWaitForDataOptions,\n PluginWaitUntilReadyOptions,\n} from \"../core/types\";\nimport { runEvalJson } from \"../dev/eval-json\";\nimport { createJsonFile } from \"../vault/json-file\";\n\nexport function createPluginHandle(client: ObsidianClient, id: string): PluginHandle {\n async function resolveDataPath() {\n const vaultPath = await client.vaultPath();\n return path.join(vaultPath, \".obsidian\", \"plugins\", id, \"data.json\");\n }\n\n async function isLoadedInApp(): Promise<boolean> {\n try {\n return await runEvalJson<boolean>(client.dev, buildPluginLoadedCode(id));\n } catch {\n return false;\n }\n }\n\n function withDefaultReadyReloadOptions(options: PluginReloadOptions = {}): PluginReloadOptions {\n return {\n ...options,\n waitUntilReady: options.waitUntilReady ?? true,\n };\n }\n\n return {\n data<T = unknown>(): JsonFile<T> {\n return {\n async patch(updater) {\n const dataPath = await resolveDataPath();\n return createJsonFile<T>(dataPath, () =>\n getClientInternals(client).snapshotFileOnce(dataPath),\n ).patch(updater);\n },\n async read() {\n const dataPath = await resolveDataPath();\n return createJsonFile<T>(dataPath).read();\n },\n async write(value) {\n const dataPath = await resolveDataPath();\n await createJsonFile<T>(dataPath, () =>\n getClientInternals(client).snapshotFileOnce(dataPath),\n ).write(value);\n },\n };\n },\n async dataPath() {\n return resolveDataPath();\n },\n async disable(options: PluginToggleOptions = {}) {\n await client.exec(\"plugin:disable\", {\n filter: options.filter,\n id,\n });\n },\n async enable(options: PluginToggleOptions = {}) {\n await client.exec(\"plugin:enable\", {\n filter: options.filter,\n id,\n });\n },\n id,\n async isEnabled() {\n const output = await client.execText(\"plugin\", { id }, { allowNonZeroExit: true });\n return /enabled\\s+true/i.test(output);\n },\n async reload(options: PluginReloadOptions = {}) {\n const { readyOptions, waitUntilReady, ...execOptions } = options;\n\n await client.exec(\"plugin:reload\", { id }, execOptions);\n\n if (waitUntilReady) {\n await this.waitUntilReady(readyOptions);\n }\n },\n async restoreData() {\n await getClientInternals(client).restoreFile(await resolveDataPath());\n },\n async updateDataAndReload<T = unknown>(\n updater: JsonFileUpdater<T>,\n options: PluginUpdateDataOptions<T> = {},\n ): Promise<T> {\n const nextData = await this.data<T>().patch(updater);\n\n if (await this.isEnabled()) {\n await this.reload(withDefaultReadyReloadOptions(options));\n }\n\n return nextData;\n },\n async withPatchedData<T = unknown, TResult = void>(\n updater: JsonFileUpdater<T>,\n run: (plugin: PluginHandle) => Promise<TResult> | TResult,\n options: PluginWithPatchedDataOptions<T> = {},\n ): Promise<TResult> {\n const pluginWasEnabled = await this.isEnabled();\n const reloadOptions = withDefaultReadyReloadOptions(options);\n let hasPatchedData = false;\n let runResult: TResult | undefined;\n let runError: unknown;\n let restoreError: unknown;\n\n try {\n await this.data<T>().patch(updater);\n hasPatchedData = true;\n\n if (pluginWasEnabled) {\n await this.reload(reloadOptions);\n }\n\n runResult = await run(this);\n } catch (error) {\n runError = error;\n }\n\n if (hasPatchedData) {\n try {\n await this.restoreData();\n\n if (pluginWasEnabled) {\n await this.reload(reloadOptions);\n }\n } catch (error) {\n restoreError = error;\n }\n }\n\n if (runError && restoreError) {\n throw new AggregateError(\n [runError, restoreError],\n `Plugin \"${id}\" patch execution and restore both failed.`,\n );\n }\n\n if (runError) {\n throw runError;\n }\n\n if (restoreError) {\n throw restoreError;\n }\n\n return runResult as TResult;\n },\n async waitForData<T = unknown>(\n predicate: PluginDataPredicate<T>,\n options: PluginWaitForDataOptions = {},\n ) {\n return client.waitFor(async () => {\n try {\n const data = await this.data<T>().read();\n return (await predicate(data)) ? data : false;\n } catch {\n return false;\n }\n }, options);\n },\n async waitUntilReady(options: PluginWaitUntilReadyOptions = {}) {\n await client.waitFor(\n async () => {\n if (!(await isLoadedInApp())) {\n return false;\n }\n\n if (options.commandId) {\n return await client.command(options.commandId).exists();\n }\n\n return true;\n },\n {\n ...options,\n message:\n options.message ??\n (options.commandId\n ? `plugin \"${id}\" to be ready with command \"${options.commandId}\"`\n : `plugin \"${id}\" to be ready`),\n },\n );\n },\n };\n}\n\nfunction buildPluginLoadedCode(id: string): string {\n return [\n \"(()=>{\",\n \"const __obsidianE2EPlugins=app?.plugins;\",\n `return Boolean(__obsidianE2EPlugins?.enabledPlugins?.has?.(${JSON.stringify(id)})&&__obsidianE2EPlugins?.plugins?.[${JSON.stringify(id)}]);`,\n \"})()\",\n ].join(\"\");\n}\n","import { spawn } from \"node:child_process\";\n\nimport { ObsidianCommandError } from \"./errors\";\nimport type { CommandTransport, ExecuteRequest, ExecResult } from \"./types\";\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport const executeCommand: CommandTransport = async ({\n allowNonZeroExit = false,\n argv,\n bin,\n cwd,\n env,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n}: ExecuteRequest): Promise<ExecResult> => {\n const child = spawn(bin, argv, {\n cwd,\n env,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n\n child.stdout.on(\"data\", (chunk) => {\n stdoutChunks.push(Buffer.from(chunk));\n });\n\n child.stderr.on(\"data\", (chunk) => {\n stderrChunks.push(Buffer.from(chunk));\n });\n\n const exitCode = await new Promise<number>((resolve, reject) => {\n const timer = setTimeout(() => {\n child.kill(\"SIGTERM\");\n reject(new Error(`Command timed out after ${timeoutMs}ms: ${bin} ${argv.join(\" \")}`));\n }, timeoutMs);\n\n child.on(\"error\", (error) => {\n clearTimeout(timer);\n reject(error);\n });\n\n child.on(\"close\", (code) => {\n clearTimeout(timer);\n resolve(code ?? 0);\n });\n });\n\n const result: ExecResult = {\n argv,\n command: bin,\n exitCode,\n stderr: Buffer.concat(stderrChunks).toString(\"utf8\"),\n stdout: Buffer.concat(stdoutChunks).toString(\"utf8\"),\n };\n\n if (exitCode !== 0 && !allowNonZeroExit) {\n throw new ObsidianCommandError(\n `Obsidian command failed with exit code ${exitCode}: ${bin} ${argv.join(\" \")}`,\n result,\n );\n }\n\n return result;\n};\n","import type {\n DevConsoleMessage,\n DevDiagnostics,\n DevNoticeEvent,\n DevRuntimeError,\n} from \"../core/types\";\n\nconst DIAGNOSTICS_NAMESPACE = \"__obsidianE2EDiagnostics\";\n\nexport type DiagnosticsMethod =\n | \"consoleMessages\"\n | \"diagnostics\"\n | \"notices\"\n | \"reset\"\n | \"runtimeErrors\";\n\nexport function buildDiagnosticsCode(method: DiagnosticsMethod): string {\n return [\n \"(()=>{\",\n `const __obsidianE2EMethod=${JSON.stringify(method)};`,\n `const __obsidianE2ENamespace=${JSON.stringify(DIAGNOSTICS_NAMESPACE)};`,\n \"const __obsidianE2EMaxEntries=100;\",\n \"const __obsidianE2EPush=(entries,value)=>{if(entries.length>=__obsidianE2EMaxEntries){entries.shift();}entries.push(value);};\",\n \"const __obsidianE2EFormat=(value)=>{if(typeof value==='string'){return value;}try{return JSON.stringify(value);}catch{return String(value);}};\",\n \"const __obsidianE2EClone=(value)=>{try{return JSON.parse(JSON.stringify(value));}catch{return __obsidianE2EFormat(value);}};\",\n \"const __obsidianE2EPushRuntimeError=(source,errorLike,state)=>{const message=errorLike&&typeof errorLike==='object'&&'message' in errorLike?String(errorLike.message):String(errorLike);const stack=errorLike&&typeof errorLike==='object'&&'stack' in errorLike?String(errorLike.stack):undefined;__obsidianE2EPush(state.runtimeErrors,{at:Date.now(),message,source,stack});};\",\n \"const root=globalThis;\",\n \"const state=root[__obsidianE2ENamespace]??(root[__obsidianE2ENamespace]={consoleMessages:[],notices:[],runtimeErrors:[],consolePatched:false,noticePatched:false,runtimePatched:false});\",\n \"if(!state.consolePatched&&root.console){for(const level of ['debug','error','info','log','warn']){const original=root.console?.[level];if(typeof original!=='function'){continue;}root.console[level]=(...args)=>{__obsidianE2EPush(state.consoleMessages,{args:args.map(__obsidianE2EClone),at:Date.now(),level,text:args.map(__obsidianE2EFormat).join(' ')});return original.apply(root.console,args);};}state.consolePatched=true;}\",\n \"if(!state.runtimePatched&&typeof root.addEventListener==='function'){root.addEventListener('error',(event)=>{__obsidianE2EPushRuntimeError('error',event?.error??event?.message??'Unknown error',state);});root.addEventListener('unhandledrejection',(event)=>{__obsidianE2EPushRuntimeError('unhandledrejection',event?.reason??'Unhandled rejection',state);});state.runtimePatched=true;}\",\n \"if(!state.noticePatched&&typeof root.Notice==='function'){const OriginalNotice=root.Notice;root.Notice=new Proxy(OriginalNotice,{construct(target,ctorArgs,newTarget){__obsidianE2EPush(state.notices,{at:Date.now(),message:__obsidianE2EFormat(ctorArgs[0]??''),timeout:typeof ctorArgs[1]==='number'&&Number.isFinite(ctorArgs[1])?ctorArgs[1]:undefined});return Reflect.construct(target,ctorArgs,newTarget);}});state.noticePatched=true;}\",\n \"if(__obsidianE2EMethod==='reset'){state.consoleMessages.splice(0);state.notices.splice(0);state.runtimeErrors.splice(0);return true;}\",\n \"if(__obsidianE2EMethod==='consoleMessages'){return state.consoleMessages;}\",\n \"if(__obsidianE2EMethod==='notices'){return state.notices;}\",\n \"if(__obsidianE2EMethod==='runtimeErrors'){return state.runtimeErrors;}\",\n \"return {consoleMessages:state.consoleMessages,notices:state.notices,runtimeErrors:state.runtimeErrors};\",\n \"})()\",\n ].join(\"\");\n}\n\nexport function createDevDiagnostics(value: DevDiagnostics | null | undefined): DevDiagnostics {\n return {\n consoleMessages: (value?.consoleMessages ?? []) as DevConsoleMessage[],\n notices: (value?.notices ?? []) as DevNoticeEvent[],\n runtimeErrors: (value?.runtimeErrors ?? []) as DevRuntimeError[],\n };\n}\n","import { WaitForTimeoutError } from \"./errors\";\nimport type { WaitForOptions } from \"./types\";\n\nconst DEFAULT_INTERVAL_MS = 100;\nconst DEFAULT_TIMEOUT_MS = 5_000;\n\nexport async function sleep(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function waitForValue<T>(\n fn: () => Promise<T | false | null | undefined> | T | false | null | undefined,\n options: WaitForOptions = {},\n): Promise<T> {\n const intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const startTime = Date.now();\n\n let lastError: unknown;\n\n while (Date.now() - startTime <= timeoutMs) {\n try {\n const result = await fn();\n if (result !== false && result !== null && result !== undefined) {\n return result;\n }\n } catch (error) {\n lastError = error;\n }\n\n await sleep(intervalMs);\n }\n\n const label = options.message ?? \"condition\";\n throw new WaitForTimeoutError(`Timed out waiting for ${label} after ${timeoutMs}ms.`, lastError);\n}\n","import { buildCommandArgv } from \"./args\";\nimport { mergeExecOptions } from \"./exec-options\";\nimport { attachClientInternals, createRestoreManager } from \"./internals\";\nimport { createObsidianMetadataHandle } from \"../metadata/metadata\";\nimport { createPluginHandle } from \"../plugin/plugin\";\nimport { executeCommand } from \"./transport\";\nimport { buildDiagnosticsCode, createDevDiagnostics } from \"../dev/diagnostics\";\nimport { parseDevEvalOutput, runEvalJson } from \"../dev/eval-json\";\nimport type {\n CommandListOptions,\n CreateObsidianClientOptions,\n DevConsoleMessage,\n DevDiagnostics,\n DevNoticeEvent,\n DevDomQueryOptions,\n DevDomResult,\n DevRuntimeError,\n ExecOptions,\n ObsidianArg,\n ObsidianAppHandle,\n ObsidianCommandHandle,\n ObsidianClient,\n ObsidianDevHandle,\n OpenFileOptions,\n OpenTabOptions,\n RestartAppOptions,\n TabsOptions,\n WaitForOptions,\n WorkspaceNode,\n WorkspaceOptions,\n WorkspaceTab,\n} from \"./types\";\nimport { sleep, waitForValue } from \"./wait\";\n\nexport function createObsidianClient(options: CreateObsidianClientOptions): ObsidianClient {\n const transport = options.transport ?? executeCommand;\n const defaultExecOptions = options.defaultExecOptions;\n const waitDefaults = {\n intervalMs: options.intervalMs,\n timeoutMs: options.timeoutMs,\n };\n\n const restoreManager = createRestoreManager(async (filePath) => {\n const { readFile } = await import(\"node:fs/promises\");\n return readFile(filePath, \"utf8\");\n });\n\n let cachedVaultPath: string | undefined;\n\n const client = {} as ObsidianClient;\n const metadata = createObsidianMetadataHandle(client);\n\n const app: ObsidianAppHandle = {\n async reload(execOptions: ExecOptions = {}) {\n await client.exec(\"reload\", {}, execOptions);\n },\n async restart({\n readyOptions,\n waitUntilReady = true,\n ...execOptions\n }: RestartAppOptions & ExecOptions = {}) {\n await client.exec(\"restart\", {}, execOptions);\n\n if (waitUntilReady) {\n await app.waitUntilReady(readyOptions);\n }\n },\n version(execOptions: ExecOptions = {}) {\n return client.execText(\"version\", {}, execOptions);\n },\n async waitUntilReady(waitOptions?: WaitForOptions) {\n await client.waitFor(async () => {\n try {\n await client.vaultPath();\n await client.commands();\n return true;\n } catch {\n return false;\n }\n }, waitOptions);\n },\n };\n\n const dev: ObsidianDevHandle = {\n async activeFilePath(execOptions: ExecOptions = {}) {\n return this.eval<string | null>(\"app.workspace.getActiveFile()?.path ?? null\", execOptions);\n },\n async consoleMessages(execOptions: ExecOptions = {}) {\n return readDiagnosticsValue<DevConsoleMessage[]>(this, \"consoleMessages\", execOptions);\n },\n async diagnostics(execOptions: ExecOptions = {}): Promise<DevDiagnostics> {\n return createDevDiagnostics(\n await readDiagnosticsValue<DevDiagnostics>(this, \"diagnostics\", execOptions),\n );\n },\n async dom(options: DevDomQueryOptions, execOptions: ExecOptions = {}): Promise<DevDomResult> {\n const output = await client.execText(\n \"dev:dom\",\n {\n all: options.all,\n attr: options.attr,\n css: options.css,\n inner: options.inner,\n selector: options.selector,\n text: options.text,\n total: options.total,\n },\n execOptions,\n );\n\n if (options.total) {\n return Number.parseInt(output, 10);\n }\n\n if (options.all) {\n return output ? output.split(/\\r?\\n/u).filter(Boolean) : [];\n }\n\n return output;\n },\n async eval<T = unknown>(code: string, execOptions: ExecOptions = {}) {\n return parseDevEvalOutput<T>(await this.evalRaw(code, execOptions));\n },\n async evalJson<T = unknown>(code: string, execOptions: ExecOptions = {}) {\n return runEvalJson<T>(this, code, execOptions);\n },\n async evalRaw(code: string, execOptions: ExecOptions = {}) {\n return client.execText(\n \"eval\",\n {\n code,\n },\n execOptions,\n );\n },\n async editorText(execOptions: ExecOptions = {}) {\n return this.eval<string | null>(\n \"app.workspace.activeLeaf?.view?.editor?.getValue?.() ?? null\",\n execOptions,\n );\n },\n async notices(execOptions: ExecOptions = {}) {\n return readDiagnosticsValue<DevNoticeEvent[]>(this, \"notices\", execOptions);\n },\n async resetDiagnostics(execOptions: ExecOptions = {}) {\n await readDiagnosticsValue<boolean>(this, \"reset\", execOptions);\n },\n async runtimeErrors(execOptions: ExecOptions = {}) {\n return readDiagnosticsValue<DevRuntimeError[]>(this, \"runtimeErrors\", execOptions);\n },\n async screenshot(targetPath: string, execOptions: ExecOptions = {}) {\n await client.exec(\n \"dev:screenshot\",\n {\n path: targetPath,\n },\n execOptions,\n );\n\n return targetPath;\n },\n };\n\n Object.assign(client, {\n app,\n bin: options.bin ?? \"obsidian\",\n dev,\n metadata,\n command(id: string): ObsidianCommandHandle {\n return {\n async exists(commandOptions: CommandListOptions = {}) {\n const commands = await client.commands({\n ...commandOptions,\n filter: commandOptions.filter ?? id,\n });\n\n return commands.includes(id);\n },\n id,\n async run(execOptions: ExecOptions = {}) {\n await client.exec(\"command\", { id }, execOptions);\n },\n };\n },\n async commands(\n commandOptions: CommandListOptions = {},\n execOptions: ExecOptions = {},\n ): Promise<string[]> {\n const output = await client.execText(\n \"commands\",\n {\n filter: commandOptions.filter,\n },\n execOptions,\n );\n return parseCommandIds(output);\n },\n exec(command: string, args: Record<string, ObsidianArg> = {}, execOptions: ExecOptions = {}) {\n return transport({\n ...mergeExecOptions(defaultExecOptions, execOptions),\n argv: buildCommandArgv(options.vault, command, args),\n bin: this.bin,\n });\n },\n async execJson<T = unknown>(\n command: string,\n args: Record<string, ObsidianArg> = {},\n execOptions: ExecOptions = {},\n ) {\n const output = await this.execText(command, args, execOptions);\n return JSON.parse(output) as T;\n },\n async execText(\n command: string,\n args: Record<string, ObsidianArg> = {},\n execOptions: ExecOptions = {},\n ) {\n const result = await this.exec(command, args, execOptions);\n return result.stdout.trimEnd();\n },\n async open(openOptions: OpenFileOptions, execOptions: ExecOptions = {}) {\n await client.exec(\n \"open\",\n {\n file: openOptions.file,\n newtab: openOptions.newTab,\n path: openOptions.path,\n },\n execOptions,\n );\n },\n async openTab(tabOptions: OpenTabOptions = {}, execOptions: ExecOptions = {}) {\n await client.exec(\n \"tab:open\",\n {\n file: tabOptions.file,\n group: tabOptions.group,\n view: tabOptions.view,\n },\n execOptions,\n );\n },\n plugin(id: string) {\n return createPluginHandle(this, id);\n },\n sleep(ms: number) {\n return sleep(ms);\n },\n async tabs(\n tabOptions: TabsOptions = {},\n execOptions: ExecOptions = {},\n ): Promise<WorkspaceTab[]> {\n const output = await client.execText(\n \"tabs\",\n {\n ids: tabOptions.ids ?? true,\n },\n execOptions,\n );\n return parseTabs(output);\n },\n async vaultPath() {\n if (!cachedVaultPath) {\n cachedVaultPath = await this.execText(\"vault\", { info: \"path\" });\n }\n\n return cachedVaultPath;\n },\n async verify() {\n await transport({\n ...mergeExecOptions(defaultExecOptions, undefined),\n argv: [\"--help\"],\n bin: this.bin,\n });\n\n await this.vaultPath();\n },\n vaultName: options.vault,\n async waitForActiveFile(path: string, options?: WaitForOptions) {\n return client.waitFor(\n async () => {\n const activePath = await dev.activeFilePath();\n\n return activePath === path ? activePath : false;\n },\n {\n ...options,\n message: options?.message ?? `active file \"${path}\"`,\n },\n );\n },\n async waitForConsoleMessage(\n predicate: (message: DevConsoleMessage) => boolean | Promise<boolean>,\n options?: WaitForOptions,\n ) {\n return waitForDiagnosticEntry(\n client,\n () => client.dev.consoleMessages(),\n predicate,\n options?.message ?? \"console message\",\n options,\n );\n },\n async waitForNotice(\n predicate: string | ((notice: DevNoticeEvent) => boolean | Promise<boolean>),\n options?: WaitForOptions,\n ) {\n return waitForDiagnosticEntry(\n client,\n () => client.dev.notices(),\n typeof predicate === \"string\" ? (notice) => notice.message.includes(predicate) : predicate,\n options?.message ?? \"notice\",\n options,\n );\n },\n async waitForRuntimeError(\n predicate: string | ((error: DevRuntimeError) => boolean | Promise<boolean>),\n options?: WaitForOptions,\n ) {\n return waitForDiagnosticEntry(\n client,\n () => client.dev.runtimeErrors(),\n typeof predicate === \"string\" ? (error) => error.message.includes(predicate) : predicate,\n options?.message ?? \"runtime error\",\n options,\n );\n },\n waitFor<T>(\n fn: () => Promise<T | false | null | undefined> | T | false | null | undefined,\n waitOptions?: WaitForOptions,\n ) {\n return waitForValue(fn, {\n ...waitDefaults,\n ...waitOptions,\n });\n },\n async workspace(\n workspaceOptions: WorkspaceOptions = {},\n execOptions: ExecOptions = {},\n ): Promise<WorkspaceNode[]> {\n const output = await client.execText(\n \"workspace\",\n {\n ids: workspaceOptions.ids ?? true,\n },\n execOptions,\n );\n return parseWorkspace(output);\n },\n });\n\n attachClientInternals(client, restoreManager);\n\n return client;\n}\n\nfunction parseCommandIds(output: string): string[] {\n return output\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter(Boolean)\n .map((line) => line.split(\"\\t\", 1)[0]?.trim() ?? \"\")\n .filter(Boolean);\n}\n\nfunction parseTabs(output: string): WorkspaceTab[] {\n return output\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter(Boolean)\n .map(parseTabLine);\n}\n\nfunction parseTabLine(line: string): WorkspaceTab {\n const [descriptor, id] = line.split(\"\\t\");\n const match = descriptor?.match(/^\\[(.+?)\\]\\s+(.*)$/u);\n\n if (!match) {\n return {\n id: id?.trim() || undefined,\n title: descriptor?.trim() ?? \"\",\n viewType: \"unknown\",\n };\n }\n\n return {\n id: id?.trim() || undefined,\n title: match[2]!,\n viewType: match[1]!,\n };\n}\n\nfunction parseWorkspace(output: string): WorkspaceNode[] {\n const roots: WorkspaceNode[] = [];\n const stack: Array<{ depth: number; node: WorkspaceNode }> = [];\n\n for (const rawLine of output.split(/\\r?\\n/u)) {\n if (!rawLine.trim()) {\n continue;\n }\n\n const depth = getWorkspaceDepth(rawLine);\n const node = parseWorkspaceNode(rawLine);\n\n while (stack.length > 0 && stack.at(-1)!.depth >= depth) {\n stack.pop();\n }\n\n const parent = stack.at(-1)?.node;\n\n if (parent) {\n parent.children.push(node);\n } else {\n roots.push(node);\n }\n\n stack.push({ depth, node });\n }\n\n return roots;\n}\n\nasync function waitForDiagnosticEntry<T>(\n client: ObsidianClient,\n readEntries: () => Promise<T[]>,\n predicate: (entry: T) => boolean | Promise<boolean>,\n label: string,\n options?: WaitForOptions,\n): Promise<T> {\n return client.waitFor(\n async () => {\n const entries = await readEntries();\n\n for (const entry of entries) {\n if (await predicate(entry)) {\n return entry;\n }\n }\n\n return false;\n },\n {\n ...options,\n message: options?.message ?? label,\n },\n );\n}\n\nasync function readDiagnosticsValue<T>(\n dev: Pick<ObsidianDevHandle, \"evalRaw\">,\n method: \"consoleMessages\" | \"diagnostics\" | \"notices\" | \"reset\" | \"runtimeErrors\",\n execOptions?: ExecOptions,\n): Promise<T> {\n return runEvalJson<T>(dev, buildDiagnosticsCode(method), execOptions);\n}\n\nfunction getWorkspaceDepth(line: string): number {\n let depth = 0;\n let remainder = line;\n\n while (true) {\n if (\n remainder.startsWith(\"│ \") ||\n remainder.startsWith(\" \") ||\n remainder.startsWith(\"├── \") ||\n remainder.startsWith(\"└── \")\n ) {\n depth += 1;\n remainder = remainder.slice(4);\n continue;\n }\n\n return depth;\n }\n}\n\nfunction parseWorkspaceNode(line: string): WorkspaceNode {\n let withoutTree = line;\n\n while (true) {\n if (\n withoutTree.startsWith(\"│ \") ||\n withoutTree.startsWith(\" \") ||\n withoutTree.startsWith(\"├── \") ||\n withoutTree.startsWith(\"└── \")\n ) {\n withoutTree = withoutTree.slice(4);\n continue;\n }\n\n break;\n }\n\n withoutTree = withoutTree.trim();\n const idMatch = withoutTree.match(/^(.*?)(?: \\(([a-z0-9]+)\\))?$/iu);\n const content = idMatch?.[1]?.trim() ?? withoutTree;\n const id = idMatch?.[2];\n const leafMatch = content.match(/^\\[(.+?)\\]\\s+(.*)$/u);\n\n if (leafMatch) {\n return {\n children: [],\n id,\n label: leafMatch[2]!,\n title: leafMatch[2]!,\n viewType: leafMatch[1]!,\n };\n }\n\n return {\n children: [],\n id,\n label: content,\n };\n}\n","export interface SanitizePathSegmentOptions {\n fallback?: string;\n maxLength?: number;\n}\n\nexport function sanitizePathSegment(\n value: string,\n options: SanitizePathSegmentOptions = {},\n): string {\n const fallback = options.fallback ?? \"test\";\n const maxLength = options.maxLength ?? 80;\n\n return (\n value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, maxLength) || fallback\n );\n}\n","import path from \"node:path\";\nimport { posix as pathPosix } from \"node:path\";\n\nimport type { ObsidianClient } from \"../core/types\";\n\nexport function normalizeScope(scope?: string): string {\n if (!scope || scope === \".\") {\n return \"\";\n }\n\n return scope.replace(/^\\/+|\\/+$/g, \"\");\n}\n\nexport function resolveVaultPath(scopeRoot: string, targetPath: string): string {\n if (!targetPath || targetPath === \".\") {\n return scopeRoot;\n }\n\n return scopeRoot ? pathPosix.join(scopeRoot, targetPath) : pathPosix.normalize(targetPath);\n}\n\nexport async function resolveFilesystemPath(\n obsidian: ObsidianClient,\n scopeRoot: string,\n targetPath: string,\n): Promise<string> {\n const vaultPath = await obsidian.vaultPath();\n const scopedPath = resolveVaultPath(scopeRoot, targetPath);\n const relativePath = scopedPath.split(\"/\").filter(Boolean);\n const resolvedPath = path.resolve(vaultPath, ...relativePath);\n const normalizedVaultPath = path.resolve(vaultPath);\n\n if (\n resolvedPath !== normalizedVaultPath &&\n !resolvedPath.startsWith(`${normalizedVaultPath}${path.sep}`)\n ) {\n throw new Error(`Resolved path escapes the vault root: ${targetPath}`);\n }\n\n return resolvedPath;\n}\n","import { access, mkdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type {\n DeleteOptions,\n JsonFile,\n ObsidianClient,\n VaultApi,\n VaultWaitForContentOptions,\n VaultWriteOptions,\n} from \"../core/types\";\nimport { normalizeScope, resolveFilesystemPath, resolveVaultPath } from \"./paths\";\n\ninterface CreateVaultApiOptions {\n obsidian: ObsidianClient;\n root?: string;\n}\n\nexport function createVaultApi(options: CreateVaultApiOptions): VaultApi {\n const scopeRoot = normalizeScope(options.root);\n\n return {\n async delete(targetPath, deleteOptions: DeleteOptions = {}) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n await rm(resolvedPath, {\n force: true,\n recursive: true,\n });\n\n if (deleteOptions.permanent === false) {\n return;\n }\n },\n async exists(targetPath) {\n try {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n await access(resolvedPath);\n return true;\n } catch {\n return false;\n }\n },\n json<T = unknown>(targetPath: string) {\n const jsonFile: JsonFile<T> = {\n async patch(updater) {\n const currentValue = await jsonFile.read();\n const draft = structuredClone(currentValue);\n const result = await updater(draft);\n const nextValue = result ?? draft;\n\n await jsonFile.write(nextValue);\n\n return nextValue;\n },\n async read() {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n const rawValue = await readFile(resolvedPath, \"utf8\");\n return JSON.parse(rawValue) as T;\n },\n async write(value) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n await mkdir(path.dirname(resolvedPath), { recursive: true });\n await writeFile(resolvedPath, `${JSON.stringify(value, null, 2)}\\n`, \"utf8\");\n },\n };\n\n return jsonFile;\n },\n async mkdir(targetPath) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n await mkdir(resolvedPath, { recursive: true });\n },\n async read(targetPath) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n return readFile(resolvedPath, \"utf8\");\n },\n async waitForContent(targetPath, predicate, waitOptions: VaultWaitForContentOptions = {}) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n\n return options.obsidian.waitFor(\n async () => {\n try {\n const content = await readFile(resolvedPath, \"utf8\");\n return (await predicate(content)) ? content : false;\n } catch {\n return false;\n }\n },\n {\n message: `vault path \"${resolveVaultPath(scopeRoot, targetPath)}\" to match content`,\n ...waitOptions,\n },\n );\n },\n async waitForExists(targetPath, waitOptions) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n\n await options.obsidian.waitFor(\n async () => {\n try {\n await access(resolvedPath);\n return true;\n } catch {\n return false;\n }\n },\n {\n message: `vault path \"${resolveVaultPath(scopeRoot, targetPath)}\" to exist`,\n ...waitOptions,\n },\n );\n },\n async waitForMissing(targetPath, waitOptions) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n\n await options.obsidian.waitFor(\n async () => {\n try {\n await access(resolvedPath);\n return false;\n } catch {\n return true;\n }\n },\n {\n message: `vault path \"${resolveVaultPath(scopeRoot, targetPath)}\" to be removed`,\n ...waitOptions,\n },\n );\n },\n async write(targetPath, content, writeOptions: VaultWriteOptions = {}) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n await mkdir(path.dirname(resolvedPath), { recursive: true });\n await writeFile(resolvedPath, content, \"utf8\");\n\n if (!writeOptions.waitForContent) {\n return;\n }\n\n const predicate =\n typeof writeOptions.waitForContent === \"function\"\n ? writeOptions.waitForContent\n : (value: string) => value === content;\n\n await this.waitForContent(targetPath, predicate, writeOptions.waitOptions);\n },\n };\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { ObsidianClient, PluginHandle } from \"../core/types\";\nimport { sanitizePathSegment } from \"../core/path-slug\";\nimport { parseNoteDocument } from \"../note/document\";\nimport { createVaultApi } from \"../vault/vault\";\n\nexport const DEFAULT_FAILURE_ARTIFACTS_DIR = \".obsidian-e2e-artifacts\";\n\nexport interface FailureArtifactOptions {\n activeFile?: boolean;\n activeNote?: boolean;\n consoleMessages?: boolean;\n dom?: boolean;\n editorText?: boolean;\n notices?: boolean;\n parsedFrontmatter?: boolean;\n runtimeErrors?: boolean;\n screenshot?: boolean;\n tabs?: boolean;\n workspace?: boolean;\n}\n\nexport interface FailureArtifactTask {\n id: string;\n name: string;\n}\n\nexport interface FailureArtifactConfig {\n artifactsDir: string;\n capture: Required<FailureArtifactOptions>;\n enabled: boolean;\n}\n\nexport interface FailureArtifactRegistrationOptions {\n artifactsDir?: string;\n captureOnFailure?: boolean | FailureArtifactOptions;\n}\n\nexport interface CaptureFailureArtifactsOptions extends FailureArtifactRegistrationOptions {\n plugin?: PluginHandle;\n}\n\nconst DEFAULT_FAILURE_ARTIFACT_CAPTURE: Required<FailureArtifactOptions> = {\n activeFile: true,\n activeNote: true,\n consoleMessages: true,\n dom: true,\n editorText: true,\n notices: true,\n parsedFrontmatter: true,\n runtimeErrors: true,\n screenshot: true,\n tabs: true,\n workspace: true,\n};\n\nexport function getFailureArtifactConfig(\n options: FailureArtifactRegistrationOptions,\n): FailureArtifactConfig {\n if (!options.captureOnFailure) {\n return {\n artifactsDir: path.resolve(options.artifactsDir ?? DEFAULT_FAILURE_ARTIFACTS_DIR),\n capture: { ...DEFAULT_FAILURE_ARTIFACT_CAPTURE },\n enabled: false,\n };\n }\n\n const overrides = options.captureOnFailure === true ? {} : options.captureOnFailure;\n\n return {\n artifactsDir: path.resolve(options.artifactsDir ?? DEFAULT_FAILURE_ARTIFACTS_DIR),\n capture: { ...DEFAULT_FAILURE_ARTIFACT_CAPTURE, ...overrides },\n enabled: true,\n };\n}\n\nexport function getFailureArtifactDirectory(\n artifactsDir: string,\n task: FailureArtifactTask,\n): string {\n const suffix = task.id.split(\"_\").at(-1) ?? \"test\";\n return path.join(artifactsDir, `${sanitizePathSegment(task.name, { maxLength: 60 })}-${suffix}`);\n}\n\nexport async function captureFailureArtifacts(\n task: FailureArtifactTask,\n obsidian: ObsidianClient,\n options: CaptureFailureArtifactsOptions,\n): Promise<string | undefined> {\n const config = getFailureArtifactConfig(options);\n\n if (!config.enabled) {\n return undefined;\n }\n\n const artifactDirectory = getFailureArtifactDirectory(config.artifactsDir, task);\n await mkdir(artifactDirectory, { recursive: true });\n const activeFile = readArtifactInput(() => readActiveFilePath(obsidian));\n const activeNote = readArtifactInput(async () => {\n const activeFilePath = await unwrapArtifactInput(activeFile);\n\n return activeFilePath ? readActiveNoteSnapshot(obsidian, activeFilePath) : null;\n });\n const diagnostics = await obsidian.dev.diagnostics().catch(() => null);\n\n await Promise.all([\n captureJsonArtifact(\n artifactDirectory,\n \"active-file.json\",\n config.capture.activeFile,\n async () => ({\n activeFile: await unwrapArtifactInput(activeFile),\n }),\n ),\n captureTextArtifact(\n artifactDirectory,\n \"active-note.md\",\n config.capture.activeNote,\n async () => (await unwrapArtifactInput(activeNote))?.raw ?? \"\",\n ),\n captureJsonArtifact(\n artifactDirectory,\n \"active-note-frontmatter.json\",\n config.capture.parsedFrontmatter,\n async () => ({\n frontmatter: (await unwrapArtifactInput(activeNote))?.frontmatter ?? null,\n }),\n ),\n captureTextArtifact(artifactDirectory, \"dom.txt\", config.capture.dom, async () =>\n String(\n await obsidian.dev.dom({\n inner: true,\n selector: \".workspace\",\n }),\n ),\n ),\n captureJsonArtifact(artifactDirectory, \"editor.json\", config.capture.editorText, async () => ({\n text: await obsidian.dev.editorText(),\n })),\n captureJsonArtifact(\n artifactDirectory,\n \"console-messages.json\",\n config.capture.consoleMessages,\n async () => diagnostics?.consoleMessages ?? [],\n ),\n captureJsonArtifact(\n artifactDirectory,\n \"runtime-errors.json\",\n config.capture.runtimeErrors,\n async () => diagnostics?.runtimeErrors ?? [],\n ),\n captureJsonArtifact(\n artifactDirectory,\n \"notices.json\",\n config.capture.notices,\n async () => diagnostics?.notices ?? [],\n ),\n captureScreenshotArtifact(artifactDirectory, config.capture.screenshot, obsidian),\n captureJsonArtifact(artifactDirectory, \"tabs.json\", config.capture.tabs, () => obsidian.tabs()),\n captureJsonArtifact(artifactDirectory, \"workspace.json\", config.capture.workspace, () =>\n obsidian.workspace(),\n ),\n options.plugin\n ? captureJsonArtifact(artifactDirectory, `${options.plugin.id}-data.json`, true, () =>\n options.plugin!.data().read(),\n )\n : Promise.resolve(),\n ]);\n\n return artifactDirectory;\n}\n\nexport async function capturePluginFailureArtifacts(\n task: FailureArtifactTask,\n plugin: PluginHandle,\n options: FailureArtifactRegistrationOptions,\n): Promise<string | undefined> {\n const config = getFailureArtifactConfig(options);\n\n if (!config.enabled) {\n return undefined;\n }\n\n const artifactDirectory = getFailureArtifactDirectory(config.artifactsDir, task);\n await mkdir(artifactDirectory, { recursive: true });\n await captureJsonArtifact(artifactDirectory, `${plugin.id}-data.json`, true, () =>\n plugin.data().read(),\n );\n\n return artifactDirectory;\n}\n\nasync function captureJsonArtifact(\n artifactDirectory: string,\n filename: string,\n enabled: boolean,\n readValue: () => Promise<unknown>,\n): Promise<void> {\n if (!enabled) {\n return;\n }\n\n try {\n const value = await readValue();\n await writeFile(\n path.join(artifactDirectory, filename),\n `${JSON.stringify(value, null, 2)}\\n`,\n \"utf8\",\n );\n } catch (error) {\n await writeFile(\n path.join(artifactDirectory, `${filename}.error.txt`),\n formatArtifactError(error),\n \"utf8\",\n );\n }\n}\n\nasync function captureScreenshotArtifact(\n artifactDirectory: string,\n enabled: boolean,\n obsidian: ObsidianClient,\n): Promise<void> {\n if (!enabled) {\n return;\n }\n\n const screenshotPath = path.join(artifactDirectory, \"screenshot.png\");\n\n try {\n await obsidian.dev.screenshot(screenshotPath);\n } catch (error) {\n await writeFile(\n path.join(artifactDirectory, \"screenshot.error.txt\"),\n formatArtifactError(error),\n \"utf8\",\n );\n }\n}\n\nasync function captureTextArtifact(\n artifactDirectory: string,\n filename: string,\n enabled: boolean,\n readValue: () => Promise<string>,\n): Promise<void> {\n if (!enabled) {\n return;\n }\n\n try {\n await writeFile(path.join(artifactDirectory, filename), await readValue(), \"utf8\");\n } catch (error) {\n await writeFile(\n path.join(artifactDirectory, `${filename}.error.txt`),\n formatArtifactError(error),\n \"utf8\",\n );\n }\n}\n\nfunction formatArtifactError(error: unknown): string {\n return error instanceof Error ? `${error.name}: ${error.message}\\n` : `${String(error)}\\n`;\n}\n\nasync function readActiveFilePath(obsidian: ObsidianClient): Promise<string | null> {\n return obsidian.dev.activeFilePath();\n}\n\nasync function readActiveNoteSnapshot(obsidian: ObsidianClient, activeFile: string) {\n const vault = createVaultApi({ obsidian });\n const raw = await vault.read(activeFile);\n\n return parseNoteDocument(raw);\n}\n\ninterface ArtifactInputResult<T> {\n promise: Promise<{ error: unknown; ok: false } | { ok: true; value: T }>;\n}\n\nfunction readArtifactInput<T>(readValue: () => Promise<T>): ArtifactInputResult<T> {\n return {\n promise: readValue().then(\n (value) => ({ ok: true, value }) as const,\n (error) => ({ error, ok: false }) as const,\n ),\n };\n}\n\nasync function unwrapArtifactInput<T>(result: ArtifactInputResult<T>): Promise<T> {\n const value = await result.promise;\n\n if (!value.ok) {\n throw value.error;\n }\n\n return value.value;\n}\n","import { posix as pathPosix } from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\n\nimport type {\n NoteDocument,\n NoteFrontmatter,\n ObsidianClient,\n SandboxApi,\n SandboxWriteNoteOptions,\n} from \"../core/types\";\nimport { sanitizePathSegment } from \"../core/path-slug\";\nimport { createNoteDocument, parseNoteDocument } from \"../note/document\";\nimport { createVaultApi } from \"./vault\";\n\ninterface CreateSandboxApiOptions {\n obsidian: ObsidianClient;\n sandboxRoot: string;\n testName: string;\n}\n\nexport async function createSandboxApi(options: CreateSandboxApiOptions): Promise<SandboxApi> {\n const root = pathPosix.join(\n options.sandboxRoot,\n `${sanitizePathSegment(options.testName)}-${randomUUID().slice(0, 8)}`,\n );\n const sandboxPath = (...segments: string[]) => pathPosix.join(root, ...segments);\n const vault = createVaultApi({\n obsidian: options.obsidian,\n root,\n });\n\n await vault.mkdir(\".\");\n\n return {\n ...vault,\n async cleanup() {\n await vault.delete(\".\", { permanent: true });\n },\n path(...segments: string[]) {\n return sandboxPath(...segments);\n },\n async readNote<TFrontmatter extends NoteFrontmatter | null = NoteFrontmatter | null>(\n targetPath: string,\n ): Promise<NoteDocument<TFrontmatter>> {\n return parseNoteDocument(await vault.read(targetPath)) as NoteDocument<TFrontmatter>;\n },\n root,\n async writeNote<TFrontmatter extends NoteFrontmatter | null = NoteFrontmatter | null>(\n writeOptions: SandboxWriteNoteOptions<TFrontmatter>,\n ): Promise<NoteDocument<TFrontmatter>> {\n const { path, waitForMetadata = true, waitOptions, ...noteInput } = writeOptions;\n const document = createNoteDocument(noteInput) as NoteDocument<TFrontmatter>;\n\n await vault.write(path, document.raw);\n\n if (waitForMetadata) {\n const predicate = typeof waitForMetadata === \"function\" ? waitForMetadata : undefined;\n await options.obsidian.metadata.waitForMetadata(sandboxPath(path), predicate, waitOptions);\n }\n\n return document;\n },\n };\n}\n","import { mkdir, readFile, rm, stat, writeFile } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { createHash, randomUUID } from \"node:crypto\";\n\nimport type { ObsidianClient } from \"../core/types\";\nimport type { SharedVaultLockOptions } from \"./types\";\n\nconst DEFAULT_HEARTBEAT_MS = 2_000;\nconst DEFAULT_STALE_MS = 15_000;\nconst DEFAULT_TIMEOUT_MS = 60_000;\nconst DEFAULT_WAIT_INTERVAL_MS = 500;\nconst DEFAULT_LOCK_ROOT = path.join(os.tmpdir(), \"obsidian-e2e-locks\");\nconst LOCK_METADATA_FILE = \"lock.json\";\nconst APP_LOCK_KEY = \"__obsidianE2ELock\";\nconst heldLocks = new Map<string, HeldVaultRunLock>();\n\nexport interface VaultRunLockMetadata {\n acquiredAt: number;\n cwd: string;\n heartbeatAt: number;\n hostname: string;\n ownerId: string;\n pid: number;\n staleMs: number;\n vaultName: string;\n vaultPath: string;\n}\n\nexport interface VaultRunLock {\n readonly lockDir: string;\n readonly metadata: VaultRunLockMetadata;\n\n publishMarker(obsidian: ObsidianClient): Promise<void>;\n release(): Promise<void>;\n}\n\nexport interface VaultRunLockState {\n heartbeatAgeMs: number;\n isStale: boolean;\n lockDir: string;\n metadata: VaultRunLockMetadata;\n}\n\nexport interface AcquireVaultRunLockOptions extends SharedVaultLockOptions {\n vaultName: string;\n vaultPath: string;\n}\n\ninterface HeldVaultRunLock {\n heartbeat: NodeJS.Timeout;\n lockDir: string;\n metadata: VaultRunLockMetadata;\n metadataPath: string;\n refs: number;\n}\n\nexport async function acquireVaultRunLock({\n heartbeatMs = DEFAULT_HEARTBEAT_MS,\n lockRoot = DEFAULT_LOCK_ROOT,\n onBusy = \"wait\",\n staleMs = DEFAULT_STALE_MS,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n vaultName,\n vaultPath,\n}: AcquireVaultRunLockOptions): Promise<VaultRunLock> {\n const lockDir = path.join(lockRoot, createVaultLockKey(vaultPath));\n const heldLock = heldLocks.get(lockDir);\n\n if (heldLock) {\n heldLock.refs += 1;\n return createVaultRunLockHandle(heldLock);\n }\n\n const ownerId = randomUUID();\n const metadataPath = path.join(lockDir, LOCK_METADATA_FILE);\n const metadata: VaultRunLockMetadata = {\n acquiredAt: Date.now(),\n cwd: process.cwd(),\n heartbeatAt: Date.now(),\n hostname: os.hostname(),\n ownerId,\n pid: process.pid,\n staleMs,\n vaultName,\n vaultPath,\n };\n\n await mkdir(lockRoot, { recursive: true });\n\n const startedAt = Date.now();\n\n while (true) {\n try {\n await mkdir(lockDir);\n await writeMetadata(metadataPath, metadata);\n break;\n } catch (error) {\n if (!isAlreadyExistsError(error)) {\n throw error;\n }\n\n const currentLock = await inspectVaultRunLock({\n lockRoot,\n staleMs,\n vaultPath,\n });\n\n if (currentLock && !currentLock.isStale) {\n if (onBusy === \"fail\") {\n throw new Error(formatBusyLockMessage(vaultPath, currentLock));\n }\n } else {\n await rm(lockDir, { force: true, recursive: true });\n continue;\n }\n\n if (Date.now() - startedAt >= timeoutMs) {\n throw new Error(\n currentLock\n ? `Timed out waiting for shared vault lock: ${formatBusyLockMessage(vaultPath, currentLock)}`\n : `Timed out waiting for shared vault lock on ${vaultPath}`,\n );\n }\n\n await sleep(Math.min(DEFAULT_WAIT_INTERVAL_MS, heartbeatMs));\n }\n }\n\n const heartbeat = setInterval(() => {\n metadata.heartbeatAt = Date.now();\n void writeMetadata(metadataPath, metadata).catch(() => {});\n }, heartbeatMs);\n heartbeat.unref();\n\n const nextHeldLock: HeldVaultRunLock = {\n heartbeat,\n lockDir,\n metadata,\n metadataPath,\n refs: 1,\n };\n\n heldLocks.set(lockDir, nextHeldLock);\n return createVaultRunLockHandle(nextHeldLock);\n}\n\nexport async function clearVaultRunLockMarker(obsidian: ObsidianClient): Promise<void> {\n await obsidian.dev.eval(`delete window.${APP_LOCK_KEY}; delete app.${APP_LOCK_KEY}; \"cleared\"`, {\n allowNonZeroExit: true,\n });\n}\n\nexport async function inspectVaultRunLock({\n lockRoot = DEFAULT_LOCK_ROOT,\n staleMs = DEFAULT_STALE_MS,\n vaultPath,\n}: Pick<\n AcquireVaultRunLockOptions,\n \"lockRoot\" | \"staleMs\" | \"vaultPath\"\n>): Promise<VaultRunLockState | null> {\n const lockDir = path.join(lockRoot, createVaultLockKey(vaultPath));\n const metadata = await readLockState(lockDir);\n\n if (!metadata) {\n return null;\n }\n\n return {\n heartbeatAgeMs: Date.now() - metadata.heartbeatAt,\n isStale: isLockStale(metadata, staleMs),\n lockDir,\n metadata,\n };\n}\n\nexport async function readVaultRunLockMarker(\n obsidian: ObsidianClient,\n): Promise<VaultRunLockMetadata | null> {\n return obsidian.dev.eval<VaultRunLockMetadata | null>(\n `window.${APP_LOCK_KEY} ?? app.${APP_LOCK_KEY} ?? null`,\n { allowNonZeroExit: true },\n );\n}\n\nfunction createVaultLockKey(vaultPath: string): string {\n return createHash(\"sha256\").update(path.resolve(vaultPath)).digest(\"hex\");\n}\n\nfunction buildSetMarkerCode(metadata: VaultRunLockMetadata): string {\n const encodedMetadata = JSON.stringify(metadata);\n return `(() => {\n const lock = ${encodedMetadata};\n window.${APP_LOCK_KEY} = lock;\n app.${APP_LOCK_KEY} = lock;\n return lock;\n })()`;\n}\n\nfunction createVaultRunLockHandle(heldLock: HeldVaultRunLock): VaultRunLock {\n return {\n get lockDir() {\n return heldLock.lockDir;\n },\n get metadata() {\n return heldLock.metadata;\n },\n async publishMarker(obsidian: ObsidianClient) {\n await obsidian.dev.eval(buildSetMarkerCode(heldLock.metadata));\n },\n async release() {\n if (heldLock.refs > 1) {\n heldLock.refs -= 1;\n return;\n }\n\n heldLocks.delete(heldLock.lockDir);\n clearInterval(heldLock.heartbeat);\n\n const currentLock = await readLockState(heldLock.lockDir);\n\n if (currentLock?.ownerId !== heldLock.metadata.ownerId) {\n return;\n }\n\n await rm(heldLock.lockDir, { force: true, recursive: true });\n },\n };\n}\n\nasync function readLockState(lockDir: string): Promise<VaultRunLockMetadata | null> {\n const metadataPath = path.join(lockDir, LOCK_METADATA_FILE);\n\n try {\n return JSON.parse(await readFile(metadataPath, \"utf8\")) as VaultRunLockMetadata;\n } catch {\n try {\n const directoryStat = await stat(lockDir);\n return {\n acquiredAt: directoryStat.mtimeMs,\n cwd: \"\",\n heartbeatAt: directoryStat.mtimeMs,\n hostname: \"\",\n ownerId: \"\",\n pid: 0,\n staleMs: DEFAULT_STALE_MS,\n vaultName: \"\",\n vaultPath: \"\",\n };\n } catch {\n return null;\n }\n }\n}\n\nfunction formatBusyLockMessage(vaultPath: string, state: VaultRunLockState): string {\n const ownerDetails = state.metadata.ownerId\n ? `owner=${state.metadata.ownerId} pid=${state.metadata.pid} cwd=${state.metadata.cwd || \"<unknown>\"}`\n : \"owner=<unknown>\";\n const ageDetails = `heartbeatAgeMs=${state.heartbeatAgeMs} stale=${state.isStale}`;\n\n return `vault ${vaultPath} is locked by ${ownerDetails} ${ageDetails}`;\n}\n\nfunction isAlreadyExistsError(error: unknown): boolean {\n return error instanceof Error && \"code\" in error && error.code === \"EEXIST\";\n}\n\nfunction isLockStale(metadata: VaultRunLockMetadata, staleMs: number): boolean {\n return Date.now() - metadata.heartbeatAt > staleMs;\n}\n\nasync function sleep(durationMs: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, durationMs));\n}\n\nasync function writeMetadata(metadataPath: string, metadata: VaultRunLockMetadata): Promise<void> {\n await writeFile(metadataPath, `${JSON.stringify(metadata, null, 2)}\\n`, \"utf8\");\n}\n","import type { TestContext } from \"vite-plus/test\";\n\nimport { createObsidianClient } from \"../core/client\";\nimport type { ObsidianClient, VaultApi } from \"../core/types\";\nimport { createVaultApi } from \"../vault/vault\";\nimport { createInternalTestContext } from \"./test-context\";\nimport type { CreateObsidianTestOptions, TestContext as ObsidianTestContext } from \"./types\";\nimport { acquireVaultRunLock, clearVaultRunLockMarker, type VaultRunLock } from \"./vault-lock\";\n\nexport const DEFAULT_SANDBOX_ROOT = \"__obsidian_e2e__\";\n\nexport interface BaseFixtureState {\n _testContext: ObsidianTestContext;\n _vaultLock: VaultRunLock | null;\n}\n\ninterface BaseFixtureOptions {\n createVault?: (obsidian: ObsidianClient) => Promise<VaultApi> | VaultApi;\n}\n\nexport function createBaseFixtures(\n options: CreateObsidianTestOptions,\n fixtureOptions: BaseFixtureOptions = {},\n) {\n const createVault =\n fixtureOptions.createVault ?? ((obsidian: ObsidianClient) => createVaultApi({ obsidian }));\n\n return {\n _vaultLock: [\n // eslint-disable-next-line no-empty-pattern\n async ({}, use: (vaultLock: VaultRunLock | null) => Promise<void>) => {\n if (!options.sharedVaultLock) {\n await use(null);\n return;\n }\n\n const lockClient = createObsidianClient(options);\n await lockClient.verify();\n\n const lockOptions = options.sharedVaultLock === true ? {} : options.sharedVaultLock;\n const vaultLock = await acquireVaultRunLock({\n ...lockOptions,\n vaultName: options.vault,\n vaultPath: await lockClient.vaultPath(),\n });\n\n await vaultLock.publishMarker(lockClient);\n try {\n await use(vaultLock);\n } finally {\n try {\n await clearVaultRunLockMarker(lockClient);\n } catch {}\n\n await vaultLock.release();\n }\n },\n { scope: \"worker\" },\n ],\n _testContext: async (\n {\n _vaultLock,\n onTestFailed,\n task,\n }: Pick<BaseFixtureState & TestContext, \"_vaultLock\" | \"onTestFailed\" | \"task\">,\n use: (context: ObsidianTestContext) => Promise<void>,\n ) => {\n let failedTask = false;\n onTestFailed(() => {\n failedTask = true;\n });\n\n const context = await createInternalTestContext({\n ...options,\n createVault,\n testName: task.name,\n vaultLock: _vaultLock,\n });\n\n try {\n await use(context);\n } finally {\n await context.cleanup({\n failedTask: failedTask ? task : undefined,\n });\n }\n },\n // oxlint-disable-next-line no-empty-pattern\n obsidian: async (\n { _testContext }: Pick<BaseFixtureState, \"_testContext\">,\n use: (obsidian: ObsidianClient) => Promise<void>,\n ) => {\n await use(_testContext.obsidian);\n },\n sandbox: async (\n { _testContext }: Pick<BaseFixtureState, \"_testContext\">,\n use: (sandbox: ObsidianTestContext[\"sandbox\"]) => Promise<void>,\n ) => {\n await use(_testContext.sandbox);\n },\n vault: async (\n { _testContext }: Pick<BaseFixtureState, \"_testContext\">,\n use: (vault: VaultApi) => Promise<void>,\n ) => {\n await use(_testContext.vault);\n },\n };\n}\n","import { createObsidianClient } from \"../core/client\";\nimport { getClientInternals } from \"../core/internals\";\nimport type { FailureArtifactTask } from \"../artifacts/failure-artifacts\";\nimport { captureFailureArtifacts } from \"../artifacts/failure-artifacts\";\nimport type { ObsidianClient, PluginHandle, VaultApi } from \"../core/types\";\nimport { createSandboxApi } from \"../vault/sandbox\";\nimport { createVaultApi } from \"../vault/vault\";\nimport { DEFAULT_SANDBOX_ROOT } from \"./base-fixtures\";\nimport { acquireVaultRunLock, clearVaultRunLockMarker, type VaultRunLock } from \"./vault-lock\";\nimport type { CreateObsidianTestOptions, PluginSessionOptions, TestContext } from \"./types\";\n\ninterface CreateInternalTestContextOptions extends CreateObsidianTestOptions {\n createVault?: (obsidian: ObsidianClient) => Promise<VaultApi> | VaultApi;\n testName?: string;\n vaultLock?: VaultRunLock | null;\n}\n\ninterface TrackedPluginSession {\n filter?: PluginSessionOptions[\"filter\"];\n plugin: PluginHandle;\n wasEnabled: boolean;\n}\n\nexport async function createTestContext(\n options: CreateObsidianTestOptions & { testName?: string },\n): Promise<TestContext> {\n return createInternalTestContext(options);\n}\n\nexport async function withVaultSandbox<TResult>(\n options: CreateObsidianTestOptions & { testName?: string },\n run: (context: TestContext) => Promise<TResult> | TResult,\n): Promise<TResult> {\n const context = await createInternalTestContext(options);\n\n try {\n return await run(context);\n } finally {\n await context.cleanup();\n }\n}\n\nexport async function createInternalTestContext(\n options: CreateInternalTestContextOptions,\n): Promise<TestContext> {\n const obsidian = createObsidianClient(options);\n const trackedPlugins = new Map<string, TrackedPluginSession>();\n let sandbox: Awaited<ReturnType<typeof createSandboxApi>> | null = null;\n const vaultLock = options.vaultLock ?? (await maybeAcquireVaultLock(options, obsidian));\n const ownsVaultLock = options.vaultLock === undefined && vaultLock !== null;\n const vaultFactory =\n options.createVault ?? ((client: ObsidianClient) => createVaultApi({ obsidian: client }));\n let disposed = false;\n\n try {\n await obsidian.verify();\n\n if (vaultLock) {\n await vaultLock.publishMarker(obsidian);\n }\n\n await obsidian.dev.resetDiagnostics().catch(() => {});\n\n const vault = await vaultFactory(obsidian);\n sandbox = await createSandboxApi({\n obsidian,\n sandboxRoot: options.sandboxRoot ?? DEFAULT_SANDBOX_ROOT,\n testName: options.testName ?? \"test\",\n });\n\n const captureArtifacts = async (task: FailureArtifactTask) =>\n captureFailureArtifacts(task, obsidian, {\n ...options,\n plugin: trackedPlugins.size === 1 ? [...trackedPlugins.values()][0]!.plugin : undefined,\n });\n\n const cleanup: TestContext[\"cleanup\"] = async (cleanupOptions = {}) => {\n if (disposed) {\n return;\n }\n\n disposed = true;\n const cleanupErrors: unknown[] = [];\n\n try {\n if (cleanupOptions.failedTask && options.captureOnFailure) {\n await captureArtifacts(cleanupOptions.failedTask);\n }\n } finally {\n try {\n await getClientInternals(obsidian).restoreAll();\n } finally {\n for (const session of [...trackedPlugins.values()].reverse()) {\n if (!session.wasEnabled) {\n await recordCleanupError(cleanupErrors, async () =>\n session.plugin.disable({ filter: session.filter }),\n );\n }\n }\n\n try {\n await clearVaultRunLockMarker(obsidian);\n } catch {}\n\n if (ownsVaultLock) {\n await recordCleanupError(cleanupErrors, async () => vaultLock.release());\n }\n\n await recordCleanupError(cleanupErrors, async () => sandbox!.cleanup());\n }\n }\n\n if (cleanupErrors.length === 1) {\n throw cleanupErrors[0];\n }\n\n if (cleanupErrors.length > 1) {\n throw new AggregateError(cleanupErrors, \"One or more test cleanup steps failed.\");\n }\n };\n\n return {\n obsidian,\n sandbox: sandbox!,\n vault,\n captureFailureArtifacts: captureArtifacts,\n cleanup,\n async plugin(id: string, sessionOptions: PluginSessionOptions = {}) {\n const existing = trackedPlugins.get(id);\n\n if (existing) {\n return existing.plugin;\n }\n\n const plugin = obsidian.plugin(id);\n const wasEnabled = await plugin.isEnabled();\n\n if (!wasEnabled) {\n await plugin.enable({ filter: sessionOptions.filter });\n }\n\n if (sessionOptions.seedData !== undefined) {\n await plugin.data().write(sessionOptions.seedData);\n }\n\n trackedPlugins.set(id, {\n filter: sessionOptions.filter,\n plugin,\n wasEnabled,\n });\n\n return plugin;\n },\n async resetDiagnostics() {\n await obsidian.dev.resetDiagnostics().catch(() => {});\n },\n };\n } catch (error) {\n try {\n if (sandbox) {\n await sandbox.cleanup();\n }\n } finally {\n try {\n await clearVaultRunLockMarker(obsidian);\n } catch {}\n\n if (ownsVaultLock) {\n await vaultLock.release();\n }\n }\n\n throw error;\n }\n}\n\nasync function recordCleanupError(\n cleanupErrors: unknown[],\n run: () => Promise<void>,\n): Promise<void> {\n try {\n await run();\n } catch (error) {\n cleanupErrors.push(error);\n }\n}\n\nasync function maybeAcquireVaultLock(\n options: CreateObsidianTestOptions,\n obsidian: ObsidianClient,\n): Promise<VaultRunLock | null> {\n if (!options.sharedVaultLock) {\n return null;\n }\n\n const lockOptions = options.sharedVaultLock === true ? {} : options.sharedVaultLock;\n\n return acquireVaultRunLock({\n ...lockOptions,\n vaultName: options.vault,\n vaultPath: await obsidian.vaultPath(),\n });\n}\n"],"mappings":"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"}
|
|
@@ -159,6 +159,7 @@ interface ObsidianDevHandle {
|
|
|
159
159
|
dom(options: DevDomQueryOptions, execOptions?: ExecOptions): Promise<DevDomResult>;
|
|
160
160
|
editorText(execOptions?: ExecOptions): Promise<string | null>;
|
|
161
161
|
eval<T = unknown>(code: string, options?: ExecOptions): Promise<T>;
|
|
162
|
+
evalJson<T = unknown>(code: string, options?: ExecOptions): Promise<T>;
|
|
162
163
|
evalRaw(code: string, options?: ExecOptions): Promise<string>;
|
|
163
164
|
notices(execOptions?: ExecOptions): Promise<DevNoticeEvent[]>;
|
|
164
165
|
resetDiagnostics(execOptions?: ExecOptions): Promise<void>;
|
|
@@ -244,13 +245,10 @@ interface VaultApi {
|
|
|
244
245
|
interface SandboxApi extends VaultApi {
|
|
245
246
|
readonly root: string;
|
|
246
247
|
cleanup(): Promise<void>;
|
|
247
|
-
frontmatter<T extends NoteFrontmatter = NoteFrontmatter>(path: string): Promise<T | null>;
|
|
248
248
|
path(...segments: string[]): string;
|
|
249
249
|
readNote<TFrontmatter extends NoteFrontmatter | null = NoteFrontmatter | null>(path: string): Promise<NoteDocument<TFrontmatter>>;
|
|
250
|
-
waitForFrontmatter<T extends NoteFrontmatter = NoteFrontmatter>(path: string, predicate?: MetadataPredicate<T>, options?: MetadataWaitOptions): Promise<T>;
|
|
251
|
-
waitForMetadata<T = MetadataFileCache>(path: string, predicate?: MetadataPredicate<T>, options?: MetadataWaitOptions): Promise<T>;
|
|
252
250
|
writeNote<TFrontmatter extends NoteFrontmatter | null = NoteFrontmatter | null>(options: SandboxWriteNoteOptions<TFrontmatter>): Promise<NoteDocument<TFrontmatter>>;
|
|
253
251
|
}
|
|
254
252
|
//#endregion
|
|
255
253
|
export { PluginHandle as A, VaultApi as B, ObsidianClient as C, OpenFileOptions as D, ObsidianMetadataHandle as E, PluginWaitUntilReadyOptions as F, WorkspaceNode as G, VaultWaitForContentOptions as H, PluginWithPatchedDataOptions as I, WorkspaceOptions as K, RestartAppOptions as L, PluginToggleOptions as M, PluginUpdateDataOptions as N, OpenTabOptions as O, PluginWaitForDataOptions as P, SandboxApi as R, ObsidianArg as S, ObsidianDevHandle as T, VaultWriteOptions as U, VaultContentPredicate as V, WaitForOptions as W, NoteDocument as _, DevDiagnostics as a, NoteMatcherOptions as b, DevNoticeEvent as c, ExecResult as d, JsonFile as f, MetadataWaitOptions as g, MetadataPredicate as h, DevConsoleMessage as i, PluginReloadOptions as j, PluginDataPredicate as k, DevRuntimeError as l, MetadataFileCache as m, CommandTransport as n, DevDomQueryOptions as o, JsonFileUpdater as p, WorkspaceTab as q, CreateObsidianClientOptions as r, DevDomResult as s, CommandListOptions as t, ExecOptions as u, NoteFrontmatter as v, ObsidianCommandHandle as w, ObsidianAppHandle as x, NoteInput as y, TabsOptions as z };
|
|
256
|
-
//# sourceMappingURL=types-
|
|
254
|
+
//# sourceMappingURL=types-BUXaueDI.d.mts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as PluginHandle, B as VaultApi, C as ObsidianClient, M as PluginToggleOptions, R as SandboxApi, r as CreateObsidianClientOptions, y as NoteInput } from "./types-
|
|
1
|
+
import { A as PluginHandle, B as VaultApi, C as ObsidianClient, M as PluginToggleOptions, R as SandboxApi, r as CreateObsidianClientOptions, y as NoteInput } from "./types-BUXaueDI.mjs";
|
|
2
2
|
import { TestAPI } from "vite-plus/test";
|
|
3
3
|
|
|
4
4
|
//#region src/artifacts/failure-artifacts.d.ts
|
|
@@ -133,4 +133,4 @@ declare function inspectVaultRunLock({
|
|
|
133
133
|
declare function readVaultRunLockMarker(obsidian: ObsidianClient): Promise<VaultRunLockMetadata | null>;
|
|
134
134
|
//#endregion
|
|
135
135
|
export { FailureArtifactConfig as C, captureFailureArtifacts as D, FailureArtifactTask as E, DEFAULT_FAILURE_ARTIFACTS_DIR as S, FailureArtifactRegistrationOptions as T, TestContext as _, acquireVaultRunLock as a, VaultSeedEntry as b, readVaultRunLockMarker as c, ObsidianFixtures as d, ObsidianTest as f, SharedVaultLockOptions as g, PluginTest as h, VaultRunLockState as i, CreateObsidianTestOptions as l, PluginSessionOptions as m, VaultRunLock as n, clearVaultRunLockMarker as o, PluginFixtures as p, VaultRunLockMetadata as r, inspectVaultRunLock as s, AcquireVaultRunLockOptions as t, CreatePluginTestOptions as u, TestContextCleanupOptions as v, FailureArtifactOptions as w, CaptureFailureArtifactsOptions as x, VaultSeed as y };
|
|
136
|
-
//# sourceMappingURL=vault-lock-
|
|
136
|
+
//# sourceMappingURL=vault-lock-XcBHtwm9.d.mts.map
|
package/dist/vitest.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as acquireVaultRunLock, b as VaultSeedEntry, c as readVaultRunLockMarker, d as ObsidianFixtures, f as ObsidianTest, g as SharedVaultLockOptions, h as PluginTest, i as VaultRunLockState, l as CreateObsidianTestOptions, n as VaultRunLock, o as clearVaultRunLockMarker, p as PluginFixtures, r as VaultRunLockMetadata, s as inspectVaultRunLock, t as AcquireVaultRunLockOptions, u as CreatePluginTestOptions, y as VaultSeed } from "./vault-lock-
|
|
1
|
+
import { a as acquireVaultRunLock, b as VaultSeedEntry, c as readVaultRunLockMarker, d as ObsidianFixtures, f as ObsidianTest, g as SharedVaultLockOptions, h as PluginTest, i as VaultRunLockState, l as CreateObsidianTestOptions, n as VaultRunLock, o as clearVaultRunLockMarker, p as PluginFixtures, r as VaultRunLockMetadata, s as inspectVaultRunLock, t as AcquireVaultRunLockOptions, u as CreatePluginTestOptions, y as VaultSeed } from "./vault-lock-XcBHtwm9.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/fixtures/create-obsidian-test.d.ts
|
|
4
4
|
declare function createObsidianTest(options: CreateObsidianTestOptions): ObsidianTest;
|
package/dist/vitest.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as clearVaultRunLockMarker, d as createVaultApi, f as resolveFilesystemPath, i as acquireVaultRunLock, m as getClientInternals, o as inspectVaultRunLock, r as createBaseFixtures, s as readVaultRunLockMarker } from "./test-context-
|
|
1
|
+
import { a as clearVaultRunLockMarker, d as createVaultApi, f as resolveFilesystemPath, i as acquireVaultRunLock, m as getClientInternals, o as inspectVaultRunLock, r as createBaseFixtures, s as readVaultRunLockMarker } from "./test-context-Bl-e-83H.mjs";
|
|
2
2
|
import { t as createNoteDocument } from "./document-DunL2Moz.mjs";
|
|
3
3
|
import { test } from "vite-plus/test";
|
|
4
4
|
//#region src/fixtures/create-obsidian-test.ts
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"test-context-BprSx6U1.mjs","names":["DEFAULT_TIMEOUT_MS","DEFAULT_TIMEOUT_MS","sleep","sleep","pathPosix","pathPosix"],"sources":["../src/core/args.ts","../src/dev/harness.ts","../src/core/exec-options.ts","../src/core/internals.ts","../src/metadata/metadata.ts","../src/vault/json-file.ts","../src/plugin/plugin.ts","../src/core/errors.ts","../src/core/transport.ts","../src/core/wait.ts","../src/core/client.ts","../src/core/path-slug.ts","../src/vault/paths.ts","../src/vault/vault.ts","../src/artifacts/failure-artifacts.ts","../src/vault/sandbox.ts","../src/fixtures/vault-lock.ts","../src/fixtures/base-fixtures.ts","../src/fixtures/test-context.ts"],"sourcesContent":["import type { ObsidianArg } from \"./types\";\n\nexport function buildCommandArgv(\n vaultName: string,\n command: string,\n args: Record<string, ObsidianArg> = {},\n): string[] {\n const argv = [`vault=${vaultName}`, command];\n\n for (const [key, value] of Object.entries(args)) {\n if (value === false || value === null || value === undefined) {\n continue;\n }\n\n if (value === true) {\n argv.push(key);\n continue;\n }\n\n argv.push(`${key}=${String(value)}`);\n }\n\n return argv;\n}\n","import type {\n DevConsoleMessage,\n DevDiagnostics,\n DevEvalErrorPayload,\n DevNoticeEvent,\n DevRuntimeError,\n} from \"../core/types\";\n\nconst HARNESS_NAMESPACE = \"__obsidianE2E\";\nconst HARNESS_VERSION = 1;\n\nexport type HarnessMethodName =\n | \"activeFilePath\"\n | \"consoleMessages\"\n | \"diagnostics\"\n | \"editorText\"\n | \"eval\"\n | \"frontmatter\"\n | \"metadata\"\n | \"notices\"\n | \"pluginLoaded\"\n | \"resetDiagnostics\"\n | \"runtimeErrors\";\n\ninterface HarnessEnvelopeSuccess {\n ok: true;\n value: unknown;\n}\n\ninterface HarnessEnvelopeError {\n error: DevEvalErrorPayload;\n ok: false;\n}\n\ntype HarnessEnvelope = HarnessEnvelopeError | HarnessEnvelopeSuccess;\n\nexport function buildHarnessCallCode(method: HarnessMethodName, ...args: unknown[]): string {\n return `(() => {\n const __obsidianE2EMethod = ${JSON.stringify(method)};\n const __obsidianE2EArgs = ${JSON.stringify(args)};\n const __obsidianE2ENamespace = ${JSON.stringify(HARNESS_NAMESPACE)};\n const __obsidianE2EVersion = ${HARNESS_VERSION};\n${HARNESS_RUNTIME}\n })()`;\n}\n\nexport function parseHarnessEnvelope<T>(raw: string): T {\n const envelope = JSON.parse(raw.startsWith(\"=> \") ? raw.slice(3) : raw) as HarnessEnvelope;\n\n if (!envelope.ok) {\n throw envelope.error;\n }\n\n return decodeHarnessValue(envelope.value) as T;\n}\n\nfunction decodeHarnessValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map((entry) => decodeHarnessValue(entry));\n }\n\n if (!value || typeof value !== \"object\") {\n return value;\n }\n\n if (\"__obsidianE2EType\" in value && value.__obsidianE2EType === \"undefined\") {\n return undefined;\n }\n\n return Object.fromEntries(\n Object.entries(value).map(([key, entry]) => [key, decodeHarnessValue(entry)]),\n );\n}\n\nexport function createDevDiagnostics(value: DevDiagnostics | null | undefined): DevDiagnostics {\n return {\n consoleMessages: (value?.consoleMessages ?? []) as DevConsoleMessage[],\n notices: (value?.notices ?? []) as DevNoticeEvent[],\n runtimeErrors: (value?.runtimeErrors ?? []) as DevRuntimeError[],\n };\n}\n\nconst HARNESS_RUNTIME = String.raw`\n const __obsidianE2EMaxEntries = 100;\n\n const __obsidianE2EPush = (entries, value) => {\n if (entries.length >= __obsidianE2EMaxEntries) {\n entries.shift();\n }\n entries.push(value);\n };\n\n const __obsidianE2EFormat = (value) => {\n if (typeof value === \"string\") {\n return value;\n }\n\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n };\n\n const __obsidianE2ESerialize = (value, path = \"$\") => {\n if (value === null) {\n return null;\n }\n\n if (value === undefined) {\n return { __obsidianE2EType: \"undefined\" };\n }\n\n const valueType = typeof value;\n\n if (valueType === \"string\" || valueType === \"boolean\") {\n return value;\n }\n\n if (valueType === \"number\") {\n if (!Number.isFinite(value)) {\n throw new Error(\\`Cannot serialize non-finite number at \\${path}.\\`);\n }\n\n return value;\n }\n\n if (valueType === \"bigint\" || valueType === \"function\" || valueType === \"symbol\") {\n throw new Error(\\`Cannot serialize \\${valueType} at \\${path}.\\`);\n }\n\n if (Array.isArray(value)) {\n return value.map((item, index) => __obsidianE2ESerialize(item, \\`\\${path}[\\${index}]\\`));\n }\n\n const prototype = Object.getPrototypeOf(value);\n\n if (prototype !== Object.prototype && prototype !== null) {\n throw new Error(\\`Cannot serialize non-plain object at \\${path}.\\`);\n }\n\n const next = {};\n\n for (const [key, entry] of Object.entries(value)) {\n next[key] = __obsidianE2ESerialize(entry, \\`\\${path}.\\${key}\\`);\n }\n\n return next;\n };\n\n const __obsidianE2EClone = (value) => JSON.parse(JSON.stringify(__obsidianE2ESerialize(value)));\n\n const __obsidianE2ECreateHarness = () => {\n const state = {\n consoleMessages: [],\n notices: [],\n runtimeErrors: [],\n };\n\n const pushConsoleMessage = (level, args) => {\n __obsidianE2EPush(state.consoleMessages, {\n args: args.map((entry) => {\n try {\n return __obsidianE2EClone(entry);\n } catch {\n return __obsidianE2EFormat(entry);\n }\n }),\n at: Date.now(),\n level,\n text: args.map(__obsidianE2EFormat).join(\" \"),\n });\n };\n\n const pushRuntimeError = (source, errorLike) => {\n const message =\n errorLike && typeof errorLike === \"object\" && \"message\" in errorLike\n ? String(errorLike.message)\n : String(errorLike);\n const stack =\n errorLike && typeof errorLike === \"object\" && \"stack\" in errorLike\n ? String(errorLike.stack)\n : undefined;\n\n __obsidianE2EPush(state.runtimeErrors, {\n at: Date.now(),\n message,\n source,\n stack,\n });\n };\n\n const installConsolePatch = (root) => {\n if (root.__obsidianE2EConsolePatched) {\n return;\n }\n\n for (const level of [\"debug\", \"error\", \"info\", \"log\", \"warn\"]) {\n const original = root.console?.[level];\n\n if (typeof original !== \"function\") {\n continue;\n }\n\n root.console[level] = (...args) => {\n pushConsoleMessage(level, args);\n return original.apply(root.console, args);\n };\n }\n\n root.__obsidianE2EConsolePatched = true;\n };\n\n const installRuntimePatch = (root) => {\n if (root.__obsidianE2ERuntimePatched || typeof root.addEventListener !== \"function\") {\n return;\n }\n\n root.addEventListener(\"error\", (event) => {\n pushRuntimeError(\"error\", event?.error ?? event?.message ?? \"Unknown error\");\n });\n root.addEventListener(\"unhandledrejection\", (event) => {\n pushRuntimeError(\"unhandledrejection\", event?.reason ?? \"Unhandled rejection\");\n });\n\n root.__obsidianE2ERuntimePatched = true;\n };\n\n const installNoticePatch = (root) => {\n if (root.__obsidianE2ENoticePatched || typeof root.Notice !== \"function\") {\n return;\n }\n\n const OriginalNotice = root.Notice;\n root.Notice = new Proxy(OriginalNotice, {\n construct(target, ctorArgs, newTarget) {\n __obsidianE2EPush(state.notices, {\n at: Date.now(),\n message: __obsidianE2EFormat(ctorArgs[0] ?? \"\"),\n timeout:\n typeof ctorArgs[1] === \"number\" && Number.isFinite(ctorArgs[1])\n ? ctorArgs[1]\n : undefined,\n });\n\n return Reflect.construct(target, ctorArgs, newTarget);\n },\n });\n root.__obsidianE2ENoticePatched = true;\n };\n\n const ensureInstalled = () => {\n const root = globalThis;\n installConsolePatch(root);\n installRuntimePatch(root);\n installNoticePatch(root);\n };\n\n const getFileCache = (vaultPath) => {\n const file = app?.vault?.getAbstractFileByPath?.(vaultPath);\n if (!file) {\n return null;\n }\n\n return app?.metadataCache?.getFileCache?.(file) ?? null;\n };\n\n return {\n activeFilePath() {\n ensureInstalled();\n return app?.workspace?.getActiveFile?.()?.path ?? null;\n },\n consoleMessages() {\n ensureInstalled();\n return state.consoleMessages;\n },\n diagnostics() {\n ensureInstalled();\n return state;\n },\n editorText() {\n ensureInstalled();\n return app?.workspace?.activeLeaf?.view?.editor?.getValue?.() ?? null;\n },\n eval(code) {\n ensureInstalled();\n return (0, eval)(code);\n },\n frontmatter(vaultPath) {\n ensureInstalled();\n return getFileCache(vaultPath)?.frontmatter ?? null;\n },\n metadata(vaultPath) {\n ensureInstalled();\n return getFileCache(vaultPath);\n },\n notices() {\n ensureInstalled();\n return state.notices;\n },\n pluginLoaded(pluginId) {\n ensureInstalled();\n const plugins = app?.plugins;\n return Boolean(\n plugins?.enabledPlugins?.has?.(pluginId) &&\n plugins?.plugins?.[pluginId],\n );\n },\n resetDiagnostics() {\n state.consoleMessages.splice(0);\n state.notices.splice(0);\n state.runtimeErrors.splice(0);\n ensureInstalled();\n return true;\n },\n runtimeErrors() {\n ensureInstalled();\n return state.runtimeErrors;\n },\n };\n };\n\n const root = globalThis;\n const current = root[__obsidianE2ENamespace];\n const harness =\n current && current.version === __obsidianE2EVersion\n ? current\n : (root[__obsidianE2ENamespace] = {\n api: __obsidianE2ECreateHarness(),\n version: __obsidianE2EVersion,\n });\n\n try {\n const result = harness.api[__obsidianE2EMethod](...__obsidianE2EArgs);\n return JSON.stringify({\n ok: true,\n value: __obsidianE2ESerialize(result),\n });\n } catch (error) {\n return JSON.stringify({\n error: {\n message: error instanceof Error ? error.message : String(error),\n name: error instanceof Error ? error.name : \"Error\",\n stack: error instanceof Error ? error.stack : undefined,\n },\n ok: false,\n });\n }`;\n","import type { ExecOptions } from \"./types\";\n\nexport function mergeExecOptions(\n defaults: ExecOptions | undefined,\n overrides: ExecOptions | undefined,\n): ExecOptions {\n if (!defaults) {\n return overrides ? { ...overrides } : {};\n }\n\n if (!overrides) {\n return { ...defaults };\n }\n\n return {\n ...defaults,\n ...overrides,\n env: mergeEnvironments(defaults.env, overrides.env),\n };\n}\n\nfunction mergeEnvironments(\n defaults: NodeJS.ProcessEnv | undefined,\n overrides: NodeJS.ProcessEnv | undefined,\n): NodeJS.ProcessEnv | undefined {\n if (!defaults) {\n return overrides ? { ...overrides } : undefined;\n }\n\n if (!overrides) {\n return { ...defaults };\n }\n\n return {\n ...defaults,\n ...overrides,\n };\n}\n","import { rm, writeFile } from \"node:fs/promises\";\n\nimport type { ObsidianClient } from \"./types\";\n\ninterface SnapshotEntry {\n exists: boolean;\n value: string;\n}\n\ninterface ClientInternals {\n restoreAll(): Promise<void>;\n restoreFile(filePath: string): Promise<void>;\n snapshotFileOnce(filePath: string): Promise<void>;\n}\n\nconst clientInternals = new WeakMap<ObsidianClient, ClientInternals>();\n\nexport function attachClientInternals(client: ObsidianClient, internals: ClientInternals): void {\n clientInternals.set(client, internals);\n}\n\nexport function getClientInternals(client: ObsidianClient): ClientInternals {\n const internals = clientInternals.get(client);\n\n if (!internals) {\n throw new Error(\"Missing obsidian client internals.\");\n }\n\n return internals;\n}\n\nexport function createRestoreManager(readFile: (filePath: string) => Promise<string>) {\n const snapshots = new Map<string, SnapshotEntry>();\n\n return {\n async restoreAll() {\n const entries = [...snapshots.entries()].reverse();\n\n for (const [filePath, snapshot] of entries) {\n await restoreSnapshot(filePath, snapshot);\n }\n\n snapshots.clear();\n },\n async restoreFile(filePath: string) {\n const snapshot = snapshots.get(filePath);\n\n if (!snapshot) {\n return;\n }\n\n await restoreSnapshot(filePath, snapshot);\n snapshots.delete(filePath);\n },\n async snapshotFileOnce(filePath: string) {\n if (snapshots.has(filePath)) {\n return;\n }\n\n try {\n snapshots.set(filePath, {\n exists: true,\n value: await readFile(filePath),\n });\n } catch (error) {\n if (isMissingFileError(error)) {\n snapshots.set(filePath, {\n exists: false,\n value: \"\",\n });\n return;\n }\n\n throw error;\n }\n },\n };\n}\n\nasync function restoreSnapshot(filePath: string, snapshot: SnapshotEntry): Promise<void> {\n if (snapshot.exists) {\n await writeFile(filePath, snapshot.value, \"utf8\");\n return;\n }\n\n await rm(filePath, { force: true, recursive: true });\n}\n\nfunction isMissingFileError(error: unknown): error is NodeJS.ErrnoException {\n return Boolean(error && typeof error === \"object\" && \"code\" in error && error.code === \"ENOENT\");\n}\n","import { buildHarnessCallCode, parseHarnessEnvelope } from \"../dev/harness\";\nimport type {\n ExecOptions,\n MetadataFileCache,\n MetadataPredicate,\n MetadataWaitOptions,\n NoteFrontmatter,\n ObsidianClient,\n ObsidianMetadataHandle,\n} from \"../core/types\";\n\nexport function createObsidianMetadataHandle(client: ObsidianClient): ObsidianMetadataHandle {\n return {\n async fileCache<T = MetadataFileCache>(path: string, execOptions?: ExecOptions) {\n return readMetadata<T | null>(client, \"metadata\", path, execOptions);\n },\n async frontmatter<T extends NoteFrontmatter = NoteFrontmatter>(\n path: string,\n execOptions?: ExecOptions,\n ) {\n return readMetadata<T | null>(client, \"frontmatter\", path, execOptions);\n },\n async waitForFileCache<T = MetadataFileCache>(\n path: string,\n predicate?: MetadataPredicate<T>,\n options?: MetadataWaitOptions,\n ) {\n return waitForPresentValue(\n client,\n path,\n () => client.metadata.fileCache<T>(path),\n predicate,\n \"metadata cache\",\n options,\n );\n },\n async waitForFrontmatter<T extends NoteFrontmatter = NoteFrontmatter>(\n path: string,\n predicate?: MetadataPredicate<T>,\n options?: MetadataWaitOptions,\n ) {\n return waitForPresentValue(\n client,\n path,\n () => client.metadata.frontmatter<T>(path),\n predicate,\n \"frontmatter\",\n options,\n );\n },\n async waitForMetadata<T = MetadataFileCache>(\n path: string,\n predicate?: MetadataPredicate<T>,\n options?: MetadataWaitOptions,\n ) {\n return waitForPresentValue(\n client,\n path,\n () => client.metadata.fileCache<T>(path),\n predicate,\n \"metadata\",\n options,\n );\n },\n };\n}\n\nasync function readMetadata<T>(\n client: ObsidianClient,\n method: \"frontmatter\" | \"metadata\",\n path: string,\n execOptions?: ExecOptions,\n): Promise<T> {\n return parseHarnessEnvelope<T>(\n await client.dev.evalRaw(buildHarnessCallCode(method, path), execOptions),\n );\n}\n\nasync function waitForPresentValue<T>(\n client: ObsidianClient,\n path: string,\n readValue: () => Promise<T | null>,\n predicate: MetadataPredicate<T> | undefined,\n label: string,\n options: MetadataWaitOptions = {},\n): Promise<T> {\n return client.waitFor(\n async () => {\n const value = await readValue();\n\n if (value === null) {\n return false;\n }\n\n return (await (predicate?.(value) ?? true)) ? value : false;\n },\n {\n ...options,\n message: options.message ?? `vault path \"${path}\" to expose ${label}`,\n },\n );\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { JsonFile, JsonFileUpdater } from \"../core/types\";\n\nexport function createJsonFile<T = unknown>(\n filePath: string,\n beforeMutate?: () => Promise<void>,\n): JsonFile<T> {\n return {\n async patch(updater: JsonFileUpdater<T>) {\n await beforeMutate?.();\n\n const currentValue = await this.read();\n const draft = structuredClone(currentValue);\n const result = await updater(draft);\n const nextValue = result ?? draft;\n\n await this.write(nextValue);\n\n return nextValue;\n },\n async read() {\n const value = await readFile(filePath, \"utf8\");\n return JSON.parse(value) as T;\n },\n async write(value: T) {\n await beforeMutate?.();\n await mkdir(path.dirname(filePath), { recursive: true });\n await writeFile(filePath, `${JSON.stringify(value, null, 2)}\\n`, \"utf8\");\n },\n };\n}\n","import path from \"node:path\";\n\nimport { buildHarnessCallCode, parseHarnessEnvelope } from \"../dev/harness\";\nimport { getClientInternals } from \"../core/internals\";\nimport type {\n JsonFile,\n JsonFileUpdater,\n ObsidianClient,\n PluginDataPredicate,\n PluginHandle,\n PluginReloadOptions,\n PluginToggleOptions,\n PluginUpdateDataOptions,\n PluginWithPatchedDataOptions,\n PluginWaitForDataOptions,\n PluginWaitUntilReadyOptions,\n} from \"../core/types\";\nimport { createJsonFile } from \"../vault/json-file\";\n\nexport function createPluginHandle(client: ObsidianClient, id: string): PluginHandle {\n async function resolveDataPath() {\n const vaultPath = await client.vaultPath();\n return path.join(vaultPath, \".obsidian\", \"plugins\", id, \"data.json\");\n }\n\n async function isLoadedInApp(): Promise<boolean> {\n try {\n return parseHarnessEnvelope<boolean>(\n await client.dev.evalRaw(buildHarnessCallCode(\"pluginLoaded\", id)),\n );\n } catch {\n return false;\n }\n }\n\n function withDefaultReadyReloadOptions(options: PluginReloadOptions = {}): PluginReloadOptions {\n return {\n ...options,\n waitUntilReady: options.waitUntilReady ?? true,\n };\n }\n\n return {\n data<T = unknown>(): JsonFile<T> {\n return {\n async patch(updater) {\n const dataPath = await resolveDataPath();\n return createJsonFile<T>(dataPath, () =>\n getClientInternals(client).snapshotFileOnce(dataPath),\n ).patch(updater);\n },\n async read() {\n const dataPath = await resolveDataPath();\n return createJsonFile<T>(dataPath).read();\n },\n async write(value) {\n const dataPath = await resolveDataPath();\n await createJsonFile<T>(dataPath, () =>\n getClientInternals(client).snapshotFileOnce(dataPath),\n ).write(value);\n },\n };\n },\n async dataPath() {\n return resolveDataPath();\n },\n async disable(options: PluginToggleOptions = {}) {\n await client.exec(\"plugin:disable\", {\n filter: options.filter,\n id,\n });\n },\n async enable(options: PluginToggleOptions = {}) {\n await client.exec(\"plugin:enable\", {\n filter: options.filter,\n id,\n });\n },\n id,\n async isEnabled() {\n const output = await client.execText(\"plugin\", { id }, { allowNonZeroExit: true });\n return /enabled\\s+true/i.test(output);\n },\n async reload(options: PluginReloadOptions = {}) {\n const { readyOptions, waitUntilReady, ...execOptions } = options;\n\n await client.exec(\"plugin:reload\", { id }, execOptions);\n\n if (waitUntilReady) {\n await this.waitUntilReady(readyOptions);\n }\n },\n async restoreData() {\n await getClientInternals(client).restoreFile(await resolveDataPath());\n },\n async updateDataAndReload<T = unknown>(\n updater: JsonFileUpdater<T>,\n options: PluginUpdateDataOptions<T> = {},\n ): Promise<T> {\n const nextData = await this.data<T>().patch(updater);\n\n if (await this.isEnabled()) {\n await this.reload(withDefaultReadyReloadOptions(options));\n }\n\n return nextData;\n },\n async withPatchedData<T = unknown, TResult = void>(\n updater: JsonFileUpdater<T>,\n run: (plugin: PluginHandle) => Promise<TResult> | TResult,\n options: PluginWithPatchedDataOptions<T> = {},\n ): Promise<TResult> {\n const pluginWasEnabled = await this.isEnabled();\n const reloadOptions = withDefaultReadyReloadOptions(options);\n let hasPatchedData = false;\n let runResult: TResult | undefined;\n let runError: unknown;\n let restoreError: unknown;\n\n try {\n await this.data<T>().patch(updater);\n hasPatchedData = true;\n\n if (pluginWasEnabled) {\n await this.reload(reloadOptions);\n }\n\n runResult = await run(this);\n } catch (error) {\n runError = error;\n }\n\n if (hasPatchedData) {\n try {\n await this.restoreData();\n\n if (pluginWasEnabled) {\n await this.reload(reloadOptions);\n }\n } catch (error) {\n restoreError = error;\n }\n }\n\n if (runError && restoreError) {\n throw new AggregateError(\n [runError, restoreError],\n `Plugin \"${id}\" patch execution and restore both failed.`,\n );\n }\n\n if (runError) {\n throw runError;\n }\n\n if (restoreError) {\n throw restoreError;\n }\n\n return runResult as TResult;\n },\n async waitForData<T = unknown>(\n predicate: PluginDataPredicate<T>,\n options: PluginWaitForDataOptions = {},\n ) {\n return client.waitFor(async () => {\n try {\n const data = await this.data<T>().read();\n return (await predicate(data)) ? data : false;\n } catch {\n return false;\n }\n }, options);\n },\n async waitUntilReady(options: PluginWaitUntilReadyOptions = {}) {\n await client.waitFor(\n async () => {\n if (!(await isLoadedInApp())) {\n return false;\n }\n\n if (options.commandId) {\n return await client.command(options.commandId).exists();\n }\n\n return true;\n },\n {\n ...options,\n message:\n options.message ??\n (options.commandId\n ? `plugin \"${id}\" to be ready with command \"${options.commandId}\"`\n : `plugin \"${id}\" to be ready`),\n },\n );\n },\n };\n}\n","import type { ExecResult } from \"./types\";\nimport type { DevEvalErrorPayload } from \"./types\";\n\nexport class ObsidianCommandError extends Error {\n readonly result: ExecResult;\n\n constructor(message: string, result: ExecResult) {\n super(message);\n this.name = \"ObsidianCommandError\";\n this.result = result;\n }\n}\n\nexport class WaitForTimeoutError extends Error {\n readonly causeError?: unknown;\n\n constructor(message: string, causeError?: unknown) {\n super(message);\n this.name = \"WaitForTimeoutError\";\n this.causeError = causeError;\n }\n}\n\nexport class DevEvalError extends Error {\n readonly remote: DevEvalErrorPayload;\n\n constructor(message: string, remote: DevEvalErrorPayload) {\n super(message);\n this.name = \"DevEvalError\";\n this.remote = remote;\n\n if (remote.stack) {\n this.stack = `${this.name}: ${message}\\nRemote stack:\\n${remote.stack}`;\n }\n }\n}\n","import { spawn } from \"node:child_process\";\n\nimport { ObsidianCommandError } from \"./errors\";\nimport type { CommandTransport, ExecuteRequest, ExecResult } from \"./types\";\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport const executeCommand: CommandTransport = async ({\n allowNonZeroExit = false,\n argv,\n bin,\n cwd,\n env,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n}: ExecuteRequest): Promise<ExecResult> => {\n const child = spawn(bin, argv, {\n cwd,\n env,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n\n child.stdout.on(\"data\", (chunk) => {\n stdoutChunks.push(Buffer.from(chunk));\n });\n\n child.stderr.on(\"data\", (chunk) => {\n stderrChunks.push(Buffer.from(chunk));\n });\n\n const exitCode = await new Promise<number>((resolve, reject) => {\n const timer = setTimeout(() => {\n child.kill(\"SIGTERM\");\n reject(new Error(`Command timed out after ${timeoutMs}ms: ${bin} ${argv.join(\" \")}`));\n }, timeoutMs);\n\n child.on(\"error\", (error) => {\n clearTimeout(timer);\n reject(error);\n });\n\n child.on(\"close\", (code) => {\n clearTimeout(timer);\n resolve(code ?? 0);\n });\n });\n\n const result: ExecResult = {\n argv,\n command: bin,\n exitCode,\n stderr: Buffer.concat(stderrChunks).toString(\"utf8\"),\n stdout: Buffer.concat(stdoutChunks).toString(\"utf8\"),\n };\n\n if (exitCode !== 0 && !allowNonZeroExit) {\n throw new ObsidianCommandError(\n `Obsidian command failed with exit code ${exitCode}: ${bin} ${argv.join(\" \")}`,\n result,\n );\n }\n\n return result;\n};\n","import { WaitForTimeoutError } from \"./errors\";\nimport type { WaitForOptions } from \"./types\";\n\nconst DEFAULT_INTERVAL_MS = 100;\nconst DEFAULT_TIMEOUT_MS = 5_000;\n\nexport async function sleep(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function waitForValue<T>(\n fn: () => Promise<T | false | null | undefined> | T | false | null | undefined,\n options: WaitForOptions = {},\n): Promise<T> {\n const intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const startTime = Date.now();\n\n let lastError: unknown;\n\n while (Date.now() - startTime <= timeoutMs) {\n try {\n const result = await fn();\n if (result !== false && result !== null && result !== undefined) {\n return result;\n }\n } catch (error) {\n lastError = error;\n }\n\n await sleep(intervalMs);\n }\n\n const label = options.message ?? \"condition\";\n throw new WaitForTimeoutError(`Timed out waiting for ${label} after ${timeoutMs}ms.`, lastError);\n}\n","import { buildCommandArgv } from \"./args\";\nimport { buildHarnessCallCode, createDevDiagnostics, parseHarnessEnvelope } from \"../dev/harness\";\nimport { mergeExecOptions } from \"./exec-options\";\nimport { attachClientInternals, createRestoreManager } from \"./internals\";\nimport { createObsidianMetadataHandle } from \"../metadata/metadata\";\nimport { createPluginHandle } from \"../plugin/plugin\";\nimport { executeCommand } from \"./transport\";\nimport type {\n CommandListOptions,\n CreateObsidianClientOptions,\n DevConsoleMessage,\n DevDiagnostics,\n DevNoticeEvent,\n DevDomQueryOptions,\n DevDomResult,\n DevRuntimeError,\n ExecOptions,\n ObsidianArg,\n ObsidianAppHandle,\n ObsidianCommandHandle,\n ObsidianClient,\n ObsidianDevHandle,\n OpenFileOptions,\n OpenTabOptions,\n RestartAppOptions,\n TabsOptions,\n WaitForOptions,\n WorkspaceNode,\n WorkspaceOptions,\n WorkspaceTab,\n} from \"./types\";\nimport { DevEvalError } from \"./errors\";\nimport { sleep, waitForValue } from \"./wait\";\n\nexport function createObsidianClient(options: CreateObsidianClientOptions): ObsidianClient {\n const transport = options.transport ?? executeCommand;\n const defaultExecOptions = options.defaultExecOptions;\n const waitDefaults = {\n intervalMs: options.intervalMs,\n timeoutMs: options.timeoutMs,\n };\n\n const restoreManager = createRestoreManager(async (filePath) => {\n const { readFile } = await import(\"node:fs/promises\");\n return readFile(filePath, \"utf8\");\n });\n\n let cachedVaultPath: string | undefined;\n\n const client = {} as ObsidianClient;\n const metadata = createObsidianMetadataHandle(client);\n\n const app: ObsidianAppHandle = {\n async reload(execOptions: ExecOptions = {}) {\n await client.exec(\"reload\", {}, execOptions);\n },\n async restart({\n readyOptions,\n waitUntilReady = true,\n ...execOptions\n }: RestartAppOptions & ExecOptions = {}) {\n await client.exec(\"restart\", {}, execOptions);\n\n if (waitUntilReady) {\n await app.waitUntilReady(readyOptions);\n }\n },\n version(execOptions: ExecOptions = {}) {\n return client.execText(\"version\", {}, execOptions);\n },\n async waitUntilReady(waitOptions?: WaitForOptions) {\n await client.waitFor(async () => {\n try {\n await client.vaultPath();\n await client.commands();\n return true;\n } catch {\n return false;\n }\n }, waitOptions);\n },\n };\n\n const dev: ObsidianDevHandle = {\n async activeFilePath(execOptions: ExecOptions = {}) {\n return readHarnessValue<string | null>(this, \"activeFilePath\", execOptions);\n },\n async consoleMessages(execOptions: ExecOptions = {}) {\n return readHarnessValue<DevConsoleMessage[]>(this, \"consoleMessages\", execOptions);\n },\n async diagnostics(execOptions: ExecOptions = {}): Promise<DevDiagnostics> {\n return createDevDiagnostics(\n await readHarnessValue<DevDiagnostics>(this, \"diagnostics\", execOptions),\n );\n },\n async dom(options: DevDomQueryOptions, execOptions: ExecOptions = {}): Promise<DevDomResult> {\n const output = await client.execText(\n \"dev:dom\",\n {\n all: options.all,\n attr: options.attr,\n css: options.css,\n inner: options.inner,\n selector: options.selector,\n text: options.text,\n total: options.total,\n },\n execOptions,\n );\n\n if (options.total) {\n return Number.parseInt(output, 10);\n }\n\n if (options.all) {\n return output ? output.split(/\\r?\\n/u).filter(Boolean) : [];\n }\n\n return output;\n },\n async eval<T = unknown>(code: string, execOptions: ExecOptions = {}) {\n try {\n return parseHarnessEnvelope<T>(\n await this.evalRaw(buildHarnessCallCode(\"eval\", code), execOptions),\n );\n } catch (error) {\n if (\n error &&\n typeof error === \"object\" &&\n \"message\" in error &&\n \"name\" in error &&\n typeof error.message === \"string\" &&\n typeof error.name === \"string\"\n ) {\n throw new DevEvalError(`Failed to evaluate Obsidian code: ${error.message}`, {\n message: error.message,\n name: error.name,\n stack: \"stack\" in error && typeof error.stack === \"string\" ? error.stack : undefined,\n });\n }\n\n throw error;\n }\n },\n async evalRaw(code: string, execOptions: ExecOptions = {}) {\n return client.execText(\n \"eval\",\n {\n code,\n },\n execOptions,\n );\n },\n async editorText(execOptions: ExecOptions = {}) {\n return readHarnessValue<string | null>(this, \"editorText\", execOptions);\n },\n async notices(execOptions: ExecOptions = {}) {\n return readHarnessValue<DevNoticeEvent[]>(this, \"notices\", execOptions);\n },\n async resetDiagnostics(execOptions: ExecOptions = {}) {\n await readHarnessValue<void>(this, \"resetDiagnostics\", execOptions);\n },\n async runtimeErrors(execOptions: ExecOptions = {}) {\n return readHarnessValue<DevRuntimeError[]>(this, \"runtimeErrors\", execOptions);\n },\n async screenshot(targetPath: string, execOptions: ExecOptions = {}) {\n await client.exec(\n \"dev:screenshot\",\n {\n path: targetPath,\n },\n execOptions,\n );\n\n return targetPath;\n },\n };\n\n Object.assign(client, {\n app,\n bin: options.bin ?? \"obsidian\",\n dev,\n metadata,\n command(id: string): ObsidianCommandHandle {\n return {\n async exists(commandOptions: CommandListOptions = {}) {\n const commands = await client.commands({\n ...commandOptions,\n filter: commandOptions.filter ?? id,\n });\n\n return commands.includes(id);\n },\n id,\n async run(execOptions: ExecOptions = {}) {\n await client.exec(\"command\", { id }, execOptions);\n },\n };\n },\n async commands(\n commandOptions: CommandListOptions = {},\n execOptions: ExecOptions = {},\n ): Promise<string[]> {\n const output = await client.execText(\n \"commands\",\n {\n filter: commandOptions.filter,\n },\n execOptions,\n );\n return parseCommandIds(output);\n },\n exec(command: string, args: Record<string, ObsidianArg> = {}, execOptions: ExecOptions = {}) {\n return transport({\n ...mergeExecOptions(defaultExecOptions, execOptions),\n argv: buildCommandArgv(options.vault, command, args),\n bin: this.bin,\n });\n },\n async execJson<T = unknown>(\n command: string,\n args: Record<string, ObsidianArg> = {},\n execOptions: ExecOptions = {},\n ) {\n const output = await this.execText(command, args, execOptions);\n return JSON.parse(output) as T;\n },\n async execText(\n command: string,\n args: Record<string, ObsidianArg> = {},\n execOptions: ExecOptions = {},\n ) {\n const result = await this.exec(command, args, execOptions);\n return result.stdout.trimEnd();\n },\n async open(openOptions: OpenFileOptions, execOptions: ExecOptions = {}) {\n await client.exec(\n \"open\",\n {\n file: openOptions.file,\n newtab: openOptions.newTab,\n path: openOptions.path,\n },\n execOptions,\n );\n },\n async openTab(tabOptions: OpenTabOptions = {}, execOptions: ExecOptions = {}) {\n await client.exec(\n \"tab:open\",\n {\n file: tabOptions.file,\n group: tabOptions.group,\n view: tabOptions.view,\n },\n execOptions,\n );\n },\n plugin(id: string) {\n return createPluginHandle(this, id);\n },\n sleep(ms: number) {\n return sleep(ms);\n },\n async tabs(\n tabOptions: TabsOptions = {},\n execOptions: ExecOptions = {},\n ): Promise<WorkspaceTab[]> {\n const output = await client.execText(\n \"tabs\",\n {\n ids: tabOptions.ids ?? true,\n },\n execOptions,\n );\n return parseTabs(output);\n },\n async vaultPath() {\n if (!cachedVaultPath) {\n cachedVaultPath = await this.execText(\"vault\", { info: \"path\" });\n }\n\n return cachedVaultPath;\n },\n async verify() {\n await transport({\n ...mergeExecOptions(defaultExecOptions, undefined),\n argv: [\"--help\"],\n bin: this.bin,\n });\n\n await this.vaultPath();\n },\n vaultName: options.vault,\n async waitForActiveFile(path: string, options?: WaitForOptions) {\n return client.waitFor(\n async () => {\n const activePath = await dev.activeFilePath();\n\n return activePath === path ? activePath : false;\n },\n {\n ...options,\n message: options?.message ?? `active file \"${path}\"`,\n },\n );\n },\n async waitForConsoleMessage(\n predicate: (message: DevConsoleMessage) => boolean | Promise<boolean>,\n options?: WaitForOptions,\n ) {\n return waitForDiagnosticEntry(\n client,\n () => client.dev.consoleMessages(),\n predicate,\n options?.message ?? \"console message\",\n options,\n );\n },\n async waitForNotice(\n predicate: string | ((notice: DevNoticeEvent) => boolean | Promise<boolean>),\n options?: WaitForOptions,\n ) {\n return waitForDiagnosticEntry(\n client,\n () => client.dev.notices(),\n typeof predicate === \"string\" ? (notice) => notice.message.includes(predicate) : predicate,\n options?.message ?? \"notice\",\n options,\n );\n },\n async waitForRuntimeError(\n predicate: string | ((error: DevRuntimeError) => boolean | Promise<boolean>),\n options?: WaitForOptions,\n ) {\n return waitForDiagnosticEntry(\n client,\n () => client.dev.runtimeErrors(),\n typeof predicate === \"string\" ? (error) => error.message.includes(predicate) : predicate,\n options?.message ?? \"runtime error\",\n options,\n );\n },\n waitFor<T>(\n fn: () => Promise<T | false | null | undefined> | T | false | null | undefined,\n waitOptions?: WaitForOptions,\n ) {\n return waitForValue(fn, {\n ...waitDefaults,\n ...waitOptions,\n });\n },\n async workspace(\n workspaceOptions: WorkspaceOptions = {},\n execOptions: ExecOptions = {},\n ): Promise<WorkspaceNode[]> {\n const output = await client.execText(\n \"workspace\",\n {\n ids: workspaceOptions.ids ?? true,\n },\n execOptions,\n );\n return parseWorkspace(output);\n },\n });\n\n attachClientInternals(client, restoreManager);\n\n return client;\n}\n\nfunction parseCommandIds(output: string): string[] {\n return output\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter(Boolean)\n .map((line) => line.split(\"\\t\", 1)[0]?.trim() ?? \"\")\n .filter(Boolean);\n}\n\nfunction parseTabs(output: string): WorkspaceTab[] {\n return output\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter(Boolean)\n .map(parseTabLine);\n}\n\nfunction parseTabLine(line: string): WorkspaceTab {\n const [descriptor, id] = line.split(\"\\t\");\n const match = descriptor?.match(/^\\[(.+?)\\]\\s+(.*)$/u);\n\n if (!match) {\n return {\n id: id?.trim() || undefined,\n title: descriptor?.trim() ?? \"\",\n viewType: \"unknown\",\n };\n }\n\n return {\n id: id?.trim() || undefined,\n title: match[2]!,\n viewType: match[1]!,\n };\n}\n\nfunction parseWorkspace(output: string): WorkspaceNode[] {\n const roots: WorkspaceNode[] = [];\n const stack: Array<{ depth: number; node: WorkspaceNode }> = [];\n\n for (const rawLine of output.split(/\\r?\\n/u)) {\n if (!rawLine.trim()) {\n continue;\n }\n\n const depth = getWorkspaceDepth(rawLine);\n const node = parseWorkspaceNode(rawLine);\n\n while (stack.length > 0 && stack.at(-1)!.depth >= depth) {\n stack.pop();\n }\n\n const parent = stack.at(-1)?.node;\n\n if (parent) {\n parent.children.push(node);\n } else {\n roots.push(node);\n }\n\n stack.push({ depth, node });\n }\n\n return roots;\n}\n\nasync function waitForDiagnosticEntry<T>(\n client: ObsidianClient,\n readEntries: () => Promise<T[]>,\n predicate: (entry: T) => boolean | Promise<boolean>,\n label: string,\n options?: WaitForOptions,\n): Promise<T> {\n return client.waitFor(\n async () => {\n const entries = await readEntries();\n\n for (const entry of entries) {\n if (await predicate(entry)) {\n return entry;\n }\n }\n\n return false;\n },\n {\n ...options,\n message: options?.message ?? label,\n },\n );\n}\n\nasync function readHarnessValue<T>(\n dev: Pick<ObsidianDevHandle, \"evalRaw\">,\n method:\n | \"activeFilePath\"\n | \"consoleMessages\"\n | \"diagnostics\"\n | \"editorText\"\n | \"notices\"\n | \"resetDiagnostics\"\n | \"runtimeErrors\",\n execOptions?: ExecOptions,\n): Promise<T> {\n return parseHarnessEnvelope<T>(await dev.evalRaw(buildHarnessCallCode(method), execOptions));\n}\n\nfunction getWorkspaceDepth(line: string): number {\n let depth = 0;\n let remainder = line;\n\n while (true) {\n if (\n remainder.startsWith(\"│ \") ||\n remainder.startsWith(\" \") ||\n remainder.startsWith(\"├── \") ||\n remainder.startsWith(\"└── \")\n ) {\n depth += 1;\n remainder = remainder.slice(4);\n continue;\n }\n\n return depth;\n }\n}\n\nfunction parseWorkspaceNode(line: string): WorkspaceNode {\n let withoutTree = line;\n\n while (true) {\n if (\n withoutTree.startsWith(\"│ \") ||\n withoutTree.startsWith(\" \") ||\n withoutTree.startsWith(\"├── \") ||\n withoutTree.startsWith(\"└── \")\n ) {\n withoutTree = withoutTree.slice(4);\n continue;\n }\n\n break;\n }\n\n withoutTree = withoutTree.trim();\n const idMatch = withoutTree.match(/^(.*?)(?: \\(([a-z0-9]+)\\))?$/iu);\n const content = idMatch?.[1]?.trim() ?? withoutTree;\n const id = idMatch?.[2];\n const leafMatch = content.match(/^\\[(.+?)\\]\\s+(.*)$/u);\n\n if (leafMatch) {\n return {\n children: [],\n id,\n label: leafMatch[2]!,\n title: leafMatch[2]!,\n viewType: leafMatch[1]!,\n };\n }\n\n return {\n children: [],\n id,\n label: content,\n };\n}\n","export interface SanitizePathSegmentOptions {\n fallback?: string;\n maxLength?: number;\n}\n\nexport function sanitizePathSegment(\n value: string,\n options: SanitizePathSegmentOptions = {},\n): string {\n const fallback = options.fallback ?? \"test\";\n const maxLength = options.maxLength ?? 80;\n\n return (\n value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, maxLength) || fallback\n );\n}\n","import path from \"node:path\";\nimport { posix as pathPosix } from \"node:path\";\n\nimport type { ObsidianClient } from \"../core/types\";\n\nexport function normalizeScope(scope?: string): string {\n if (!scope || scope === \".\") {\n return \"\";\n }\n\n return scope.replace(/^\\/+|\\/+$/g, \"\");\n}\n\nexport function resolveVaultPath(scopeRoot: string, targetPath: string): string {\n if (!targetPath || targetPath === \".\") {\n return scopeRoot;\n }\n\n return scopeRoot ? pathPosix.join(scopeRoot, targetPath) : pathPosix.normalize(targetPath);\n}\n\nexport async function resolveFilesystemPath(\n obsidian: ObsidianClient,\n scopeRoot: string,\n targetPath: string,\n): Promise<string> {\n const vaultPath = await obsidian.vaultPath();\n const scopedPath = resolveVaultPath(scopeRoot, targetPath);\n const relativePath = scopedPath.split(\"/\").filter(Boolean);\n const resolvedPath = path.resolve(vaultPath, ...relativePath);\n const normalizedVaultPath = path.resolve(vaultPath);\n\n if (\n resolvedPath !== normalizedVaultPath &&\n !resolvedPath.startsWith(`${normalizedVaultPath}${path.sep}`)\n ) {\n throw new Error(`Resolved path escapes the vault root: ${targetPath}`);\n }\n\n return resolvedPath;\n}\n","import { access, mkdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type {\n DeleteOptions,\n JsonFile,\n ObsidianClient,\n VaultApi,\n VaultWaitForContentOptions,\n VaultWriteOptions,\n} from \"../core/types\";\nimport { normalizeScope, resolveFilesystemPath, resolveVaultPath } from \"./paths\";\n\ninterface CreateVaultApiOptions {\n obsidian: ObsidianClient;\n root?: string;\n}\n\nexport function createVaultApi(options: CreateVaultApiOptions): VaultApi {\n const scopeRoot = normalizeScope(options.root);\n\n return {\n async delete(targetPath, deleteOptions: DeleteOptions = {}) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n await rm(resolvedPath, {\n force: true,\n recursive: true,\n });\n\n if (deleteOptions.permanent === false) {\n return;\n }\n },\n async exists(targetPath) {\n try {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n await access(resolvedPath);\n return true;\n } catch {\n return false;\n }\n },\n json<T = unknown>(targetPath: string) {\n const jsonFile: JsonFile<T> = {\n async patch(updater) {\n const currentValue = await jsonFile.read();\n const draft = structuredClone(currentValue);\n const result = await updater(draft);\n const nextValue = result ?? draft;\n\n await jsonFile.write(nextValue);\n\n return nextValue;\n },\n async read() {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n const rawValue = await readFile(resolvedPath, \"utf8\");\n return JSON.parse(rawValue) as T;\n },\n async write(value) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n await mkdir(path.dirname(resolvedPath), { recursive: true });\n await writeFile(resolvedPath, `${JSON.stringify(value, null, 2)}\\n`, \"utf8\");\n },\n };\n\n return jsonFile;\n },\n async mkdir(targetPath) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n await mkdir(resolvedPath, { recursive: true });\n },\n async read(targetPath) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n return readFile(resolvedPath, \"utf8\");\n },\n async waitForContent(targetPath, predicate, waitOptions: VaultWaitForContentOptions = {}) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n\n return options.obsidian.waitFor(\n async () => {\n try {\n const content = await readFile(resolvedPath, \"utf8\");\n return (await predicate(content)) ? content : false;\n } catch {\n return false;\n }\n },\n {\n message: `vault path \"${resolveVaultPath(scopeRoot, targetPath)}\" to match content`,\n ...waitOptions,\n },\n );\n },\n async waitForExists(targetPath, waitOptions) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n\n await options.obsidian.waitFor(\n async () => {\n try {\n await access(resolvedPath);\n return true;\n } catch {\n return false;\n }\n },\n {\n message: `vault path \"${resolveVaultPath(scopeRoot, targetPath)}\" to exist`,\n ...waitOptions,\n },\n );\n },\n async waitForMissing(targetPath, waitOptions) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n\n await options.obsidian.waitFor(\n async () => {\n try {\n await access(resolvedPath);\n return false;\n } catch {\n return true;\n }\n },\n {\n message: `vault path \"${resolveVaultPath(scopeRoot, targetPath)}\" to be removed`,\n ...waitOptions,\n },\n );\n },\n async write(targetPath, content, writeOptions: VaultWriteOptions = {}) {\n const resolvedPath = await resolveFilesystemPath(options.obsidian, scopeRoot, targetPath);\n await mkdir(path.dirname(resolvedPath), { recursive: true });\n await writeFile(resolvedPath, content, \"utf8\");\n\n if (!writeOptions.waitForContent) {\n return;\n }\n\n const predicate =\n typeof writeOptions.waitForContent === \"function\"\n ? writeOptions.waitForContent\n : (value: string) => value === content;\n\n await this.waitForContent(targetPath, predicate, writeOptions.waitOptions);\n },\n };\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { ObsidianClient, PluginHandle } from \"../core/types\";\nimport { sanitizePathSegment } from \"../core/path-slug\";\nimport { parseNoteDocument } from \"../note/document\";\nimport { createVaultApi } from \"../vault/vault\";\n\nexport const DEFAULT_FAILURE_ARTIFACTS_DIR = \".obsidian-e2e-artifacts\";\n\nexport interface FailureArtifactOptions {\n activeFile?: boolean;\n activeNote?: boolean;\n consoleMessages?: boolean;\n dom?: boolean;\n editorText?: boolean;\n notices?: boolean;\n parsedFrontmatter?: boolean;\n runtimeErrors?: boolean;\n screenshot?: boolean;\n tabs?: boolean;\n workspace?: boolean;\n}\n\nexport interface FailureArtifactTask {\n id: string;\n name: string;\n}\n\nexport interface FailureArtifactConfig {\n artifactsDir: string;\n capture: Required<FailureArtifactOptions>;\n enabled: boolean;\n}\n\nexport interface FailureArtifactRegistrationOptions {\n artifactsDir?: string;\n captureOnFailure?: boolean | FailureArtifactOptions;\n}\n\nexport interface CaptureFailureArtifactsOptions extends FailureArtifactRegistrationOptions {\n plugin?: PluginHandle;\n}\n\nconst DEFAULT_FAILURE_ARTIFACT_CAPTURE: Required<FailureArtifactOptions> = {\n activeFile: true,\n activeNote: true,\n consoleMessages: true,\n dom: true,\n editorText: true,\n notices: true,\n parsedFrontmatter: true,\n runtimeErrors: true,\n screenshot: true,\n tabs: true,\n workspace: true,\n};\n\nexport function getFailureArtifactConfig(\n options: FailureArtifactRegistrationOptions,\n): FailureArtifactConfig {\n if (!options.captureOnFailure) {\n return {\n artifactsDir: path.resolve(options.artifactsDir ?? DEFAULT_FAILURE_ARTIFACTS_DIR),\n capture: { ...DEFAULT_FAILURE_ARTIFACT_CAPTURE },\n enabled: false,\n };\n }\n\n const overrides = options.captureOnFailure === true ? {} : options.captureOnFailure;\n\n return {\n artifactsDir: path.resolve(options.artifactsDir ?? DEFAULT_FAILURE_ARTIFACTS_DIR),\n capture: { ...DEFAULT_FAILURE_ARTIFACT_CAPTURE, ...overrides },\n enabled: true,\n };\n}\n\nexport function getFailureArtifactDirectory(\n artifactsDir: string,\n task: FailureArtifactTask,\n): string {\n const suffix = task.id.split(\"_\").at(-1) ?? \"test\";\n return path.join(artifactsDir, `${sanitizePathSegment(task.name, { maxLength: 60 })}-${suffix}`);\n}\n\nexport async function captureFailureArtifacts(\n task: FailureArtifactTask,\n obsidian: ObsidianClient,\n options: CaptureFailureArtifactsOptions,\n): Promise<string | undefined> {\n const config = getFailureArtifactConfig(options);\n\n if (!config.enabled) {\n return undefined;\n }\n\n const artifactDirectory = getFailureArtifactDirectory(config.artifactsDir, task);\n await mkdir(artifactDirectory, { recursive: true });\n const activeFile = readArtifactInput(() => readActiveFilePath(obsidian));\n const activeNote = readArtifactInput(async () => {\n const activeFilePath = await unwrapArtifactInput(activeFile);\n\n return activeFilePath ? readActiveNoteSnapshot(obsidian, activeFilePath) : null;\n });\n const diagnostics = await obsidian.dev.diagnostics().catch(() => null);\n\n await Promise.all([\n captureJsonArtifact(\n artifactDirectory,\n \"active-file.json\",\n config.capture.activeFile,\n async () => ({\n activeFile: await unwrapArtifactInput(activeFile),\n }),\n ),\n captureTextArtifact(\n artifactDirectory,\n \"active-note.md\",\n config.capture.activeNote,\n async () => (await unwrapArtifactInput(activeNote))?.raw ?? \"\",\n ),\n captureJsonArtifact(\n artifactDirectory,\n \"active-note-frontmatter.json\",\n config.capture.parsedFrontmatter,\n async () => ({\n frontmatter: (await unwrapArtifactInput(activeNote))?.frontmatter ?? null,\n }),\n ),\n captureTextArtifact(artifactDirectory, \"dom.txt\", config.capture.dom, async () =>\n String(\n await obsidian.dev.dom({\n inner: true,\n selector: \".workspace\",\n }),\n ),\n ),\n captureJsonArtifact(artifactDirectory, \"editor.json\", config.capture.editorText, async () => ({\n text: await obsidian.dev.editorText(),\n })),\n captureJsonArtifact(\n artifactDirectory,\n \"console-messages.json\",\n config.capture.consoleMessages,\n async () => diagnostics?.consoleMessages ?? [],\n ),\n captureJsonArtifact(\n artifactDirectory,\n \"runtime-errors.json\",\n config.capture.runtimeErrors,\n async () => diagnostics?.runtimeErrors ?? [],\n ),\n captureJsonArtifact(\n artifactDirectory,\n \"notices.json\",\n config.capture.notices,\n async () => diagnostics?.notices ?? [],\n ),\n captureScreenshotArtifact(artifactDirectory, config.capture.screenshot, obsidian),\n captureJsonArtifact(artifactDirectory, \"tabs.json\", config.capture.tabs, () => obsidian.tabs()),\n captureJsonArtifact(artifactDirectory, \"workspace.json\", config.capture.workspace, () =>\n obsidian.workspace(),\n ),\n options.plugin\n ? captureJsonArtifact(artifactDirectory, `${options.plugin.id}-data.json`, true, () =>\n options.plugin!.data().read(),\n )\n : Promise.resolve(),\n ]);\n\n return artifactDirectory;\n}\n\nexport async function capturePluginFailureArtifacts(\n task: FailureArtifactTask,\n plugin: PluginHandle,\n options: FailureArtifactRegistrationOptions,\n): Promise<string | undefined> {\n const config = getFailureArtifactConfig(options);\n\n if (!config.enabled) {\n return undefined;\n }\n\n const artifactDirectory = getFailureArtifactDirectory(config.artifactsDir, task);\n await mkdir(artifactDirectory, { recursive: true });\n await captureJsonArtifact(artifactDirectory, `${plugin.id}-data.json`, true, () =>\n plugin.data().read(),\n );\n\n return artifactDirectory;\n}\n\nasync function captureJsonArtifact(\n artifactDirectory: string,\n filename: string,\n enabled: boolean,\n readValue: () => Promise<unknown>,\n): Promise<void> {\n if (!enabled) {\n return;\n }\n\n try {\n const value = await readValue();\n await writeFile(\n path.join(artifactDirectory, filename),\n `${JSON.stringify(value, null, 2)}\\n`,\n \"utf8\",\n );\n } catch (error) {\n await writeFile(\n path.join(artifactDirectory, `${filename}.error.txt`),\n formatArtifactError(error),\n \"utf8\",\n );\n }\n}\n\nasync function captureScreenshotArtifact(\n artifactDirectory: string,\n enabled: boolean,\n obsidian: ObsidianClient,\n): Promise<void> {\n if (!enabled) {\n return;\n }\n\n const screenshotPath = path.join(artifactDirectory, \"screenshot.png\");\n\n try {\n await obsidian.dev.screenshot(screenshotPath);\n } catch (error) {\n await writeFile(\n path.join(artifactDirectory, \"screenshot.error.txt\"),\n formatArtifactError(error),\n \"utf8\",\n );\n }\n}\n\nasync function captureTextArtifact(\n artifactDirectory: string,\n filename: string,\n enabled: boolean,\n readValue: () => Promise<string>,\n): Promise<void> {\n if (!enabled) {\n return;\n }\n\n try {\n await writeFile(path.join(artifactDirectory, filename), await readValue(), \"utf8\");\n } catch (error) {\n await writeFile(\n path.join(artifactDirectory, `${filename}.error.txt`),\n formatArtifactError(error),\n \"utf8\",\n );\n }\n}\n\nfunction formatArtifactError(error: unknown): string {\n return error instanceof Error ? `${error.name}: ${error.message}\\n` : `${String(error)}\\n`;\n}\n\nasync function readActiveFilePath(obsidian: ObsidianClient): Promise<string | null> {\n return obsidian.dev.activeFilePath();\n}\n\nasync function readActiveNoteSnapshot(obsidian: ObsidianClient, activeFile: string) {\n const vault = createVaultApi({ obsidian });\n const raw = await vault.read(activeFile);\n\n return parseNoteDocument(raw);\n}\n\ninterface ArtifactInputResult<T> {\n promise: Promise<{ error: unknown; ok: false } | { ok: true; value: T }>;\n}\n\nfunction readArtifactInput<T>(readValue: () => Promise<T>): ArtifactInputResult<T> {\n return {\n promise: readValue().then(\n (value) => ({ ok: true, value }) as const,\n (error) => ({ error, ok: false }) as const,\n ),\n };\n}\n\nasync function unwrapArtifactInput<T>(result: ArtifactInputResult<T>): Promise<T> {\n const value = await result.promise;\n\n if (!value.ok) {\n throw value.error;\n }\n\n return value.value;\n}\n","import { posix as pathPosix } from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\n\nimport type {\n NoteDocument,\n NoteFrontmatter,\n ObsidianClient,\n SandboxApi,\n SandboxWriteNoteOptions,\n} from \"../core/types\";\nimport { sanitizePathSegment } from \"../core/path-slug\";\nimport { createNoteDocument, parseNoteDocument } from \"../note/document\";\nimport { createVaultApi } from \"./vault\";\n\ninterface CreateSandboxApiOptions {\n obsidian: ObsidianClient;\n sandboxRoot: string;\n testName: string;\n}\n\nexport async function createSandboxApi(options: CreateSandboxApiOptions): Promise<SandboxApi> {\n const root = pathPosix.join(\n options.sandboxRoot,\n `${sanitizePathSegment(options.testName)}-${randomUUID().slice(0, 8)}`,\n );\n const sandboxPath = (...segments: string[]) => pathPosix.join(root, ...segments);\n const vault = createVaultApi({\n obsidian: options.obsidian,\n root,\n });\n\n await vault.mkdir(\".\");\n\n return {\n ...vault,\n async cleanup() {\n await vault.delete(\".\", { permanent: true });\n },\n async frontmatter(targetPath) {\n return options.obsidian.metadata.frontmatter(sandboxPath(targetPath));\n },\n path(...segments: string[]) {\n return sandboxPath(...segments);\n },\n async readNote<TFrontmatter extends NoteFrontmatter | null = NoteFrontmatter | null>(\n targetPath: string,\n ): Promise<NoteDocument<TFrontmatter>> {\n return parseNoteDocument(await vault.read(targetPath)) as NoteDocument<TFrontmatter>;\n },\n root,\n async waitForFrontmatter(targetPath, predicate, waitOptions) {\n return options.obsidian.metadata.waitForFrontmatter(\n sandboxPath(targetPath),\n predicate,\n waitOptions,\n );\n },\n async waitForMetadata(targetPath, predicate, waitOptions) {\n return options.obsidian.metadata.waitForMetadata(\n sandboxPath(targetPath),\n predicate,\n waitOptions,\n );\n },\n async writeNote<TFrontmatter extends NoteFrontmatter | null = NoteFrontmatter | null>(\n writeOptions: SandboxWriteNoteOptions<TFrontmatter>,\n ): Promise<NoteDocument<TFrontmatter>> {\n const { path, waitForMetadata = true, waitOptions, ...noteInput } = writeOptions;\n const document = createNoteDocument(noteInput) as NoteDocument<TFrontmatter>;\n\n await vault.write(path, document.raw);\n\n if (waitForMetadata) {\n const predicate = typeof waitForMetadata === \"function\" ? waitForMetadata : undefined;\n await options.obsidian.metadata.waitForMetadata(sandboxPath(path), predicate, waitOptions);\n }\n\n return document;\n },\n };\n}\n","import { mkdir, readFile, rm, stat, writeFile } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { createHash, randomUUID } from \"node:crypto\";\n\nimport type { ObsidianClient } from \"../core/types\";\nimport type { SharedVaultLockOptions } from \"./types\";\n\nconst DEFAULT_HEARTBEAT_MS = 2_000;\nconst DEFAULT_STALE_MS = 15_000;\nconst DEFAULT_TIMEOUT_MS = 60_000;\nconst DEFAULT_WAIT_INTERVAL_MS = 500;\nconst DEFAULT_LOCK_ROOT = path.join(os.tmpdir(), \"obsidian-e2e-locks\");\nconst LOCK_METADATA_FILE = \"lock.json\";\nconst APP_LOCK_KEY = \"__obsidianE2ELock\";\nconst heldLocks = new Map<string, HeldVaultRunLock>();\n\nexport interface VaultRunLockMetadata {\n acquiredAt: number;\n cwd: string;\n heartbeatAt: number;\n hostname: string;\n ownerId: string;\n pid: number;\n staleMs: number;\n vaultName: string;\n vaultPath: string;\n}\n\nexport interface VaultRunLock {\n readonly lockDir: string;\n readonly metadata: VaultRunLockMetadata;\n\n publishMarker(obsidian: ObsidianClient): Promise<void>;\n release(): Promise<void>;\n}\n\nexport interface VaultRunLockState {\n heartbeatAgeMs: number;\n isStale: boolean;\n lockDir: string;\n metadata: VaultRunLockMetadata;\n}\n\nexport interface AcquireVaultRunLockOptions extends SharedVaultLockOptions {\n vaultName: string;\n vaultPath: string;\n}\n\ninterface HeldVaultRunLock {\n heartbeat: NodeJS.Timeout;\n lockDir: string;\n metadata: VaultRunLockMetadata;\n metadataPath: string;\n refs: number;\n}\n\nexport async function acquireVaultRunLock({\n heartbeatMs = DEFAULT_HEARTBEAT_MS,\n lockRoot = DEFAULT_LOCK_ROOT,\n onBusy = \"wait\",\n staleMs = DEFAULT_STALE_MS,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n vaultName,\n vaultPath,\n}: AcquireVaultRunLockOptions): Promise<VaultRunLock> {\n const lockDir = path.join(lockRoot, createVaultLockKey(vaultPath));\n const heldLock = heldLocks.get(lockDir);\n\n if (heldLock) {\n heldLock.refs += 1;\n return createVaultRunLockHandle(heldLock);\n }\n\n const ownerId = randomUUID();\n const metadataPath = path.join(lockDir, LOCK_METADATA_FILE);\n const metadata: VaultRunLockMetadata = {\n acquiredAt: Date.now(),\n cwd: process.cwd(),\n heartbeatAt: Date.now(),\n hostname: os.hostname(),\n ownerId,\n pid: process.pid,\n staleMs,\n vaultName,\n vaultPath,\n };\n\n await mkdir(lockRoot, { recursive: true });\n\n const startedAt = Date.now();\n\n while (true) {\n try {\n await mkdir(lockDir);\n await writeMetadata(metadataPath, metadata);\n break;\n } catch (error) {\n if (!isAlreadyExistsError(error)) {\n throw error;\n }\n\n const currentLock = await inspectVaultRunLock({\n lockRoot,\n staleMs,\n vaultPath,\n });\n\n if (currentLock && !currentLock.isStale) {\n if (onBusy === \"fail\") {\n throw new Error(formatBusyLockMessage(vaultPath, currentLock));\n }\n } else {\n await rm(lockDir, { force: true, recursive: true });\n continue;\n }\n\n if (Date.now() - startedAt >= timeoutMs) {\n throw new Error(\n currentLock\n ? `Timed out waiting for shared vault lock: ${formatBusyLockMessage(vaultPath, currentLock)}`\n : `Timed out waiting for shared vault lock on ${vaultPath}`,\n );\n }\n\n await sleep(Math.min(DEFAULT_WAIT_INTERVAL_MS, heartbeatMs));\n }\n }\n\n const heartbeat = setInterval(() => {\n metadata.heartbeatAt = Date.now();\n void writeMetadata(metadataPath, metadata).catch(() => {});\n }, heartbeatMs);\n heartbeat.unref();\n\n const nextHeldLock: HeldVaultRunLock = {\n heartbeat,\n lockDir,\n metadata,\n metadataPath,\n refs: 1,\n };\n\n heldLocks.set(lockDir, nextHeldLock);\n return createVaultRunLockHandle(nextHeldLock);\n}\n\nexport async function clearVaultRunLockMarker(obsidian: ObsidianClient): Promise<void> {\n await obsidian.dev.eval(`delete window.${APP_LOCK_KEY}; delete app.${APP_LOCK_KEY}; \"cleared\"`, {\n allowNonZeroExit: true,\n });\n}\n\nexport async function inspectVaultRunLock({\n lockRoot = DEFAULT_LOCK_ROOT,\n staleMs = DEFAULT_STALE_MS,\n vaultPath,\n}: Pick<\n AcquireVaultRunLockOptions,\n \"lockRoot\" | \"staleMs\" | \"vaultPath\"\n>): Promise<VaultRunLockState | null> {\n const lockDir = path.join(lockRoot, createVaultLockKey(vaultPath));\n const metadata = await readLockState(lockDir);\n\n if (!metadata) {\n return null;\n }\n\n return {\n heartbeatAgeMs: Date.now() - metadata.heartbeatAt,\n isStale: isLockStale(metadata, staleMs),\n lockDir,\n metadata,\n };\n}\n\nexport async function readVaultRunLockMarker(\n obsidian: ObsidianClient,\n): Promise<VaultRunLockMetadata | null> {\n return obsidian.dev.eval<VaultRunLockMetadata | null>(\n `window.${APP_LOCK_KEY} ?? app.${APP_LOCK_KEY} ?? null`,\n { allowNonZeroExit: true },\n );\n}\n\nfunction createVaultLockKey(vaultPath: string): string {\n return createHash(\"sha256\").update(path.resolve(vaultPath)).digest(\"hex\");\n}\n\nfunction buildSetMarkerCode(metadata: VaultRunLockMetadata): string {\n const encodedMetadata = JSON.stringify(metadata);\n return `(() => {\n const lock = ${encodedMetadata};\n window.${APP_LOCK_KEY} = lock;\n app.${APP_LOCK_KEY} = lock;\n return lock;\n })()`;\n}\n\nfunction createVaultRunLockHandle(heldLock: HeldVaultRunLock): VaultRunLock {\n return {\n get lockDir() {\n return heldLock.lockDir;\n },\n get metadata() {\n return heldLock.metadata;\n },\n async publishMarker(obsidian: ObsidianClient) {\n await obsidian.dev.eval(buildSetMarkerCode(heldLock.metadata));\n },\n async release() {\n if (heldLock.refs > 1) {\n heldLock.refs -= 1;\n return;\n }\n\n heldLocks.delete(heldLock.lockDir);\n clearInterval(heldLock.heartbeat);\n\n const currentLock = await readLockState(heldLock.lockDir);\n\n if (currentLock?.ownerId !== heldLock.metadata.ownerId) {\n return;\n }\n\n await rm(heldLock.lockDir, { force: true, recursive: true });\n },\n };\n}\n\nasync function readLockState(lockDir: string): Promise<VaultRunLockMetadata | null> {\n const metadataPath = path.join(lockDir, LOCK_METADATA_FILE);\n\n try {\n return JSON.parse(await readFile(metadataPath, \"utf8\")) as VaultRunLockMetadata;\n } catch {\n try {\n const directoryStat = await stat(lockDir);\n return {\n acquiredAt: directoryStat.mtimeMs,\n cwd: \"\",\n heartbeatAt: directoryStat.mtimeMs,\n hostname: \"\",\n ownerId: \"\",\n pid: 0,\n staleMs: DEFAULT_STALE_MS,\n vaultName: \"\",\n vaultPath: \"\",\n };\n } catch {\n return null;\n }\n }\n}\n\nfunction formatBusyLockMessage(vaultPath: string, state: VaultRunLockState): string {\n const ownerDetails = state.metadata.ownerId\n ? `owner=${state.metadata.ownerId} pid=${state.metadata.pid} cwd=${state.metadata.cwd || \"<unknown>\"}`\n : \"owner=<unknown>\";\n const ageDetails = `heartbeatAgeMs=${state.heartbeatAgeMs} stale=${state.isStale}`;\n\n return `vault ${vaultPath} is locked by ${ownerDetails} ${ageDetails}`;\n}\n\nfunction isAlreadyExistsError(error: unknown): boolean {\n return error instanceof Error && \"code\" in error && error.code === \"EEXIST\";\n}\n\nfunction isLockStale(metadata: VaultRunLockMetadata, staleMs: number): boolean {\n return Date.now() - metadata.heartbeatAt > staleMs;\n}\n\nasync function sleep(durationMs: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, durationMs));\n}\n\nasync function writeMetadata(metadataPath: string, metadata: VaultRunLockMetadata): Promise<void> {\n await writeFile(metadataPath, `${JSON.stringify(metadata, null, 2)}\\n`, \"utf8\");\n}\n","import type { TestContext } from \"vite-plus/test\";\n\nimport { createObsidianClient } from \"../core/client\";\nimport type { ObsidianClient, VaultApi } from \"../core/types\";\nimport { createVaultApi } from \"../vault/vault\";\nimport { createInternalTestContext } from \"./test-context\";\nimport type { CreateObsidianTestOptions, TestContext as ObsidianTestContext } from \"./types\";\nimport { acquireVaultRunLock, clearVaultRunLockMarker, type VaultRunLock } from \"./vault-lock\";\n\nexport const DEFAULT_SANDBOX_ROOT = \"__obsidian_e2e__\";\n\nexport interface BaseFixtureState {\n _testContext: ObsidianTestContext;\n _vaultLock: VaultRunLock | null;\n}\n\ninterface BaseFixtureOptions {\n createVault?: (obsidian: ObsidianClient) => Promise<VaultApi> | VaultApi;\n}\n\nexport function createBaseFixtures(\n options: CreateObsidianTestOptions,\n fixtureOptions: BaseFixtureOptions = {},\n) {\n const createVault =\n fixtureOptions.createVault ?? ((obsidian: ObsidianClient) => createVaultApi({ obsidian }));\n\n return {\n _vaultLock: [\n // eslint-disable-next-line no-empty-pattern\n async ({}, use: (vaultLock: VaultRunLock | null) => Promise<void>) => {\n if (!options.sharedVaultLock) {\n await use(null);\n return;\n }\n\n const lockClient = createObsidianClient(options);\n await lockClient.verify();\n\n const lockOptions = options.sharedVaultLock === true ? {} : options.sharedVaultLock;\n const vaultLock = await acquireVaultRunLock({\n ...lockOptions,\n vaultName: options.vault,\n vaultPath: await lockClient.vaultPath(),\n });\n\n await vaultLock.publishMarker(lockClient);\n try {\n await use(vaultLock);\n } finally {\n try {\n await clearVaultRunLockMarker(lockClient);\n } catch {}\n\n await vaultLock.release();\n }\n },\n { scope: \"worker\" },\n ],\n _testContext: async (\n {\n _vaultLock,\n onTestFailed,\n task,\n }: Pick<BaseFixtureState & TestContext, \"_vaultLock\" | \"onTestFailed\" | \"task\">,\n use: (context: ObsidianTestContext) => Promise<void>,\n ) => {\n let failedTask = false;\n onTestFailed(() => {\n failedTask = true;\n });\n\n const context = await createInternalTestContext({\n ...options,\n createVault,\n testName: task.name,\n vaultLock: _vaultLock,\n });\n\n try {\n await use(context);\n } finally {\n await context.cleanup({\n failedTask: failedTask ? task : undefined,\n });\n }\n },\n // oxlint-disable-next-line no-empty-pattern\n obsidian: async (\n { _testContext }: Pick<BaseFixtureState, \"_testContext\">,\n use: (obsidian: ObsidianClient) => Promise<void>,\n ) => {\n await use(_testContext.obsidian);\n },\n sandbox: async (\n { _testContext }: Pick<BaseFixtureState, \"_testContext\">,\n use: (sandbox: ObsidianTestContext[\"sandbox\"]) => Promise<void>,\n ) => {\n await use(_testContext.sandbox);\n },\n vault: async (\n { _testContext }: Pick<BaseFixtureState, \"_testContext\">,\n use: (vault: VaultApi) => Promise<void>,\n ) => {\n await use(_testContext.vault);\n },\n };\n}\n","import { createObsidianClient } from \"../core/client\";\nimport { getClientInternals } from \"../core/internals\";\nimport type { FailureArtifactTask } from \"../artifacts/failure-artifacts\";\nimport { captureFailureArtifacts } from \"../artifacts/failure-artifacts\";\nimport type { ObsidianClient, PluginHandle, VaultApi } from \"../core/types\";\nimport { createSandboxApi } from \"../vault/sandbox\";\nimport { createVaultApi } from \"../vault/vault\";\nimport { DEFAULT_SANDBOX_ROOT } from \"./base-fixtures\";\nimport { acquireVaultRunLock, clearVaultRunLockMarker, type VaultRunLock } from \"./vault-lock\";\nimport type { CreateObsidianTestOptions, PluginSessionOptions, TestContext } from \"./types\";\n\ninterface CreateInternalTestContextOptions extends CreateObsidianTestOptions {\n createVault?: (obsidian: ObsidianClient) => Promise<VaultApi> | VaultApi;\n testName?: string;\n vaultLock?: VaultRunLock | null;\n}\n\ninterface TrackedPluginSession {\n filter?: PluginSessionOptions[\"filter\"];\n plugin: PluginHandle;\n wasEnabled: boolean;\n}\n\nexport async function createTestContext(\n options: CreateObsidianTestOptions & { testName?: string },\n): Promise<TestContext> {\n return createInternalTestContext(options);\n}\n\nexport async function withVaultSandbox<TResult>(\n options: CreateObsidianTestOptions & { testName?: string },\n run: (context: TestContext) => Promise<TResult> | TResult,\n): Promise<TResult> {\n const context = await createInternalTestContext(options);\n\n try {\n return await run(context);\n } finally {\n await context.cleanup();\n }\n}\n\nexport async function createInternalTestContext(\n options: CreateInternalTestContextOptions,\n): Promise<TestContext> {\n const obsidian = createObsidianClient(options);\n const trackedPlugins = new Map<string, TrackedPluginSession>();\n let sandbox: Awaited<ReturnType<typeof createSandboxApi>> | null = null;\n const vaultLock = options.vaultLock ?? (await maybeAcquireVaultLock(options, obsidian));\n const ownsVaultLock = options.vaultLock === undefined && vaultLock !== null;\n const vaultFactory =\n options.createVault ?? ((client: ObsidianClient) => createVaultApi({ obsidian: client }));\n let disposed = false;\n\n try {\n await obsidian.verify();\n\n if (vaultLock) {\n await vaultLock.publishMarker(obsidian);\n }\n\n await obsidian.dev.resetDiagnostics().catch(() => {});\n\n const vault = await vaultFactory(obsidian);\n sandbox = await createSandboxApi({\n obsidian,\n sandboxRoot: options.sandboxRoot ?? DEFAULT_SANDBOX_ROOT,\n testName: options.testName ?? \"test\",\n });\n\n const captureArtifacts = async (task: FailureArtifactTask) =>\n captureFailureArtifacts(task, obsidian, {\n ...options,\n plugin: trackedPlugins.size === 1 ? [...trackedPlugins.values()][0]!.plugin : undefined,\n });\n\n const cleanup: TestContext[\"cleanup\"] = async (cleanupOptions = {}) => {\n if (disposed) {\n return;\n }\n\n disposed = true;\n const cleanupErrors: unknown[] = [];\n\n try {\n if (cleanupOptions.failedTask && options.captureOnFailure) {\n await captureArtifacts(cleanupOptions.failedTask);\n }\n } finally {\n try {\n await getClientInternals(obsidian).restoreAll();\n } finally {\n for (const session of [...trackedPlugins.values()].reverse()) {\n if (!session.wasEnabled) {\n await recordCleanupError(cleanupErrors, async () =>\n session.plugin.disable({ filter: session.filter }),\n );\n }\n }\n\n try {\n await clearVaultRunLockMarker(obsidian);\n } catch {}\n\n if (ownsVaultLock) {\n await recordCleanupError(cleanupErrors, async () => vaultLock.release());\n }\n\n await recordCleanupError(cleanupErrors, async () => sandbox!.cleanup());\n }\n }\n\n if (cleanupErrors.length === 1) {\n throw cleanupErrors[0];\n }\n\n if (cleanupErrors.length > 1) {\n throw new AggregateError(cleanupErrors, \"One or more test cleanup steps failed.\");\n }\n };\n\n return {\n obsidian,\n sandbox: sandbox!,\n vault,\n captureFailureArtifacts: captureArtifacts,\n cleanup,\n async plugin(id: string, sessionOptions: PluginSessionOptions = {}) {\n const existing = trackedPlugins.get(id);\n\n if (existing) {\n return existing.plugin;\n }\n\n const plugin = obsidian.plugin(id);\n const wasEnabled = await plugin.isEnabled();\n\n if (!wasEnabled) {\n await plugin.enable({ filter: sessionOptions.filter });\n }\n\n if (sessionOptions.seedData !== undefined) {\n await plugin.data().write(sessionOptions.seedData);\n }\n\n trackedPlugins.set(id, {\n filter: sessionOptions.filter,\n plugin,\n wasEnabled,\n });\n\n return plugin;\n },\n async resetDiagnostics() {\n await obsidian.dev.resetDiagnostics().catch(() => {});\n },\n };\n } catch (error) {\n try {\n if (sandbox) {\n await sandbox.cleanup();\n }\n } finally {\n try {\n await clearVaultRunLockMarker(obsidian);\n } catch {}\n\n if (ownsVaultLock) {\n await vaultLock.release();\n }\n }\n\n throw error;\n }\n}\n\nasync function recordCleanupError(\n cleanupErrors: unknown[],\n run: () => Promise<void>,\n): Promise<void> {\n try {\n await run();\n } catch (error) {\n cleanupErrors.push(error);\n }\n}\n\nasync function maybeAcquireVaultLock(\n options: CreateObsidianTestOptions,\n obsidian: ObsidianClient,\n): Promise<VaultRunLock | null> {\n if (!options.sharedVaultLock) {\n return null;\n }\n\n const lockOptions = options.sharedVaultLock === true ? {} : options.sharedVaultLock;\n\n return acquireVaultRunLock({\n ...lockOptions,\n vaultName: options.vault,\n vaultPath: await obsidian.vaultPath(),\n });\n}\n"],"mappings":"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"}
|