Ordo commited on
Commit
0bb82b0
·
0 Parent(s):

Initial public release

Browse files
Files changed (8) hide show
  1. .env.example +1 -0
  2. .gitignore +6 -0
  3. LICENSE +21 -0
  4. README.md +17 -0
  5. SECURITY.md +3 -0
  6. index.mjs +67 -0
  7. openclaw.plugin.json +10 -0
  8. package.json +15 -0
.env.example ADDED
@@ -0,0 +1 @@
 
 
1
+ OBSIDIAN_BIN=obsidian
.gitignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ .env
2
+ .env.*
3
+ !.env.example
4
+ node_modules/
5
+ npm-debug.log*
6
+ *.log
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Patrick
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # OpenClaw Obsidian Bridge
2
+
3
+ Minimal OpenClaw plugin extension that exposes Obsidian status/open helpers through gateway methods and an authenticated HTTP route.
4
+
5
+ ## Methods
6
+
7
+ - `obsidian.bridge.status`
8
+ - `obsidian.bridge.open`
9
+ - `POST /hooks/obsidian-bridge`
10
+
11
+ ## Local Check
12
+
13
+ ```bash
14
+ npm test
15
+ ```
16
+
17
+ The example assumes an `obsidian` helper binary is available. Adapt `index.mjs` for your own host path or wrapper.
SECURITY.md ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ # Security
2
+
3
+ Do not expose this bridge without OpenClaw plugin authentication. Vault paths and file names can be sensitive; avoid logging request bodies in public deployments.
index.mjs ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { definePluginEntry } from 'openclaw/plugin-sdk/plugin-entry';
2
+ import { execFile } from 'node:child_process';
3
+ import { promisify } from 'node:util';
4
+
5
+ const execFileAsync = promisify(execFile);
6
+
7
+ async function run(command, args = []) {
8
+ const { stdout, stderr } = await execFileAsync(command, args, { encoding: 'utf8' });
9
+ return { stdout, stderr };
10
+ }
11
+
12
+ async function obsidianStatus() {
13
+ const { stdout } = await run(process.env.OBSIDIAN_BIN || 'obsidian', ['status']);
14
+ return JSON.parse(stdout);
15
+ }
16
+
17
+ async function obsidianOpen(vaultPath) {
18
+ const args = ['open'];
19
+ if (vaultPath) args.push(`path=${vaultPath}`);
20
+ const { stdout } = await run(process.env.OBSIDIAN_BIN || 'obsidian', args);
21
+ return stdout ? JSON.parse(stdout) : { launched: true };
22
+ }
23
+
24
+ export default definePluginEntry({
25
+ id: 'obsidian-bridge',
26
+ name: 'Obsidian Bridge',
27
+ description: 'Minimal OpenClaw-owned Obsidian bridge for Paperclip and local callers.',
28
+ register(api) {
29
+ api.registerGatewayMethod('obsidian.bridge.status', async ({ respond }) => {
30
+ try {
31
+ respond({ ok: true, status: await obsidianStatus() });
32
+ } catch (error) {
33
+ respond({ ok: false, error: String(error?.message || error) });
34
+ }
35
+ });
36
+ api.registerGatewayMethod('obsidian.bridge.open', async ({ params, respond }) => {
37
+ try {
38
+ respond({ ok: true, result: await obsidianOpen(params?.path || null) });
39
+ } catch (error) {
40
+ respond({ ok: false, error: String(error?.message || error) });
41
+ }
42
+ });
43
+ api.registerHttpRoute({
44
+ path: '/hooks/obsidian-bridge',
45
+ auth: 'plugin',
46
+ match: 'exact',
47
+ replaceExisting: true,
48
+ async handler(req, res) {
49
+ try {
50
+ const body = req.body && typeof req.body === 'object' ? req.body : {};
51
+ const action = body.action || 'status';
52
+ if (action === 'status') {
53
+ res.status(200).json({ ok: true, status: await obsidianStatus() });
54
+ return;
55
+ }
56
+ if (action === 'open') {
57
+ res.status(200).json({ ok: true, result: await obsidianOpen(body.path || null) });
58
+ return;
59
+ }
60
+ res.status(400).json({ ok: false, error: 'unsupported action' });
61
+ } catch (error) {
62
+ res.status(500).json({ ok: false, error: String(error?.message || error) });
63
+ }
64
+ }
65
+ });
66
+ }
67
+ });
openclaw.plugin.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "id": "obsidian-bridge",
3
+ "name": "Obsidian Bridge",
4
+ "description": "Minimal OpenClaw-owned Obsidian bridge for Paperclip and local callers.",
5
+ "configSchema": {
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "properties": {}
9
+ }
10
+ }
package.json ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "obsidian-bridge",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Minimal OpenClaw-owned Obsidian bridge for Paperclip and local callers.",
6
+ "private": false,
7
+ "scripts": {
8
+ "test": "node --check index.mjs"
9
+ },
10
+ "openclaw": {
11
+ "extensions": [
12
+ "./index.mjs"
13
+ ]
14
+ }
15
+ }