feat: add Obsidian CLI API service
Build and Push Docker Container / build-and-push (push) Successful in 4m26s
Build and Push Docker Container / build-and-push (push) Successful in 4m26s
- Add Docker image for the official Obsidian desktop app and CLI. - Start Obsidian headlessly with Xvfb and DBus setup. - Expose a safe structured HTTP command API without shell execution. - Add JWT-based vault, path, and command authorization. - Support single-vault and multi-vault container mounts. - Add TypeScript SDK helpers for Obsidian CLI commands. - Add n8n community node package with Obsidian operations. - Add docs, compose config, tests, and production image workflow.
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
# @obsidian-api/sdk
|
||||
TypeScript SDK for this HTTP wrapper around the **official Obsidian CLI**.
|
||||
|
||||
The SDK is built for Node 18+, n8n Code nodes, Prism, and other TypeScript agent harnesses.
|
||||
|
||||
## Install locally
|
||||
```bash
|
||||
npm install /path/to/obsidian-api/sdk/typescript
|
||||
```
|
||||
|
||||
## Usage
|
||||
```ts
|
||||
import { ObsidianCliClient } from '@obsidian-api/sdk';
|
||||
|
||||
const obsidian = new ObsidianCliClient({
|
||||
baseUrl: 'http://localhost:8080',
|
||||
token: 'change-me',
|
||||
});
|
||||
|
||||
await obsidian.create({
|
||||
path: 'Inbox/Hello.md',
|
||||
content: '# Hello from n8n/Prism',
|
||||
overwrite: true,
|
||||
});
|
||||
|
||||
const note = await obsidian.read({ path: 'Inbox/Hello.md' });
|
||||
console.log(note.stdout);
|
||||
|
||||
const results = await obsidian.search('Hello', { format: 'json' });
|
||||
console.log(JSON.parse(results.stdout));
|
||||
```
|
||||
|
||||
## Multiple vaults
|
||||
Use the official CLI `vault=<name>` prefix directly:
|
||||
```ts
|
||||
await obsidian.runInVault('work', 'create', 'path=Inbox/Task.md', 'content=Hello');
|
||||
```
|
||||
|
||||
Or create a scoped client:
|
||||
```ts
|
||||
const workVault = obsidian.inVault('work');
|
||||
await workVault.create({ path: 'Inbox/Task.md', content: 'Hello', overwrite: true });
|
||||
await workVault.read({ path: 'Inbox/Task.md' });
|
||||
```
|
||||
|
||||
You can also set a default vault in the constructor:
|
||||
```ts
|
||||
const obsidian = new ObsidianCliClient({
|
||||
baseUrl: 'http://localhost:8080',
|
||||
token: 'change-me',
|
||||
vault: 'work',
|
||||
});
|
||||
```
|
||||
|
||||
## Raw command escape hatch
|
||||
Still safe: sends an args array, not a shell command string.
|
||||
```ts
|
||||
await obsidian.runRaw('create', 'name=Scratch', 'content=Test', 'overwrite');
|
||||
```
|
||||
Generated
+33
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "@obsidian-api/sdk",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@obsidian-api/sdk",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"typescript": "^5.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@obsidian-api/sdk",
|
||||
"version": "1.0.0",
|
||||
"description": "TypeScript SDK for the official Obsidian CLI HTTP wrapper. Built for n8n, Prism, and other TS/Node agent harnesses.",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"files": ["dist", "src"],
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"typecheck": "tsc -p tsconfig.json --noEmit",
|
||||
"test": "node --test"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"typescript": "^5.9.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
export type OutputFormat = "json" | "tsv" | "csv" | "text" | "yaml" | "md" | "paths" | "tree";
|
||||
export type PaneType = "tab" | "split" | "window";
|
||||
export type PluginFilter = "core" | "community";
|
||||
export type PropertyType = "text" | "list" | "number" | "checkbox" | "date" | "datetime";
|
||||
export type HistoryFilter = "local" | "sync";
|
||||
export type LogLevel = "log" | "warn" | "error" | "info" | "debug";
|
||||
|
||||
export interface CommandResult {
|
||||
id: string;
|
||||
command: string[];
|
||||
cwd: string;
|
||||
exit_code: number;
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
duration_ms: number;
|
||||
timed_out: boolean;
|
||||
}
|
||||
|
||||
export class ObsidianApiError extends Error {
|
||||
constructor(public statusCode: number, public detail: string) {
|
||||
super(`HTTP ${statusCode}: ${detail}`);
|
||||
this.name = "ObsidianApiError";
|
||||
}
|
||||
}
|
||||
|
||||
export interface ObsidianCliClientOptions {
|
||||
baseUrl: string;
|
||||
token?: string;
|
||||
timeoutMs?: number;
|
||||
/** Optional default vault name/path. Sent as the official CLI `vault=<name>` prefix. */
|
||||
vault?: string;
|
||||
}
|
||||
|
||||
type ParamValue = string | number | boolean | undefined | null;
|
||||
|
||||
function kv(name: string, value: ParamValue): string | undefined {
|
||||
if (value === undefined || value === null) return undefined;
|
||||
if (typeof value === "boolean") return value ? name : undefined;
|
||||
return `${name}=${value}`;
|
||||
}
|
||||
|
||||
function args(...items: Array<string | undefined>): string[] {
|
||||
return items.filter((item): item is string => item !== undefined);
|
||||
}
|
||||
|
||||
export class ObsidianCliClient {
|
||||
readonly baseUrl: string;
|
||||
readonly token?: string;
|
||||
readonly timeoutMs: number;
|
||||
readonly defaultVault?: string;
|
||||
|
||||
constructor(options: ObsidianCliClientOptions) {
|
||||
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
||||
this.token = options.token;
|
||||
this.timeoutMs = options.timeoutMs ?? 60_000;
|
||||
this.defaultVault = options.vault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a scoped client that automatically prefixes every command with
|
||||
* `vault=<name>`, matching the official Obsidian CLI multi-vault syntax.
|
||||
*/
|
||||
inVault(vault: string): ObsidianCliClient {
|
||||
return new ObsidianCliClient({
|
||||
baseUrl: this.baseUrl,
|
||||
token: this.token,
|
||||
timeoutMs: this.timeoutMs,
|
||||
vault,
|
||||
});
|
||||
}
|
||||
|
||||
async run(commandArgs: string[], options: { stdin?: string; timeoutMs?: number } = {}): Promise<CommandResult> {
|
||||
const timeoutMs = options.timeoutMs ?? this.timeoutMs;
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), timeoutMs + 5_000);
|
||||
|
||||
try {
|
||||
const response = await fetch(`${this.baseUrl}/commands`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
...(this.token ? { authorization: `Bearer ${this.token}` } : {}),
|
||||
},
|
||||
body: JSON.stringify({
|
||||
args: this.defaultVault && !commandArgs[0]?.startsWith("vault=") ? [`vault=${this.defaultVault}`, ...commandArgs] : commandArgs,
|
||||
stdin: options.stdin,
|
||||
timeout: Math.ceil(timeoutMs / 1000),
|
||||
}),
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
const data = await response.json() as CommandResult | { detail?: string };
|
||||
if (!response.ok) {
|
||||
throw new ObsidianApiError(response.status, "detail" in data && data.detail ? data.detail : response.statusText);
|
||||
}
|
||||
return data as CommandResult;
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
|
||||
async runRaw(...commandArgs: string[]): Promise<CommandResult> {
|
||||
return this.run(commandArgs);
|
||||
}
|
||||
|
||||
async runInVault(vault: string, command: string, ...commandArgs: string[]): Promise<CommandResult> {
|
||||
return this.run([`vault=${vault}`, command, ...commandArgs]);
|
||||
}
|
||||
|
||||
// General
|
||||
help = (command?: string) => this.run(args("help", command));
|
||||
version = () => this.run(["version"]);
|
||||
reload = () => this.run(["reload"]);
|
||||
restart = () => this.run(["restart"]);
|
||||
|
||||
// Bases
|
||||
bases = () => this.run(["bases"]);
|
||||
baseViews = () => this.run(["base:views"]);
|
||||
baseCreate = (o: { file?: string; path?: string; view?: string; name?: string; content?: string; open?: boolean; newtab?: boolean } = {}) =>
|
||||
this.run(args("base:create", kv("file", o.file), kv("path", o.path), kv("view", o.view), kv("name", o.name), kv("content", o.content), kv("open", o.open), kv("newtab", o.newtab)));
|
||||
baseQuery = (o: { file?: string; path?: string; view?: string; format?: "json" | "csv" | "tsv" | "md" | "paths" } = {}) =>
|
||||
this.run(args("base:query", kv("file", o.file), kv("path", o.path), kv("view", o.view), kv("format", o.format)));
|
||||
|
||||
// Bookmarks / command palette / hotkeys
|
||||
bookmarks = (o: { total?: boolean; verbose?: boolean; format?: "json" | "tsv" | "csv" } = {}) => this.run(args("bookmarks", kv("total", o.total), kv("verbose", o.verbose), kv("format", o.format)));
|
||||
bookmark = (o: { file?: string; subpath?: string; folder?: string; search?: string; url?: string; title?: string }) => this.run(args("bookmark", kv("file", o.file), kv("subpath", o.subpath), kv("folder", o.folder), kv("search", o.search), kv("url", o.url), kv("title", o.title)));
|
||||
commands = (o: { filter?: string } = {}) => this.run(args("commands", kv("filter", o.filter)));
|
||||
command = (id: string) => this.run(["command", kv("id", id)!]);
|
||||
hotkeys = (o: { total?: boolean; verbose?: boolean; format?: "json" | "tsv" | "csv" } = {}) => this.run(args("hotkeys", kv("total", o.total), kv("verbose", o.verbose), kv("format", o.format)));
|
||||
hotkey = (id: string, o: { verbose?: boolean } = {}) => this.run(args("hotkey", kv("id", id), kv("verbose", o.verbose)));
|
||||
|
||||
// Daily notes
|
||||
daily = (o: { paneType?: PaneType } = {}) => this.run(args("daily", kv("paneType", o.paneType)));
|
||||
dailyPath = () => this.run(["daily:path"]);
|
||||
dailyRead = () => this.run(["daily:read"]);
|
||||
dailyAppend = (content: string, o: { paneType?: PaneType; inline?: boolean; open?: boolean } = {}) => this.run(args("daily:append", kv("content", content), kv("paneType", o.paneType), kv("inline", o.inline), kv("open", o.open)));
|
||||
dailyPrepend = (content: string, o: { paneType?: PaneType; inline?: boolean; open?: boolean } = {}) => this.run(args("daily:prepend", kv("content", content), kv("paneType", o.paneType), kv("inline", o.inline), kv("open", o.open)));
|
||||
|
||||
// File history
|
||||
diff = (o: { file?: string; path?: string; from?: number; to?: number; filter?: HistoryFilter } = {}) => this.run(args("diff", kv("file", o.file), kv("path", o.path), kv("from", o.from), kv("to", o.to), kv("filter", o.filter)));
|
||||
history = (o: { file?: string; path?: string } = {}) => this.run(args("history", kv("file", o.file), kv("path", o.path)));
|
||||
historyList = () => this.run(["history:list"]);
|
||||
historyRead = (o: { file?: string; path?: string; version?: number } = {}) => this.run(args("history:read", kv("file", o.file), kv("path", o.path), kv("version", o.version)));
|
||||
historyRestore = (version: number, o: { file?: string; path?: string } = {}) => this.run(args("history:restore", kv("file", o.file), kv("path", o.path), kv("version", version)));
|
||||
historyOpen = (o: { file?: string; path?: string } = {}) => this.run(args("history:open", kv("file", o.file), kv("path", o.path)));
|
||||
|
||||
// Files and folders
|
||||
file = (o: { file?: string; path?: string } = {}) => this.run(args("file", kv("file", o.file), kv("path", o.path)));
|
||||
files = (o: { folder?: string; ext?: string; total?: boolean } = {}) => this.run(args("files", kv("folder", o.folder), kv("ext", o.ext), kv("total", o.total)));
|
||||
folder = (path: string, o: { info?: "files" | "folders" | "size" } = {}) => this.run(args("folder", kv("path", path), kv("info", o.info)));
|
||||
folders = (o: { folder?: string; total?: boolean } = {}) => this.run(args("folders", kv("folder", o.folder), kv("total", o.total)));
|
||||
open = (o: { file?: string; path?: string; newtab?: boolean } = {}) => this.run(args("open", kv("file", o.file), kv("path", o.path), kv("newtab", o.newtab)));
|
||||
create = (o: { name?: string; path?: string; content?: string; template?: string; overwrite?: boolean; open?: boolean; newtab?: boolean } = {}) => this.run(args("create", kv("name", o.name), kv("path", o.path), kv("content", o.content), kv("template", o.template), kv("overwrite", o.overwrite), kv("open", o.open), kv("newtab", o.newtab)));
|
||||
read = (o: { file?: string; path?: string } = {}) => this.run(args("read", kv("file", o.file), kv("path", o.path)));
|
||||
append = (content: string, o: { file?: string; path?: string; inline?: boolean } = {}) => this.run(args("append", kv("file", o.file), kv("path", o.path), kv("content", content), kv("inline", o.inline)));
|
||||
prepend = (content: string, o: { file?: string; path?: string; inline?: boolean } = {}) => this.run(args("prepend", kv("file", o.file), kv("path", o.path), kv("content", content), kv("inline", o.inline)));
|
||||
move = (to: string, o: { file?: string; path?: string } = {}) => this.run(args("move", kv("file", o.file), kv("path", o.path), kv("to", to)));
|
||||
rename = (name: string, o: { file?: string; path?: string } = {}) => this.run(args("rename", kv("file", o.file), kv("path", o.path), kv("name", name)));
|
||||
delete = (o: { file?: string; path?: string; permanent?: boolean } = {}) => this.run(args("delete", kv("file", o.file), kv("path", o.path), kv("permanent", o.permanent)));
|
||||
|
||||
// Links / outline
|
||||
backlinks = (o: { file?: string; path?: string; counts?: boolean; total?: boolean; format?: "json" | "tsv" | "csv" } = {}) => this.run(args("backlinks", kv("file", o.file), kv("path", o.path), kv("counts", o.counts), kv("total", o.total), kv("format", o.format)));
|
||||
links = (o: { file?: string; path?: string; total?: boolean } = {}) => this.run(args("links", kv("file", o.file), kv("path", o.path), kv("total", o.total)));
|
||||
unresolved = (o: { total?: boolean; counts?: boolean; verbose?: boolean; format?: "json" | "tsv" | "csv" } = {}) => this.run(args("unresolved", kv("total", o.total), kv("counts", o.counts), kv("verbose", o.verbose), kv("format", o.format)));
|
||||
orphans = (o: { total?: boolean } = {}) => this.run(args("orphans", kv("total", o.total)));
|
||||
deadends = (o: { total?: boolean } = {}) => this.run(args("deadends", kv("total", o.total)));
|
||||
outline = (o: { file?: string; path?: string; format?: "tree" | "md" | "json"; total?: boolean } = {}) => this.run(args("outline", kv("file", o.file), kv("path", o.path), kv("format", o.format), kv("total", o.total)));
|
||||
|
||||
// Plugins
|
||||
plugins = (o: { filter?: PluginFilter; versions?: boolean; format?: "json" | "tsv" | "csv" } = {}) => this.run(args("plugins", kv("filter", o.filter), kv("versions", o.versions), kv("format", o.format)));
|
||||
pluginsEnabled = (o: { filter?: PluginFilter; versions?: boolean; format?: "json" | "tsv" | "csv" } = {}) => this.run(args("plugins:enabled", kv("filter", o.filter), kv("versions", o.versions), kv("format", o.format)));
|
||||
pluginsRestrict = (o: { on?: boolean; off?: boolean } = {}) => this.run(args("plugins:restrict", kv("on", o.on), kv("off", o.off)));
|
||||
plugin = (id: string) => this.run(["plugin", kv("id", id)!]);
|
||||
pluginEnable = (id: string, o: { filter?: PluginFilter } = {}) => this.run(args("plugin:enable", kv("id", id), kv("filter", o.filter)));
|
||||
pluginDisable = (id: string, o: { filter?: PluginFilter } = {}) => this.run(args("plugin:disable", kv("id", id), kv("filter", o.filter)));
|
||||
pluginInstall = (id: string, o: { enable?: boolean } = {}) => this.run(args("plugin:install", kv("id", id), kv("enable", o.enable)));
|
||||
pluginUninstall = (id: string) => this.run(["plugin:uninstall", kv("id", id)!]);
|
||||
pluginReload = (id: string) => this.run(["plugin:reload", kv("id", id)!]);
|
||||
|
||||
// Properties
|
||||
aliases = (o: { file?: string; path?: string; total?: boolean; verbose?: boolean; active?: boolean } = {}) => this.run(args("aliases", kv("file", o.file), kv("path", o.path), kv("total", o.total), kv("verbose", o.verbose), kv("active", o.active)));
|
||||
properties = (o: { file?: string; path?: string; name?: string; sort?: "count"; format?: "yaml" | "json" | "tsv"; total?: boolean; counts?: boolean; active?: boolean } = {}) => this.run(args("properties", kv("file", o.file), kv("path", o.path), kv("name", o.name), kv("sort", o.sort), kv("format", o.format), kv("total", o.total), kv("counts", o.counts), kv("active", o.active)));
|
||||
propertySet = (name: string, value: string, o: { type?: PropertyType; file?: string; path?: string } = {}) => this.run(args("property:set", kv("name", name), kv("value", value), kv("type", o.type), kv("file", o.file), kv("path", o.path)));
|
||||
propertyRemove = (name: string, o: { file?: string; path?: string } = {}) => this.run(args("property:remove", kv("name", name), kv("file", o.file), kv("path", o.path)));
|
||||
propertyRead = (name: string, o: { file?: string; path?: string } = {}) => this.run(args("property:read", kv("name", name), kv("file", o.file), kv("path", o.path)));
|
||||
|
||||
// Publish
|
||||
publishSite = () => this.run(["publish:site"]);
|
||||
publishList = (o: { total?: boolean } = {}) => this.run(args("publish:list", kv("total", o.total)));
|
||||
publishStatus = (o: { total?: boolean; new?: boolean; changed?: boolean; deleted?: boolean } = {}) => this.run(args("publish:status", kv("total", o.total), kv("new", o.new), kv("changed", o.changed), kv("deleted", o.deleted)));
|
||||
publishAdd = (o: { file?: string; path?: string; changed?: boolean } = {}) => this.run(args("publish:add", kv("file", o.file), kv("path", o.path), kv("changed", o.changed)));
|
||||
publishRemove = (o: { file?: string; path?: string } = {}) => this.run(args("publish:remove", kv("file", o.file), kv("path", o.path)));
|
||||
publishOpen = (o: { file?: string; path?: string } = {}) => this.run(args("publish:open", kv("file", o.file), kv("path", o.path)));
|
||||
|
||||
// Random / search
|
||||
random = (o: { folder?: string; newtab?: boolean } = {}) => this.run(args("random", kv("folder", o.folder), kv("newtab", o.newtab)));
|
||||
randomRead = (o: { folder?: string } = {}) => this.run(args("random:read", kv("folder", o.folder)));
|
||||
search = (query: string, o: { path?: string; limit?: number; format?: "text" | "json"; total?: boolean; case?: boolean } = {}) => this.run(args("search", kv("query", query), kv("path", o.path), kv("limit", o.limit), kv("format", o.format), kv("total", o.total), kv("case", o.case)));
|
||||
searchContext = (query: string, o: { path?: string; limit?: number; format?: "text" | "json"; case?: boolean } = {}) => this.run(args("search:context", kv("query", query), kv("path", o.path), kv("limit", o.limit), kv("format", o.format), kv("case", o.case)));
|
||||
searchOpen = (o: { query?: string } = {}) => this.run(args("search:open", kv("query", o.query)));
|
||||
|
||||
// Sync
|
||||
sync = (o: { on?: boolean; off?: boolean } = {}) => this.run(args("sync", kv("on", o.on), kv("off", o.off)));
|
||||
syncStatus = () => this.run(["sync:status"]);
|
||||
syncHistory = (o: { file?: string; path?: string; total?: boolean } = {}) => this.run(args("sync:history", kv("file", o.file), kv("path", o.path), kv("total", o.total)));
|
||||
syncRead = (version: number, o: { file?: string; path?: string } = {}) => this.run(args("sync:read", kv("file", o.file), kv("path", o.path), kv("version", version)));
|
||||
syncRestore = (version: number, o: { file?: string; path?: string } = {}) => this.run(args("sync:restore", kv("file", o.file), kv("path", o.path), kv("version", version)));
|
||||
syncOpen = (o: { file?: string; path?: string } = {}) => this.run(args("sync:open", kv("file", o.file), kv("path", o.path)));
|
||||
syncDeleted = (o: { total?: boolean } = {}) => this.run(args("sync:deleted", kv("total", o.total)));
|
||||
|
||||
// Tags / tasks
|
||||
tags = (o: { file?: string; path?: string; sort?: "count"; total?: boolean; counts?: boolean; format?: "json" | "tsv" | "csv"; active?: boolean } = {}) => this.run(args("tags", kv("file", o.file), kv("path", o.path), kv("sort", o.sort), kv("total", o.total), kv("counts", o.counts), kv("format", o.format), kv("active", o.active)));
|
||||
tag = (name: string, o: { total?: boolean; verbose?: boolean } = {}) => this.run(args("tag", kv("name", name), kv("total", o.total), kv("verbose", o.verbose)));
|
||||
tasks = (o: { file?: string; path?: string; status?: string; total?: boolean; done?: boolean; todo?: boolean; verbose?: boolean; format?: "json" | "tsv" | "csv"; active?: boolean; daily?: boolean } = {}) => this.run(args("tasks", kv("file", o.file), kv("path", o.path), kv("status", o.status), kv("total", o.total), kv("done", o.done), kv("todo", o.todo), kv("verbose", o.verbose), kv("format", o.format), kv("active", o.active), kv("daily", o.daily)));
|
||||
task = (o: { ref?: string; file?: string; path?: string; line?: number; status?: string; toggle?: boolean; daily?: boolean; done?: boolean; todo?: boolean } = {}) => this.run(args("task", kv("ref", o.ref), kv("file", o.file), kv("path", o.path), kv("line", o.line), kv("status", o.status), kv("toggle", o.toggle), kv("daily", o.daily), kv("done", o.done), kv("todo", o.todo)));
|
||||
|
||||
// Templates / themes / snippets
|
||||
templates = (o: { total?: boolean } = {}) => this.run(args("templates", kv("total", o.total)));
|
||||
templateRead = (name: string, o: { title?: string; resolve?: boolean } = {}) => this.run(args("template:read", kv("name", name), kv("title", o.title), kv("resolve", o.resolve)));
|
||||
templateInsert = (name: string) => this.run(["template:insert", kv("name", name)!]);
|
||||
themes = (o: { versions?: boolean } = {}) => this.run(args("themes", kv("versions", o.versions)));
|
||||
theme = (o: { name?: string } = {}) => this.run(args("theme", kv("name", o.name)));
|
||||
themeSet = (name: string) => this.run(["theme:set", kv("name", name)!]);
|
||||
themeInstall = (name: string, o: { enable?: boolean } = {}) => this.run(args("theme:install", kv("name", name), kv("enable", o.enable)));
|
||||
themeUninstall = (name: string) => this.run(["theme:uninstall", kv("name", name)!]);
|
||||
snippets = () => this.run(["snippets"]);
|
||||
snippetsEnabled = () => this.run(["snippets:enabled"]);
|
||||
snippetEnable = (name: string) => this.run(["snippet:enable", kv("name", name)!]);
|
||||
snippetDisable = (name: string) => this.run(["snippet:disable", kv("name", name)!]);
|
||||
|
||||
// Unique / vault / web / wordcount / workspace
|
||||
unique = (o: { name?: string; content?: string; paneType?: PaneType; open?: boolean } = {}) => this.run(args("unique", kv("name", o.name), kv("content", o.content), kv("paneType", o.paneType), kv("open", o.open)));
|
||||
vault = (o: { info?: "name" | "path" | "files" | "folders" | "size" } = {}) => this.run(args("vault", kv("info", o.info)));
|
||||
vaults = (o: { total?: boolean; verbose?: boolean } = {}) => this.run(args("vaults", kv("total", o.total), kv("verbose", o.verbose)));
|
||||
vaultOpen = (name: string) => this.run(["vault:open", kv("name", name)!]);
|
||||
web = (url: string, o: { newtab?: boolean } = {}) => this.run(args("web", kv("url", url), kv("newtab", o.newtab)));
|
||||
wordcount = (o: { file?: string; path?: string; words?: boolean; characters?: boolean } = {}) => this.run(args("wordcount", kv("file", o.file), kv("path", o.path), kv("words", o.words), kv("characters", o.characters)));
|
||||
workspace = (o: { ids?: boolean } = {}) => this.run(args("workspace", kv("ids", o.ids)));
|
||||
workspaces = (o: { total?: boolean } = {}) => this.run(args("workspaces", kv("total", o.total)));
|
||||
workspaceSave = (name: string) => this.run(["workspace:save", kv("name", name)!]);
|
||||
workspaceLoad = (name: string) => this.run(["workspace:load", kv("name", name)!]);
|
||||
workspaceDelete = (name: string) => this.run(["workspace:delete", kv("name", name)!]);
|
||||
tabs = (o: { ids?: boolean } = {}) => this.run(args("tabs", kv("ids", o.ids)));
|
||||
tabOpen = (o: { group?: string; file?: string; view?: string } = {}) => this.run(args("tab:open", kv("group", o.group), kv("file", o.file), kv("view", o.view)));
|
||||
recents = (o: { total?: boolean } = {}) => this.run(args("recents", kv("total", o.total)));
|
||||
|
||||
// Developer commands
|
||||
devtools = () => this.run(["devtools"]);
|
||||
devDebug = (o: { on?: boolean; off?: boolean } = {}) => this.run(args("dev:debug", kv("on", o.on), kv("off", o.off)));
|
||||
devCdp = (method: string, o: { params?: string } = {}) => this.run(args("dev:cdp", kv("method", method), kv("params", o.params)));
|
||||
devErrors = (o: { clear?: boolean } = {}) => this.run(args("dev:errors", kv("clear", o.clear)));
|
||||
devScreenshot = (o: { path?: string } = {}) => this.run(args("dev:screenshot", kv("path", o.path)));
|
||||
devConsole = (o: { limit?: number; level?: LogLevel; clear?: boolean } = {}) => this.run(args("dev:console", kv("limit", o.limit), kv("level", o.level), kv("clear", o.clear)));
|
||||
devCss = (selector: string, o: { prop?: string } = {}) => this.run(args("dev:css", kv("selector", selector), kv("prop", o.prop)));
|
||||
devDom = (selector: string, o: { attr?: string; css?: string; total?: boolean; text?: boolean; inner?: boolean; all?: boolean } = {}) => this.run(args("dev:dom", kv("selector", selector), kv("attr", o.attr), kv("css", o.css), kv("total", o.total), kv("text", o.text), kv("inner", o.inner), kv("all", o.all)));
|
||||
devMobile = (o: { on?: boolean; off?: boolean } = {}) => this.run(args("dev:mobile", kv("on", o.on), kv("off", o.off)));
|
||||
eval = (code: string) => this.run(["eval", kv("code", code)!]);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"lib": ["ES2022", "DOM"],
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
Reference in New Issue
Block a user