odcli 0.1.5__tar.gz → 0.1.7__tar.gz
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.
- {odcli-0.1.5 → odcli-0.1.7}/PKG-INFO +147 -62
- odcli-0.1.7/README.md +280 -0
- {odcli-0.1.5 → odcli-0.1.7}/pyproject.toml +1 -1
- {odcli-0.1.5 → odcli-0.1.7}/src/obsidian_cli/__init__.py +1 -1
- {odcli-0.1.5 → odcli-0.1.7}/src/obsidian_cli/cli.py +29 -4
- {odcli-0.1.5 → odcli-0.1.7}/src/obsidian_cli/commands.py +2 -2
- {odcli-0.1.5 → odcli-0.1.7}/src/obsidian_cli/discovery.py +14 -1
- {odcli-0.1.5 → odcli-0.1.7}/src/obsidian_cli/plugins.py +6 -1
- odcli-0.1.7/src/obsidian_cli/vault.py +328 -0
- {odcli-0.1.5 → odcli-0.1.7}/src/odcli.egg-info/PKG-INFO +147 -62
- {odcli-0.1.5 → odcli-0.1.7}/tests/test_cli.py +82 -7
- odcli-0.1.5/README.md +0 -195
- odcli-0.1.5/src/obsidian_cli/vault.py +0 -131
- {odcli-0.1.5 → odcli-0.1.7}/setup.cfg +0 -0
- {odcli-0.1.5 → odcli-0.1.7}/src/obsidian_cli/__main__.py +0 -0
- {odcli-0.1.5 → odcli-0.1.7}/src/odcli.egg-info/SOURCES.txt +0 -0
- {odcli-0.1.5 → odcli-0.1.7}/src/odcli.egg-info/dependency_links.txt +0 -0
- {odcli-0.1.5 → odcli-0.1.7}/src/odcli.egg-info/entry_points.txt +0 -0
- {odcli-0.1.5 → odcli-0.1.7}/src/odcli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: odcli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: A small CLI for reading and writing notes in a local Obsidian vault.
|
|
5
5
|
Author: odcli contributors
|
|
6
6
|
Keywords: obsidian,cli,markdown,notes,vault
|
|
@@ -18,68 +18,160 @@ Description-Content-Type: text/markdown
|
|
|
18
18
|
|
|
19
19
|
# odcli
|
|
20
20
|
|
|
21
|
-
`odcli` is a
|
|
22
|
-
It works directly on Markdown files inside the vault, so it does not depend on private Obsidian APIs and remains portable and easy to extend.
|
|
21
|
+
`odcli` is a command-line tool for reading and writing notes in a local Obsidian vault.
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
It works directly on Markdown files inside the vault, so you can use it without any private Obsidian API.
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
- List Markdown notes in the vault
|
|
28
|
-
- Read a specific note
|
|
29
|
-
- Read a specific line range from a note
|
|
30
|
-
- Overwrite a note or create it automatically
|
|
31
|
-
- Replace a specific line range in a note
|
|
32
|
-
- Append content to a note
|
|
33
|
-
- Full-text search across the vault
|
|
34
|
-
- Auto-discover the default vault from Obsidian config or common macOS and Windows locations
|
|
35
|
-
- Install odcli helper skills into Codex or Claude Code skill directories
|
|
25
|
+
## Install
|
|
36
26
|
|
|
37
|
-
|
|
27
|
+
From PyPI:
|
|
38
28
|
|
|
39
29
|
```bash
|
|
40
|
-
|
|
41
|
-
uv sync
|
|
42
|
-
uv run odcli --help
|
|
30
|
+
pip install odcli
|
|
43
31
|
```
|
|
44
32
|
|
|
45
|
-
|
|
33
|
+
Or with `uv`:
|
|
46
34
|
|
|
47
35
|
```bash
|
|
48
|
-
|
|
49
|
-
uv run python -m unittest discover -s tests
|
|
36
|
+
uv tool install odcli
|
|
50
37
|
```
|
|
51
38
|
|
|
52
|
-
|
|
39
|
+
After installation, both command names are available:
|
|
53
40
|
|
|
54
41
|
```bash
|
|
55
|
-
|
|
56
|
-
|
|
42
|
+
odcli --help
|
|
43
|
+
obsidian-cli --help
|
|
57
44
|
```
|
|
58
45
|
|
|
59
|
-
|
|
60
|
-
After installation, both `odcli` and `obsidian-cli` are available as command names.
|
|
46
|
+
## Quickstart
|
|
61
47
|
|
|
62
|
-
|
|
48
|
+
If your vault is already in a common location, `odcli` can usually find it automatically:
|
|
63
49
|
|
|
64
50
|
```bash
|
|
65
|
-
|
|
66
|
-
|
|
51
|
+
odcli check
|
|
52
|
+
odcli list
|
|
67
53
|
```
|
|
68
54
|
|
|
69
|
-
|
|
55
|
+
If you want to set the vault explicitly:
|
|
70
56
|
|
|
71
57
|
```bash
|
|
72
|
-
|
|
73
|
-
|
|
58
|
+
export OBSIDIAN_VAULT="/path/to/MyVault"
|
|
59
|
+
odcli check
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
You can also override the vault per command:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
odcli --vault "/path/to/MyVault" list
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Remote Vault over SSH
|
|
69
|
+
|
|
70
|
+
You can operate on an Obsidian vault stored on another machine over SSH.
|
|
71
|
+
|
|
72
|
+
Example:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
odcli \
|
|
76
|
+
--ssh-host your-server \
|
|
77
|
+
--ssh-user your-user \
|
|
78
|
+
--vault /path/to/ObsidianVault \
|
|
79
|
+
list
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Read a remote note:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
odcli \
|
|
86
|
+
--ssh-host your-server \
|
|
87
|
+
--ssh-user your-user \
|
|
88
|
+
--vault /path/to/ObsidianVault \
|
|
89
|
+
read Inbox/today.md
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Write a remote note:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
odcli \
|
|
96
|
+
--ssh-host your-server \
|
|
97
|
+
--ssh-user your-user \
|
|
98
|
+
--vault /path/to/ObsidianVault \
|
|
99
|
+
write Inbox/today.md --content "# Remote note"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Optional SSH flags:
|
|
103
|
+
|
|
104
|
+
- `--ssh-port`
|
|
105
|
+
- `--ssh-identity`
|
|
106
|
+
|
|
107
|
+
In SSH mode, `--vault` or `OBSIDIAN_VAULT` should point to the remote vault path.
|
|
108
|
+
|
|
109
|
+
## Common Commands
|
|
110
|
+
|
|
111
|
+
Read a note:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
odcli read Inbox/today.md
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Read specific lines:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
odcli read-lines Inbox/today.md 3 8
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Create or overwrite a note:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
odcli write Inbox/today.md --content "# Today"
|
|
74
127
|
```
|
|
75
128
|
|
|
76
|
-
|
|
129
|
+
Replace a line range:
|
|
77
130
|
|
|
78
131
|
```bash
|
|
79
|
-
|
|
132
|
+
odcli write-lines Inbox/today.md 3 4 --content "- replaced\n- lines\n"
|
|
80
133
|
```
|
|
81
134
|
|
|
82
|
-
|
|
135
|
+
Append content:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
odcli append Inbox/today.md --content "\n- new item"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Search across the vault:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
odcli search "project alpha"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Skill Install
|
|
148
|
+
|
|
149
|
+
`odcli` can install helper skills for local coding tools.
|
|
150
|
+
|
|
151
|
+
Install into Codex:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
odcli plugin install codex-skill
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Install into Claude Code:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
odcli plugin install claude-skill
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Install both:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
odcli plugin install all-skills
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Installed paths:
|
|
170
|
+
|
|
171
|
+
- Codex: `~/.codex/skills/odcli/SKILL.md`
|
|
172
|
+
- Claude Code: `~/.claude/skills/odcli/SKILL.md`
|
|
173
|
+
|
|
174
|
+
## Vault Discovery
|
|
83
175
|
|
|
84
176
|
Resolution priority:
|
|
85
177
|
|
|
@@ -96,21 +188,7 @@ Built-in default locations:
|
|
|
96
188
|
- Windows: `%USERPROFILE%\\Documents\\Obsidian Vault`
|
|
97
189
|
- Windows: `%USERPROFILE%\\Documents\\Obsidian`
|
|
98
190
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
```bash
|
|
102
|
-
export OBSIDIAN_VAULT="/path/to/MyVault"
|
|
103
|
-
./odcli check
|
|
104
|
-
./odcli list
|
|
105
|
-
./odcli read Inbox/today.md
|
|
106
|
-
./odcli read-lines Inbox/today.md 3 8
|
|
107
|
-
./odcli write Inbox/today.md --content "# Today"
|
|
108
|
-
./odcli write-lines Inbox/today.md 3 4 --content "- replaced\n- lines\n"
|
|
109
|
-
./odcli append Inbox/today.md --content "\n- new item"
|
|
110
|
-
./odcli search "project alpha"
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
## Commands
|
|
191
|
+
## Command Summary
|
|
114
192
|
|
|
115
193
|
### `check`
|
|
116
194
|
|
|
@@ -187,27 +265,34 @@ Arguments:
|
|
|
187
265
|
- `query`
|
|
188
266
|
- `--case-sensitive`
|
|
189
267
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
Install odcli helper skills for local coding tools.
|
|
268
|
+
## Global Options
|
|
193
269
|
|
|
194
|
-
|
|
270
|
+
- `--vault`
|
|
271
|
+
- `--ssh-host`
|
|
272
|
+
- `--ssh-user`
|
|
273
|
+
- `--ssh-port`
|
|
274
|
+
- `--ssh-identity`
|
|
195
275
|
|
|
196
|
-
|
|
197
|
-
- `claude-skill`: installs to `~/.claude/skills/odcli/SKILL.md`
|
|
198
|
-
- `all-skills`: installs both
|
|
276
|
+
## For Developers
|
|
199
277
|
|
|
200
|
-
|
|
278
|
+
Run from source:
|
|
201
279
|
|
|
202
280
|
```bash
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
281
|
+
cd path/to/obsidian_cli
|
|
282
|
+
uv sync
|
|
283
|
+
uv run odcli --help
|
|
206
284
|
```
|
|
207
285
|
|
|
208
|
-
|
|
286
|
+
Run tests:
|
|
209
287
|
|
|
210
288
|
```bash
|
|
211
289
|
cd path/to/obsidian_cli
|
|
212
290
|
uv run python -m unittest discover -s tests
|
|
213
291
|
```
|
|
292
|
+
|
|
293
|
+
Build distributions:
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
cd path/to/obsidian_cli
|
|
297
|
+
uv build
|
|
298
|
+
```
|
odcli-0.1.7/README.md
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# odcli
|
|
2
|
+
|
|
3
|
+
`odcli` is a command-line tool for reading and writing notes in a local Obsidian vault.
|
|
4
|
+
|
|
5
|
+
It works directly on Markdown files inside the vault, so you can use it without any private Obsidian API.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
From PyPI:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install odcli
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or with `uv`:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
uv tool install odcli
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
After installation, both command names are available:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
odcli --help
|
|
25
|
+
obsidian-cli --help
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quickstart
|
|
29
|
+
|
|
30
|
+
If your vault is already in a common location, `odcli` can usually find it automatically:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
odcli check
|
|
34
|
+
odcli list
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
If you want to set the vault explicitly:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
export OBSIDIAN_VAULT="/path/to/MyVault"
|
|
41
|
+
odcli check
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
You can also override the vault per command:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
odcli --vault "/path/to/MyVault" list
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Remote Vault over SSH
|
|
51
|
+
|
|
52
|
+
You can operate on an Obsidian vault stored on another machine over SSH.
|
|
53
|
+
|
|
54
|
+
Example:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
odcli \
|
|
58
|
+
--ssh-host your-server \
|
|
59
|
+
--ssh-user your-user \
|
|
60
|
+
--vault /path/to/ObsidianVault \
|
|
61
|
+
list
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Read a remote note:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
odcli \
|
|
68
|
+
--ssh-host your-server \
|
|
69
|
+
--ssh-user your-user \
|
|
70
|
+
--vault /path/to/ObsidianVault \
|
|
71
|
+
read Inbox/today.md
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Write a remote note:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
odcli \
|
|
78
|
+
--ssh-host your-server \
|
|
79
|
+
--ssh-user your-user \
|
|
80
|
+
--vault /path/to/ObsidianVault \
|
|
81
|
+
write Inbox/today.md --content "# Remote note"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Optional SSH flags:
|
|
85
|
+
|
|
86
|
+
- `--ssh-port`
|
|
87
|
+
- `--ssh-identity`
|
|
88
|
+
|
|
89
|
+
In SSH mode, `--vault` or `OBSIDIAN_VAULT` should point to the remote vault path.
|
|
90
|
+
|
|
91
|
+
## Common Commands
|
|
92
|
+
|
|
93
|
+
Read a note:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
odcli read Inbox/today.md
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Read specific lines:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
odcli read-lines Inbox/today.md 3 8
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Create or overwrite a note:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
odcli write Inbox/today.md --content "# Today"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Replace a line range:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
odcli write-lines Inbox/today.md 3 4 --content "- replaced\n- lines\n"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Append content:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
odcli append Inbox/today.md --content "\n- new item"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Search across the vault:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
odcli search "project alpha"
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Skill Install
|
|
130
|
+
|
|
131
|
+
`odcli` can install helper skills for local coding tools.
|
|
132
|
+
|
|
133
|
+
Install into Codex:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
odcli plugin install codex-skill
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Install into Claude Code:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
odcli plugin install claude-skill
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Install both:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
odcli plugin install all-skills
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Installed paths:
|
|
152
|
+
|
|
153
|
+
- Codex: `~/.codex/skills/odcli/SKILL.md`
|
|
154
|
+
- Claude Code: `~/.claude/skills/odcli/SKILL.md`
|
|
155
|
+
|
|
156
|
+
## Vault Discovery
|
|
157
|
+
|
|
158
|
+
Resolution priority:
|
|
159
|
+
|
|
160
|
+
1. `--vault /path/to/vault`
|
|
161
|
+
2. `OBSIDIAN_VAULT`
|
|
162
|
+
3. The most recently opened vault recorded by local Obsidian config
|
|
163
|
+
4. Common default directories
|
|
164
|
+
|
|
165
|
+
Built-in default locations:
|
|
166
|
+
|
|
167
|
+
- macOS: `~/Documents/Obsidian Vault`
|
|
168
|
+
- macOS: `~/Documents/Obsidian`
|
|
169
|
+
- macOS iCloud: `~/Library/Mobile Documents/iCloud~md~obsidian/Documents`
|
|
170
|
+
- Windows: `%USERPROFILE%\\Documents\\Obsidian Vault`
|
|
171
|
+
- Windows: `%USERPROFILE%\\Documents\\Obsidian`
|
|
172
|
+
|
|
173
|
+
## Command Summary
|
|
174
|
+
|
|
175
|
+
### `check`
|
|
176
|
+
|
|
177
|
+
Validate that the vault exists and report whether `.obsidian` is present.
|
|
178
|
+
|
|
179
|
+
### `list`
|
|
180
|
+
|
|
181
|
+
List Markdown notes in the vault.
|
|
182
|
+
|
|
183
|
+
Optional arguments:
|
|
184
|
+
|
|
185
|
+
- `--limit N`
|
|
186
|
+
|
|
187
|
+
### `read`
|
|
188
|
+
|
|
189
|
+
Read a note.
|
|
190
|
+
|
|
191
|
+
Arguments:
|
|
192
|
+
|
|
193
|
+
- `note_path`: path relative to the vault root
|
|
194
|
+
|
|
195
|
+
### `write`
|
|
196
|
+
|
|
197
|
+
Overwrite a note. Parent directories are created automatically if needed.
|
|
198
|
+
|
|
199
|
+
Arguments:
|
|
200
|
+
|
|
201
|
+
- `note_path`
|
|
202
|
+
- `--content TEXT`
|
|
203
|
+
- `--stdin`
|
|
204
|
+
|
|
205
|
+
Optional arguments:
|
|
206
|
+
|
|
207
|
+
- `--create-only`
|
|
208
|
+
|
|
209
|
+
### `read-lines`
|
|
210
|
+
|
|
211
|
+
Read a line range. Line numbers are 1-based and inclusive.
|
|
212
|
+
|
|
213
|
+
Arguments:
|
|
214
|
+
|
|
215
|
+
- `note_path`
|
|
216
|
+
- `start_line`
|
|
217
|
+
- `end_line`
|
|
218
|
+
|
|
219
|
+
### `write-lines`
|
|
220
|
+
|
|
221
|
+
Replace a line range. Line numbers are 1-based and inclusive.
|
|
222
|
+
|
|
223
|
+
Arguments:
|
|
224
|
+
|
|
225
|
+
- `note_path`
|
|
226
|
+
- `start_line`
|
|
227
|
+
- `end_line`
|
|
228
|
+
- `--content TEXT`
|
|
229
|
+
- `--stdin`
|
|
230
|
+
|
|
231
|
+
### `append`
|
|
232
|
+
|
|
233
|
+
Append content to the end of a note.
|
|
234
|
+
|
|
235
|
+
Arguments:
|
|
236
|
+
|
|
237
|
+
- `note_path`
|
|
238
|
+
- `--content TEXT`
|
|
239
|
+
- `--stdin`
|
|
240
|
+
|
|
241
|
+
### `search`
|
|
242
|
+
|
|
243
|
+
Search across all Markdown notes in the vault.
|
|
244
|
+
|
|
245
|
+
Arguments:
|
|
246
|
+
|
|
247
|
+
- `query`
|
|
248
|
+
- `--case-sensitive`
|
|
249
|
+
|
|
250
|
+
## Global Options
|
|
251
|
+
|
|
252
|
+
- `--vault`
|
|
253
|
+
- `--ssh-host`
|
|
254
|
+
- `--ssh-user`
|
|
255
|
+
- `--ssh-port`
|
|
256
|
+
- `--ssh-identity`
|
|
257
|
+
|
|
258
|
+
## For Developers
|
|
259
|
+
|
|
260
|
+
Run from source:
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
cd path/to/obsidian_cli
|
|
264
|
+
uv sync
|
|
265
|
+
uv run odcli --help
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Run tests:
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
cd path/to/obsidian_cli
|
|
272
|
+
uv run python -m unittest discover -s tests
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Build distributions:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
cd path/to/obsidian_cli
|
|
279
|
+
uv build
|
|
280
|
+
```
|
|
@@ -6,7 +6,13 @@ import sys
|
|
|
6
6
|
from obsidian_cli.commands import CommandRunner
|
|
7
7
|
from obsidian_cli.discovery import VaultLocator
|
|
8
8
|
from obsidian_cli.plugins import SkillInstaller
|
|
9
|
-
from obsidian_cli.vault import
|
|
9
|
+
from obsidian_cli.vault import (
|
|
10
|
+
ObsidianVault,
|
|
11
|
+
SshConfig,
|
|
12
|
+
SshObsidianVault,
|
|
13
|
+
VaultBackend,
|
|
14
|
+
VaultError,
|
|
15
|
+
)
|
|
10
16
|
|
|
11
17
|
|
|
12
18
|
class ObsidianCLI:
|
|
@@ -22,9 +28,7 @@ class ObsidianCLI:
|
|
|
22
28
|
if args.command == "plugin":
|
|
23
29
|
return self._run_plugin_command(args)
|
|
24
30
|
|
|
25
|
-
runner = CommandRunner(
|
|
26
|
-
ObsidianVault(self._vault_locator.resolve(args.vault))
|
|
27
|
-
)
|
|
31
|
+
runner = CommandRunner(self._build_vault(args))
|
|
28
32
|
|
|
29
33
|
if args.command == "check":
|
|
30
34
|
return runner.check()
|
|
@@ -72,6 +76,13 @@ class ObsidianCLI:
|
|
|
72
76
|
"--vault",
|
|
73
77
|
help="Path to the Obsidian vault. Falls back to OBSIDIAN_VAULT.",
|
|
74
78
|
)
|
|
79
|
+
parser.add_argument("--ssh-host", help="SSH host for a remote vault.")
|
|
80
|
+
parser.add_argument("--ssh-user", help="SSH username for a remote vault.")
|
|
81
|
+
parser.add_argument("--ssh-port", type=int, help="SSH port for a remote vault.")
|
|
82
|
+
parser.add_argument(
|
|
83
|
+
"--ssh-identity",
|
|
84
|
+
help="SSH identity file used when connecting to a remote vault.",
|
|
85
|
+
)
|
|
75
86
|
|
|
76
87
|
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
77
88
|
subparsers.add_parser("check", help="Validate the vault path.")
|
|
@@ -175,6 +186,20 @@ class ObsidianCLI:
|
|
|
175
186
|
self._parser.error(f"unsupported plugin command: {args.plugin_command}")
|
|
176
187
|
return 2
|
|
177
188
|
|
|
189
|
+
def _build_vault(self, args: argparse.Namespace) -> VaultBackend:
|
|
190
|
+
if args.ssh_host:
|
|
191
|
+
ssh_root = self._vault_locator.resolve_configured(args.vault)
|
|
192
|
+
return SshObsidianVault(
|
|
193
|
+
str(ssh_root),
|
|
194
|
+
SshConfig(
|
|
195
|
+
host=args.ssh_host,
|
|
196
|
+
user=args.ssh_user,
|
|
197
|
+
port=args.ssh_port,
|
|
198
|
+
identity_file=args.ssh_identity,
|
|
199
|
+
),
|
|
200
|
+
)
|
|
201
|
+
return ObsidianVault(self._vault_locator.resolve(args.vault))
|
|
202
|
+
|
|
178
203
|
@staticmethod
|
|
179
204
|
def _read_content_arg(content: str | None, use_stdin: bool) -> str:
|
|
180
205
|
if content is not None and use_stdin:
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from obsidian_cli.vault import
|
|
3
|
+
from obsidian_cli.vault import VaultBackend, VaultError
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class CommandRunner:
|
|
7
|
-
def __init__(self, vault:
|
|
7
|
+
def __init__(self, vault: VaultBackend) -> None:
|
|
8
8
|
self._vault = vault
|
|
9
9
|
|
|
10
10
|
def check(self) -> int:
|
|
@@ -18,7 +18,7 @@ class VaultLocator:
|
|
|
18
18
|
def __init__(
|
|
19
19
|
self, env: dict[str, str] | None = None, home: Path | None = None
|
|
20
20
|
) -> None:
|
|
21
|
-
self._env = dict(env
|
|
21
|
+
self._env = dict(os.environ if env is None else env)
|
|
22
22
|
self._home = (home or Path.home()).expanduser()
|
|
23
23
|
|
|
24
24
|
def resolve(self, cli_value: str | None) -> Path:
|
|
@@ -38,6 +38,19 @@ class VaultLocator:
|
|
|
38
38
|
"vault path is required; use --vault, OBSIDIAN_VAULT, or place your vault in a default Obsidian location"
|
|
39
39
|
)
|
|
40
40
|
|
|
41
|
+
def resolve_configured(self, cli_value: str | None) -> Path:
|
|
42
|
+
cli_path = self._path_from_string(cli_value)
|
|
43
|
+
if cli_path is not None:
|
|
44
|
+
return cli_path
|
|
45
|
+
|
|
46
|
+
env_path = self._path_from_string(self._env.get("OBSIDIAN_VAULT"))
|
|
47
|
+
if env_path is not None:
|
|
48
|
+
return env_path
|
|
49
|
+
|
|
50
|
+
raise VaultError(
|
|
51
|
+
"vault path is required for SSH mode; use --vault or OBSIDIAN_VAULT"
|
|
52
|
+
)
|
|
53
|
+
|
|
41
54
|
def discover_default_vault(self) -> VaultCandidate | None:
|
|
42
55
|
config_candidate = self._discover_from_obsidian_config()
|
|
43
56
|
if config_candidate is not None:
|
|
@@ -4,7 +4,12 @@ from dataclasses import dataclass
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
SKILL_BODY = """
|
|
7
|
+
SKILL_BODY = """---
|
|
8
|
+
name: "odcli"
|
|
9
|
+
description: "Use odcli to read, write, append, search, and patch notes inside a local Obsidian vault."
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# odcli
|
|
8
13
|
|
|
9
14
|
Use `odcli` when you need to read or write notes inside a local Obsidian vault.
|
|
10
15
|
|