@qiqiangvae/dsh-obsidian 0.1.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/ATTRIBUTION.md +36 -0
- package/LICENSE +21 -0
- package/README.md +102 -0
- package/cordis.patch.yml +23 -0
- package/index.js +5 -0
- package/lib/index.d.ts +64 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +351 -0
- package/lib/index.js.map +1 -0
- package/lib/lint.d.ts +25 -0
- package/lib/lint.d.ts.map +1 -0
- package/lib/lint.js +145 -0
- package/lib/lint.js.map +1 -0
- package/lib/scaffold.d.ts +26 -0
- package/lib/scaffold.d.ts.map +1 -0
- package/lib/scaffold.js +67 -0
- package/lib/scaffold.js.map +1 -0
- package/lib/search.d.ts +41 -0
- package/lib/search.d.ts.map +1 -0
- package/lib/search.js +127 -0
- package/lib/search.js.map +1 -0
- package/lib/skills.d.ts +18 -0
- package/lib/skills.d.ts.map +1 -0
- package/lib/skills.js +83 -0
- package/lib/skills.js.map +1 -0
- package/lib/types.d.ts +55 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +6 -0
- package/lib/types.js.map +1 -0
- package/lib/vault.d.ts +69 -0
- package/lib/vault.d.ts.map +1 -0
- package/lib/vault.js +315 -0
- package/lib/vault.js.map +1 -0
- package/package.json +66 -0
- package/skills/defuddle/SKILL.md +35 -0
- package/skills/json-canvas/SKILL.md +61 -0
- package/skills/obsidian-bases/SKILL.md +51 -0
- package/skills/obsidian-cli/SKILL.md +41 -0
- package/skills/obsidian-markdown/SKILL.md +59 -0
- package/skills/save/SKILL.md +33 -0
- package/skills/think/SKILL.md +27 -0
- package/skills/wiki/SKILL.md +45 -0
- package/skills/wiki-ingest/SKILL.md +40 -0
- package/skills/wiki-lint/SKILL.md +36 -0
- package/skills/wiki-query/SKILL.md +34 -0
package/lib/types.js
ADDED
package/lib/types.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/lib/vault.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vault.ts — vault file operations, type routing, frontmatter bookkeeping.
|
|
3
|
+
*
|
|
4
|
+
* Re-implementation of the LLM Wiki pattern's mechanical core (paths,
|
|
5
|
+
* frontmatter, master index, log, source delta tracking). Adapted from
|
|
6
|
+
* dsh-plugin-wiki-tools; now written directly against node:fs in modern
|
|
7
|
+
* TypeScript so it survives cordis API churn.
|
|
8
|
+
*/
|
|
9
|
+
import type { PluginConfig } from './types.js';
|
|
10
|
+
export type { PluginConfig } from './types.js';
|
|
11
|
+
export interface VaultLayout {
|
|
12
|
+
wikiDir: string;
|
|
13
|
+
rawDir: string;
|
|
14
|
+
metaDir: string;
|
|
15
|
+
indexFile: string;
|
|
16
|
+
logFile: string;
|
|
17
|
+
hotFile: string;
|
|
18
|
+
typeFolders: Record<string, string>;
|
|
19
|
+
}
|
|
20
|
+
export declare function resolveLayout(vaultPath: string, config: PluginConfig): VaultLayout;
|
|
21
|
+
export declare function isMachineryPage(name: string): boolean;
|
|
22
|
+
export declare function isPortableFilename(name: string): boolean;
|
|
23
|
+
/** Reject any path that resolves outside vaultPath. */
|
|
24
|
+
export declare function assertInsideVault(vaultPath: string, target: string): void;
|
|
25
|
+
export interface Frontmatter {
|
|
26
|
+
title?: string;
|
|
27
|
+
type?: string;
|
|
28
|
+
tags?: string[];
|
|
29
|
+
created?: string;
|
|
30
|
+
updated?: string;
|
|
31
|
+
source?: string;
|
|
32
|
+
source_hash?: string;
|
|
33
|
+
[k: string]: unknown;
|
|
34
|
+
}
|
|
35
|
+
export declare function parseFrontmatter(md: string): {
|
|
36
|
+
fm: Frontmatter;
|
|
37
|
+
body: string;
|
|
38
|
+
};
|
|
39
|
+
export declare function serializeFrontmatter(fm: Frontmatter): string;
|
|
40
|
+
export declare function completeFrontmatter(existing: Frontmatter, patch: Partial<Frontmatter>, now?: string): Frontmatter;
|
|
41
|
+
export declare function upsertIndexEntry(indexFile: string, type: string, sectionHeading: string, title: string, style?: ':' | '—'): void;
|
|
42
|
+
export declare function appendLog(logFile: string, line: string): void;
|
|
43
|
+
export interface WritePageArgs {
|
|
44
|
+
title: string;
|
|
45
|
+
type: string;
|
|
46
|
+
content: string;
|
|
47
|
+
tags?: string[];
|
|
48
|
+
source_path?: string;
|
|
49
|
+
force?: boolean;
|
|
50
|
+
}
|
|
51
|
+
export interface WritePageResult {
|
|
52
|
+
path: string;
|
|
53
|
+
unresolvedLinks: string[];
|
|
54
|
+
sourceHash?: string;
|
|
55
|
+
skipped?: boolean;
|
|
56
|
+
}
|
|
57
|
+
export declare function safeFilename(title: string): string;
|
|
58
|
+
export declare function routePageFolder(vaultPath: string, layout: VaultLayout, type: string): string;
|
|
59
|
+
export declare function collectUnresolvedLinks(body: string, knownTitles: Set<string>): string[];
|
|
60
|
+
export declare function listAllTitles(wikiDir: string): Set<string>;
|
|
61
|
+
export declare function sha256(s: string | Buffer): string;
|
|
62
|
+
export declare function writePage(vaultPath: string, config: PluginConfig, args: WritePageArgs): WritePageResult;
|
|
63
|
+
export declare function renamePage(vaultPath: string, config: PluginConfig, oldTitle: string, newTitle: string): {
|
|
64
|
+
from: string;
|
|
65
|
+
to: string;
|
|
66
|
+
};
|
|
67
|
+
export declare function deletePage(vaultPath: string, config: PluginConfig, title: string): void;
|
|
68
|
+
export declare function walkMd(root: string): Generator<string>;
|
|
69
|
+
//# sourceMappingURL=vault.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"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"}
|
package/lib/vault.js
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vault.ts — vault file operations, type routing, frontmatter bookkeeping.
|
|
3
|
+
*
|
|
4
|
+
* Re-implementation of the LLM Wiki pattern's mechanical core (paths,
|
|
5
|
+
* frontmatter, master index, log, source delta tracking). Adapted from
|
|
6
|
+
* dsh-plugin-wiki-tools; now written directly against node:fs in modern
|
|
7
|
+
* TypeScript so it survives cordis API churn.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync, readdirSync, statSync, mkdirSync, renameSync, unlinkSync, } from 'node:fs';
|
|
10
|
+
import { join, dirname, basename, extname, resolve, sep } from 'node:path';
|
|
11
|
+
import { createHash } from 'node:crypto';
|
|
12
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
13
|
+
// Defaults — overridable via config.typeFolders
|
|
14
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
15
|
+
const DEFAULT_TYPE_FOLDERS = {
|
|
16
|
+
domain: 'wiki/areas',
|
|
17
|
+
area: 'wiki/areas',
|
|
18
|
+
project: 'wiki/projects',
|
|
19
|
+
resource: 'wiki/resources',
|
|
20
|
+
source: 'wiki/sources',
|
|
21
|
+
archive: 'wiki/archive',
|
|
22
|
+
index: 'wiki',
|
|
23
|
+
log: 'wiki',
|
|
24
|
+
hot: 'wiki',
|
|
25
|
+
};
|
|
26
|
+
export function resolveLayout(vaultPath, config) {
|
|
27
|
+
const typeFolders = { ...DEFAULT_TYPE_FOLDERS, ...(config.typeFolders ?? {}) };
|
|
28
|
+
return {
|
|
29
|
+
wikiDir: join(vaultPath, 'wiki'),
|
|
30
|
+
rawDir: join(vaultPath, '.raw'),
|
|
31
|
+
metaDir: join(vaultPath, 'wiki', 'meta'),
|
|
32
|
+
indexFile: join(vaultPath, 'wiki', 'index.md'),
|
|
33
|
+
logFile: join(vaultPath, 'wiki', 'log.md'),
|
|
34
|
+
hotFile: join(vaultPath, 'wiki', 'hot.md'),
|
|
35
|
+
typeFolders,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
39
|
+
// Path safety — jail everything inside the configured vaultPath
|
|
40
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
41
|
+
const RESERVED_DEVICE_NAMES = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/i;
|
|
42
|
+
const PORTABLE_BAD_CHARS = /[:<>"|?*\\]/;
|
|
43
|
+
const PORTABLE_BAD_TAIL = /[ .]+$/;
|
|
44
|
+
export function isMachineryPage(name) {
|
|
45
|
+
// case-insensitive: "Lint Report", "lint report", "LINT REPORT" all count
|
|
46
|
+
return /^lint report\b/i.test(name);
|
|
47
|
+
}
|
|
48
|
+
export function isPortableFilename(name) {
|
|
49
|
+
if (!name)
|
|
50
|
+
return false;
|
|
51
|
+
if (RESERVED_DEVICE_NAMES.test(name))
|
|
52
|
+
return false;
|
|
53
|
+
if (PORTABLE_BAD_CHARS.test(name))
|
|
54
|
+
return false;
|
|
55
|
+
if (PORTABLE_BAD_TAIL.test(name))
|
|
56
|
+
return false;
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
/** Reject any path that resolves outside vaultPath. */
|
|
60
|
+
export function assertInsideVault(vaultPath, target) {
|
|
61
|
+
const abs = resolve(target);
|
|
62
|
+
const root = resolve(vaultPath);
|
|
63
|
+
if (abs !== root && !abs.startsWith(root + sep)) {
|
|
64
|
+
throw new Error(`path escapes vault: ${target}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const FM_RE = /^---\n([\s\S]*?)\n---\n?/;
|
|
68
|
+
export function parseFrontmatter(md) {
|
|
69
|
+
const m = FM_RE.exec(md);
|
|
70
|
+
if (!m)
|
|
71
|
+
return { fm: {}, body: md };
|
|
72
|
+
const fm = {};
|
|
73
|
+
for (const line of m[1].split('\n')) {
|
|
74
|
+
const idx = line.indexOf(':');
|
|
75
|
+
if (idx < 0)
|
|
76
|
+
continue;
|
|
77
|
+
const key = line.slice(0, idx).trim();
|
|
78
|
+
let val = line.slice(idx + 1).trim();
|
|
79
|
+
if (typeof val === 'string' && val.startsWith('[') && val.endsWith(']')) {
|
|
80
|
+
// YAML-style inline list: [a, b, c] — split, strip quotes
|
|
81
|
+
val = val.slice(1, -1).split(',').map((s) => s.trim().replace(/^["']|["']$/g, '')).filter(Boolean);
|
|
82
|
+
}
|
|
83
|
+
else if (typeof val === 'string') {
|
|
84
|
+
val = val.replace(/^["']|["']$/g, '');
|
|
85
|
+
}
|
|
86
|
+
fm[key] = val;
|
|
87
|
+
}
|
|
88
|
+
return { fm, body: md.slice(m[0].length) };
|
|
89
|
+
}
|
|
90
|
+
export function serializeFrontmatter(fm) {
|
|
91
|
+
const lines = ['---'];
|
|
92
|
+
for (const [k, v] of Object.entries(fm)) {
|
|
93
|
+
if (v === undefined)
|
|
94
|
+
continue;
|
|
95
|
+
if (Array.isArray(v)) {
|
|
96
|
+
lines.push(`${k}: ${JSON.stringify(v)}`);
|
|
97
|
+
}
|
|
98
|
+
else if (typeof v === 'string' && (v.includes(':') || v.startsWith('['))) {
|
|
99
|
+
lines.push(`${k}: "${v.replace(/"/g, '\\"')}"`);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
lines.push(`${k}: ${v}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
lines.push('---', '');
|
|
106
|
+
return lines.join('\n');
|
|
107
|
+
}
|
|
108
|
+
export function completeFrontmatter(existing, patch, now = new Date().toISOString().slice(0, 10)) {
|
|
109
|
+
const merged = { ...existing, ...patch };
|
|
110
|
+
if (!merged.created)
|
|
111
|
+
merged.created = existing.created ?? now;
|
|
112
|
+
merged.updated = now;
|
|
113
|
+
return merged;
|
|
114
|
+
}
|
|
115
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
116
|
+
// Index / log / hot bookkeeping
|
|
117
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
118
|
+
export function upsertIndexEntry(indexFile, type, sectionHeading, title, style = ':') {
|
|
119
|
+
if (!existsSync(indexFile)) {
|
|
120
|
+
writeFileSync(indexFile, `# Index\n\n`);
|
|
121
|
+
}
|
|
122
|
+
const md = readFileSync(indexFile, 'utf8');
|
|
123
|
+
const sectionRe = new RegExp(`(^## ${escapeRe(sectionHeading)}\\n)([\\s\\S]*?)(?=^## |\\Z)`, 'm');
|
|
124
|
+
const m = sectionRe.exec(md);
|
|
125
|
+
const sep = style === '—' ? ' — ' : ': ';
|
|
126
|
+
const entry = `- [[${title}]]${sep}${type}\n`;
|
|
127
|
+
let next;
|
|
128
|
+
if (m) {
|
|
129
|
+
const body = m[2];
|
|
130
|
+
if (body.includes(`[[${title}]]`))
|
|
131
|
+
return; // already present
|
|
132
|
+
next = md.replace(m[0], m[1] + body + entry + m[3]);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
next = md + `\n## ${sectionHeading}\n\n` + entry;
|
|
136
|
+
}
|
|
137
|
+
writeFileSync(indexFile, next);
|
|
138
|
+
}
|
|
139
|
+
export function appendLog(logFile, line) {
|
|
140
|
+
if (!existsSync(dirname(logFile))) {
|
|
141
|
+
mkdirSync(dirname(logFile), { recursive: true });
|
|
142
|
+
}
|
|
143
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
144
|
+
let md = existsSync(logFile) ? readFileSync(logFile, 'utf8') : `# Log\n\n`;
|
|
145
|
+
if (!md.startsWith(`## ${today}`)) {
|
|
146
|
+
md = `## ${today}\n\n` + md.replace(/^# Log\n\n/, '');
|
|
147
|
+
}
|
|
148
|
+
md = `- ${new Date().toISOString()} — ${line}\n` + md;
|
|
149
|
+
writeFileSync(logFile, md);
|
|
150
|
+
}
|
|
151
|
+
export function safeFilename(title) {
|
|
152
|
+
return title.replace(/[\\/]/g, '-').replace(/[<>:"?*|]/g, '').trim() || 'untitled';
|
|
153
|
+
}
|
|
154
|
+
// typeFolders values are RELATIVE TO vaultPath (they already include the
|
|
155
|
+
// leading `wiki/` segment), e.g. `resource` → `wiki/resources`. Route against
|
|
156
|
+
// vaultPath directly — never against wikiDir, which would double the `wiki/`.
|
|
157
|
+
export function routePageFolder(vaultPath, layout, type) {
|
|
158
|
+
const folder = layout.typeFolders[type] ?? layout.typeFolders['resource'];
|
|
159
|
+
return join(vaultPath, folder);
|
|
160
|
+
}
|
|
161
|
+
export function collectUnresolvedLinks(body, knownTitles) {
|
|
162
|
+
const linkRe = /\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/g;
|
|
163
|
+
const out = [];
|
|
164
|
+
const seen = new Set();
|
|
165
|
+
for (const m of body.matchAll(linkRe)) {
|
|
166
|
+
const t = m[1].trim();
|
|
167
|
+
if (knownTitles.has(t) || seen.has(t))
|
|
168
|
+
continue;
|
|
169
|
+
seen.add(t);
|
|
170
|
+
out.push(t);
|
|
171
|
+
}
|
|
172
|
+
return out;
|
|
173
|
+
}
|
|
174
|
+
export function listAllTitles(wikiDir) {
|
|
175
|
+
const titles = new Set();
|
|
176
|
+
if (!existsSync(wikiDir))
|
|
177
|
+
return titles;
|
|
178
|
+
for (const f of walkMd(wikiDir)) {
|
|
179
|
+
const base = basename(f, extname(f));
|
|
180
|
+
if (!isMachineryPage(base))
|
|
181
|
+
titles.add(base);
|
|
182
|
+
}
|
|
183
|
+
return titles;
|
|
184
|
+
}
|
|
185
|
+
export function sha256(s) {
|
|
186
|
+
return createHash('sha256').update(s).digest('hex');
|
|
187
|
+
}
|
|
188
|
+
export function writePage(vaultPath, config, args) {
|
|
189
|
+
const layout = resolveLayout(vaultPath, config);
|
|
190
|
+
const filename = safeFilename(args.title);
|
|
191
|
+
if (isMachineryPage(filename)) {
|
|
192
|
+
throw new Error(`refusing to write machinery page: ${filename}`);
|
|
193
|
+
}
|
|
194
|
+
if (!isPortableFilename(filename)) {
|
|
195
|
+
throw new Error(`non-portable filename: ${filename}`);
|
|
196
|
+
}
|
|
197
|
+
const folder = routePageFolder(vaultPath, layout, args.type);
|
|
198
|
+
assertInsideVault(vaultPath, folder);
|
|
199
|
+
if (!existsSync(folder))
|
|
200
|
+
mkdirSync(folder, { recursive: true });
|
|
201
|
+
const targetPath = join(folder, `${filename}.md`);
|
|
202
|
+
// filename-uniqueness guard
|
|
203
|
+
if (existsSync(targetPath) && args.title !== basename(targetPath, '.md')) {
|
|
204
|
+
throw new Error(`filename collision: ${targetPath}`);
|
|
205
|
+
}
|
|
206
|
+
// source hash + skip-on-unchanged
|
|
207
|
+
let sourceHash;
|
|
208
|
+
if (args.source_path) {
|
|
209
|
+
if (!existsSync(args.source_path)) {
|
|
210
|
+
throw new Error(`source not found: ${args.source_path}`);
|
|
211
|
+
}
|
|
212
|
+
sourceHash = sha256(readFileSync(args.source_path));
|
|
213
|
+
}
|
|
214
|
+
// parse existing page (if any) to preserve `created` and unknown fields
|
|
215
|
+
const existing = existsSync(targetPath)
|
|
216
|
+
? parseFrontmatter(readFileSync(targetPath, 'utf8'))
|
|
217
|
+
: { fm: {}, body: '' };
|
|
218
|
+
if (existing.fm.source_hash && sourceHash && existing.fm.source_hash === sourceHash && !args.force) {
|
|
219
|
+
return { path: targetPath, unresolvedLinks: [], sourceHash, skipped: true };
|
|
220
|
+
}
|
|
221
|
+
const fm = completeFrontmatter(existing.fm, {
|
|
222
|
+
title: args.title,
|
|
223
|
+
type: args.type,
|
|
224
|
+
tags: args.tags,
|
|
225
|
+
source: args.source_path,
|
|
226
|
+
source_hash: sourceHash,
|
|
227
|
+
});
|
|
228
|
+
const final = serializeFrontmatter(fm) + args.content;
|
|
229
|
+
writeFileSync(targetPath, final, 'utf8');
|
|
230
|
+
// index & log
|
|
231
|
+
const sectionHeading = layout.typeFolders[args.type]?.replace(/^wiki\//, '') ?? args.type;
|
|
232
|
+
upsertIndexEntry(layout.indexFile, args.type, sectionHeading, args.title);
|
|
233
|
+
appendLog(layout.logFile, `${args.type} [[${args.title}]]${args.source_path ? ` (source ${args.source_path})` : ''}`);
|
|
234
|
+
// forward-link report
|
|
235
|
+
const titles = listAllTitles(layout.wikiDir);
|
|
236
|
+
titles.add(args.title);
|
|
237
|
+
const unresolvedLinks = collectUnresolvedLinks(args.content, titles);
|
|
238
|
+
return { path: targetPath, unresolvedLinks, sourceHash };
|
|
239
|
+
}
|
|
240
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
241
|
+
// Page rename with machinery protection
|
|
242
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
243
|
+
export function renamePage(vaultPath, config, oldTitle, newTitle) {
|
|
244
|
+
const layout = resolveLayout(vaultPath, config);
|
|
245
|
+
const oldName = safeFilename(oldTitle);
|
|
246
|
+
const newName = safeFilename(newTitle);
|
|
247
|
+
if (isMachineryPage(oldName) || isMachineryPage(newName)) {
|
|
248
|
+
throw new Error('refusing to rename machinery page');
|
|
249
|
+
}
|
|
250
|
+
if (!isPortableFilename(newName)) {
|
|
251
|
+
throw new Error(`non-portable filename: ${newName}`);
|
|
252
|
+
}
|
|
253
|
+
// Locate the existing page across every effective type folder.
|
|
254
|
+
let from;
|
|
255
|
+
for (const type of Object.keys(layout.typeFolders)) {
|
|
256
|
+
const dir = routePageFolder(vaultPath, layout, type);
|
|
257
|
+
const candidate = join(dir, `${oldName}.md`);
|
|
258
|
+
if (existsSync(candidate)) {
|
|
259
|
+
from = candidate;
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (!from)
|
|
264
|
+
throw new Error(`not found: ${oldTitle}`);
|
|
265
|
+
const toDir = dirname(from);
|
|
266
|
+
const to = join(toDir, `${newName}.md`);
|
|
267
|
+
if (existsSync(to))
|
|
268
|
+
throw new Error(`target exists: ${to}`);
|
|
269
|
+
renameSync(from, to);
|
|
270
|
+
return { from, to };
|
|
271
|
+
}
|
|
272
|
+
export function deletePage(vaultPath, config, title) {
|
|
273
|
+
const layout = resolveLayout(vaultPath, config);
|
|
274
|
+
const name = safeFilename(title);
|
|
275
|
+
if (isMachineryPage(name))
|
|
276
|
+
throw new Error('refusing to delete machinery page');
|
|
277
|
+
// search in all effective typeFolders
|
|
278
|
+
for (const type of Object.keys(layout.typeFolders)) {
|
|
279
|
+
const p = join(routePageFolder(vaultPath, layout, type), `${name}.md`);
|
|
280
|
+
if (existsSync(p)) {
|
|
281
|
+
unlinkSync(p);
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
throw new Error(`not found: ${title}`);
|
|
286
|
+
}
|
|
287
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
288
|
+
// Walk helpers
|
|
289
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
290
|
+
export function* walkMd(root) {
|
|
291
|
+
if (!existsSync(root))
|
|
292
|
+
return;
|
|
293
|
+
for (const entry of readdirSync(root)) {
|
|
294
|
+
const p = join(root, entry);
|
|
295
|
+
let st;
|
|
296
|
+
try {
|
|
297
|
+
st = statSync(p);
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
if (st.isDirectory()) {
|
|
303
|
+
if (entry === 'meta' || entry.startsWith('.'))
|
|
304
|
+
continue;
|
|
305
|
+
yield* walkMd(p);
|
|
306
|
+
}
|
|
307
|
+
else if (st.isFile() && p.endsWith('.md')) {
|
|
308
|
+
yield p;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function escapeRe(s) {
|
|
313
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
314
|
+
}
|
|
315
|
+
//# sourceMappingURL=vault.js.map
|
package/lib/vault.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vault.js","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,UAAU,EACV,YAAY,EACZ,aAAa,EACb,WAAW,EACX,QAAQ,EACR,SAAS,EACT,UAAU,EACV,UAAU,GACX,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIzC,iFAAiF;AACjF,gDAAgD;AAChD,iFAAiF;AAEjF,MAAM,oBAAoB,GAA2B;IACnD,MAAM,EAAE,YAAY;IACpB,IAAI,EAAE,YAAY;IAClB,OAAO,EAAE,eAAe;IACxB,QAAQ,EAAE,gBAAgB;IAC1B,MAAM,EAAE,cAAc;IACtB,OAAO,EAAE,cAAc;IACvB,KAAK,EAAE,MAAM;IACb,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,MAAM;CACZ,CAAC;AAYF,MAAM,UAAU,aAAa,CAAC,SAAiB,EAAE,MAAoB;IACnE,MAAM,WAAW,GAAG,EAAE,GAAG,oBAAoB,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC,EAAE,CAAC;IAC/E,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC;QAChC,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC;QAC/B,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC;QACxC,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC;QAC9C,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC;QAC1C,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC;QAC1C,WAAW;KACZ,CAAC;AACJ,CAAC;AAED,iFAAiF;AACjF,gEAAgE;AAChE,iFAAiF;AAEjF,MAAM,qBAAqB,GAAG,wCAAwC,CAAC;AACvE,MAAM,kBAAkB,GAAG,aAAa,CAAC;AACzC,MAAM,iBAAiB,GAAG,QAAQ,CAAC;AAEnC,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,0EAA0E;IAC1E,OAAO,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,IAAI,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACnD,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAChD,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,iBAAiB,CAAC,SAAiB,EAAE,MAAc;IACjE,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,IAAI,GAAG,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,uBAAuB,MAAM,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAiBD,MAAM,KAAK,GAAG,0BAA0B,CAAC;AAEzC,MAAM,UAAU,gBAAgB,CAAC,EAAU;IACzC,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzB,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IACpC,MAAM,EAAE,GAAgB,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,GAAG,GAAG,CAAC;YAAE,SAAS;QACtB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,GAAG,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACxE,0DAA0D;YAC1D,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC7G,CAAC;aAAM,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YACnC,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;QACxC,CAAC;QACD,EAAE,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IAChB,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,EAAe;IAClD,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC;IACtB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;QACxC,IAAI,CAAC,KAAK,SAAS;YAAE,SAAS;QAC9B,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACrB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC3C,CAAC;aAAM,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAC3E,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QAClD,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACtB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,QAAqB,EACrB,KAA2B,EAC3B,MAAc,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;IAEnD,MAAM,MAAM,GAAgB,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,EAAE,CAAC;IACtD,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,MAAM,CAAC,OAAO,GAAG,QAAQ,CAAC,OAAO,IAAI,GAAG,CAAC;IAC9D,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC;IACrB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,iFAAiF;AACjF,gCAAgC;AAChC,iFAAiF;AAEjF,MAAM,UAAU,gBAAgB,CAC9B,SAAiB,EACjB,IAAY,EACZ,cAAsB,EACtB,KAAa,EACb,QAAmB,GAAG;IAEtB,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,aAAa,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,EAAE,GAAG,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,IAAI,MAAM,CAAC,QAAQ,QAAQ,CAAC,cAAc,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;IAClG,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7B,MAAM,GAAG,GAAG,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACzC,MAAM,KAAK,GAAG,OAAO,KAAK,KAAK,GAAG,GAAG,IAAI,IAAI,CAAC;IAC9C,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC;QACN,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,KAAK,IAAI,CAAC;YAAE,OAAO,CAAC,kBAAkB;QAC7D,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,CAAC;SAAM,CAAC;QACN,IAAI,GAAG,EAAE,GAAG,QAAQ,cAAc,MAAM,GAAG,KAAK,CAAC;IACnD,CAAC;IACD,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,IAAY;IACrD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QAClC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACpD,IAAI,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;IAC3E,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,KAAK,EAAE,CAAC,EAAE,CAAC;QAClC,EAAE,GAAG,MAAM,KAAK,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,EAAE,GAAG,KAAK,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,IAAI,IAAI,GAAG,EAAE,CAAC;IACtD,aAAa,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAC7B,CAAC;AAsBD,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,UAAU,CAAC;AACrF,CAAC;AAED,yEAAyE;AACzE,8EAA8E;AAC9E,8EAA8E;AAC9E,MAAM,UAAU,eAAe,CAAC,SAAiB,EAAE,MAAmB,EAAE,IAAY;IAClF,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC,UAAU,CAAE,CAAC;IAC3E,OAAO,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAY,EAAE,WAAwB;IAC3E,MAAM,MAAM,GAAG,iCAAiC,CAAC;IACjD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC;QACvB,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,SAAS;QAChD,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACZ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACd,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IACjC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,MAAM,CAAC;IACxC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACrC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,CAAkB;IACvC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,SAAS,CACvB,SAAiB,EACjB,MAAoB,EACpB,IAAmB;IAEnB,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,qCAAqC,QAAQ,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,MAAM,GAAG,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7D,iBAAiB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACrC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEhE,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,QAAQ,KAAK,CAAC,CAAC;IAElD,4BAA4B;IAC5B,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC;QACzE,MAAM,IAAI,KAAK,CAAC,uBAAuB,UAAU,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,kCAAkC;IAClC,IAAI,UAA8B,CAAC;IACnC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAC3D,CAAC;QACD,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,wEAAwE;IACxE,MAAM,QAAQ,GAAG,UAAU,CAAC,UAAU,CAAC;QACrC,CAAC,CAAC,gBAAgB,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACpD,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IAEzB,IAAI,QAAQ,CAAC,EAAE,CAAC,WAAW,IAAI,UAAU,IAAI,QAAQ,CAAC,EAAE,CAAC,WAAW,KAAK,UAAU,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QACnG,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,eAAe,EAAE,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC9E,CAAC;IAED,MAAM,EAAE,GAAG,mBAAmB,CAAC,QAAQ,CAAC,EAAE,EAAE;QAC1C,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,MAAM,EAAE,IAAI,CAAC,WAAW;QACxB,WAAW,EAAE,UAAU;KACxB,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,oBAAoB,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;IACtD,aAAa,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAEzC,cAAc;IACd,MAAM,cAAc,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC;IAC1F,gBAAgB,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1E,SAAS,CACP,MAAM,CAAC,OAAO,EACd,GAAG,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAC3F,CAAC;IAEF,sBAAsB;IACtB,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvB,MAAM,eAAe,GAAG,sBAAsB,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAErE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,CAAC;AAC3D,CAAC;AAED,iFAAiF;AACjF,wCAAwC;AACxC,iFAAiF;AAEjF,MAAM,UAAU,UAAU,CACxB,SAAiB,EACjB,MAAoB,EACpB,QAAgB,EAChB,QAAgB;IAEhB,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,eAAe,CAAC,OAAO,CAAC,IAAI,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,0BAA0B,OAAO,EAAE,CAAC,CAAC;IACvD,CAAC;IACD,+DAA+D;IAC/D,IAAI,IAAwB,CAAC;IAC7B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;QACnD,MAAM,GAAG,GAAG,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;QACrD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,KAAK,CAAC,CAAC;QAC7C,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAAC,IAAI,GAAG,SAAS,CAAC;YAAC,MAAM;QAAC,CAAC;IACzD,CAAC;IACD,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,cAAc,QAAQ,EAAE,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,OAAO,KAAK,CAAC,CAAC;IACxC,IAAI,UAAU,CAAC,EAAE,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;IAC5D,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACrB,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,SAAiB,EAAE,MAAoB,EAAE,KAAa;IAC/E,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACjC,IAAI,eAAe,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAChF,sCAAsC;IACtC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;QACnD,MAAM,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC;QACvE,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;IAC/C,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,cAAc,KAAK,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,iFAAiF;AACjF,eAAe;AACf,iFAAiF;AAEjF,MAAM,SAAS,CAAC,CAAC,MAAM,CAAC,IAAY;IAClC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO;IAC9B,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC5B,IAAI,EAAE,CAAC;QACP,IAAI,CAAC;YAAC,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,SAAS;QAAC,CAAC;QAC7C,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;YACrB,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAS;YACxD,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACnB,CAAC;aAAM,IAAI,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5C,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,CAAS;IACzB,OAAO,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@qiqiangvae/dsh-obsidian",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Self-organizing AI second brain for Obsidian, as a single DeepSeek Harness plugin. Merged fork of dsh-plugin-wiki-skills + dsh-plugin-wiki-tools, targeting parity with claude-obsidian.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"types": "index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./index.js",
|
|
10
|
+
"./lib/vault.js": "./lib/vault.js",
|
|
11
|
+
"./lib/search.js": "./lib/search.js",
|
|
12
|
+
"./lib/lint.js": "./lib/lint.js",
|
|
13
|
+
"./lib/scaffold.js": "./lib/scaffold.js",
|
|
14
|
+
"./lib/skills.js": "./lib/skills.js",
|
|
15
|
+
"./lib/types.js": "./lib/types.js",
|
|
16
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
17
|
+
"./package.json": "./package.json"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"index.js",
|
|
21
|
+
"lib/",
|
|
22
|
+
"cordis.patch.yml",
|
|
23
|
+
"skills/",
|
|
24
|
+
"README.md",
|
|
25
|
+
"LICENSE",
|
|
26
|
+
"ATTRIBUTION.md"
|
|
27
|
+
],
|
|
28
|
+
"keywords": [
|
|
29
|
+
"dsh-plugin",
|
|
30
|
+
"deepseek-harness",
|
|
31
|
+
"obsidian",
|
|
32
|
+
"knowledge-base",
|
|
33
|
+
"second-brain",
|
|
34
|
+
"llm-wiki"
|
|
35
|
+
],
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/qiqiangvae/dsh-obsidian.git"
|
|
39
|
+
},
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=22.19.0"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"@deepseek-ai/cordis": "*",
|
|
46
|
+
"@deepseek-ai/dsh-tools": "*",
|
|
47
|
+
"@deepseek-ai/schemastery": "*"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"test": "node --test test/basic.test.mjs test/apply.smoke.test.mjs",
|
|
51
|
+
"build": "tsc -p tsconfig.json",
|
|
52
|
+
"prepublishOnly": "npm run build"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"typescript": "^5.5.0",
|
|
56
|
+
"@types/node": "^20.0.0",
|
|
57
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
58
|
+
"@deepseek-ai/dsh-tools": "^0.0.1-rc.1",
|
|
59
|
+
"@deepseek-ai/schemastery": "^3.18.1"
|
|
60
|
+
},
|
|
61
|
+
"dsh": {
|
|
62
|
+
"bundle": {
|
|
63
|
+
"patch": "./cordis.patch.yml"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: defuddle
|
|
3
|
+
description: Extract clean markdown from a web page (article, blog post, doc page) by stripping nav, ads, cookie banners, and chrome. Use before ingesting a URL into the vault, to save tokens and keep the source readable.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# defuddle
|
|
7
|
+
|
|
8
|
+
Clean a web page down to its article body.
|
|
9
|
+
|
|
10
|
+
## When to use
|
|
11
|
+
|
|
12
|
+
- Before any URL ingestion via `wiki-ingest`, prefer running the URL through
|
|
13
|
+
defuddle-style extraction.
|
|
14
|
+
- The actual extraction is done by the [Defuddle](https://github.com/kepano/defuddle)
|
|
15
|
+
CLI / npm package. The skill's job is to *instruct* the agent to call it.
|
|
16
|
+
|
|
17
|
+
## Workflow
|
|
18
|
+
|
|
19
|
+
1. Fetch the URL. If the response is already markdown, skip defuddle.
|
|
20
|
+
2. Otherwise, run `npx defuddle <url>` (or the equivalent in your runtime).
|
|
21
|
+
3. Hand the cleaned markdown to `wiki-ingest` to write a `resource` page.
|
|
22
|
+
|
|
23
|
+
## What defuddle removes
|
|
24
|
+
|
|
25
|
+
- Nav, header, footer
|
|
26
|
+
- Cookie / GDPR banners
|
|
27
|
+
- Sidebars, related-article blocks
|
|
28
|
+
- Most ads and trackers
|
|
29
|
+
|
|
30
|
+
## What it preserves
|
|
31
|
+
|
|
32
|
+
- Article title (h1)
|
|
33
|
+
- Author and date metadata
|
|
34
|
+
- Headings, paragraphs, lists, code blocks
|
|
35
|
+
- Images (with src intact)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: json-canvas
|
|
3
|
+
description: Create and edit JSON Canvas (.canvas) files: nodes (text, file, link, group), edges, and layout. Use to produce visual mind-maps, knowledge graphs, or workflow diagrams from vault content.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# json-canvas
|
|
7
|
+
|
|
8
|
+
JSON Canvas is an open spec (https://jsoncanvas.org). Obsidian Canvas reads
|
|
9
|
+
these files. Other readers: Kinopio, Jiyuu.
|
|
10
|
+
|
|
11
|
+
## Schema (1.0)
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"nodes": [
|
|
16
|
+
{
|
|
17
|
+
"id": "uuid-or-string",
|
|
18
|
+
"type": "text",
|
|
19
|
+
"x": 0, "y": 0, "width": 250, "height": 100,
|
|
20
|
+
"label": "Optional",
|
|
21
|
+
"text": "# Heading\nMarkdown body"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": "uuid-or-string",
|
|
25
|
+
"type": "file",
|
|
26
|
+
"x": 300, "y": 0, "width": 250, "height": 100,
|
|
27
|
+
"file": "Notes/My Note.md"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "uuid-or-string",
|
|
31
|
+
"type": "link",
|
|
32
|
+
"x": 600, "y": 0, "width": 250, "height": 100,
|
|
33
|
+
"url": "https://example.com"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"id": "uuid-or-string",
|
|
37
|
+
"type": "group",
|
|
38
|
+
"x": 0, "y": 150, "width": 500, "height": 200,
|
|
39
|
+
"label": "Cluster",
|
|
40
|
+
"color": "1"
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"edges": [
|
|
44
|
+
{
|
|
45
|
+
"id": "edge-1",
|
|
46
|
+
"fromNode": "uuid-1",
|
|
47
|
+
"fromSide": "right",
|
|
48
|
+
"toNode": "uuid-2",
|
|
49
|
+
"toSide": "left",
|
|
50
|
+
"label": "links to"
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Tips
|
|
57
|
+
|
|
58
|
+
- Generate `id`s as stable strings; downstream tools dedupe on them.
|
|
59
|
+
- Coordinates: pixel units; Obsidian's default zoom fits 100×100.
|
|
60
|
+
- For "graph from vault wikilinks", walk pages, build nodes per title,
|
|
61
|
+
and add an edge for each `[[link]]` occurrence.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: obsidian-bases
|
|
3
|
+
description: Create and edit Obsidian Bases (.base) with views, filters, formulas, and summaries. Use when the user asks for a tabular view, a project dashboard, or a filtered list of pages by property.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# obsidian-bases
|
|
7
|
+
|
|
8
|
+
Obsidian Bases are `.base` YAML files in the vault root (or anywhere).
|
|
9
|
+
|
|
10
|
+
## Minimal example
|
|
11
|
+
|
|
12
|
+
```yaml
|
|
13
|
+
title: Projects
|
|
14
|
+
filter:
|
|
15
|
+
and:
|
|
16
|
+
- type == "project"
|
|
17
|
+
views:
|
|
18
|
+
- type: table
|
|
19
|
+
name: Active
|
|
20
|
+
filter:
|
|
21
|
+
and:
|
|
22
|
+
- status == "active"
|
|
23
|
+
order:
|
|
24
|
+
- file.name
|
|
25
|
+
- due
|
|
26
|
+
- status
|
|
27
|
+
- type: cards
|
|
28
|
+
name: By status
|
|
29
|
+
groupBy: status
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Common formula patterns
|
|
33
|
+
|
|
34
|
+
```yaml
|
|
35
|
+
formulas:
|
|
36
|
+
days_to_due: (date(prop("due")) - today()) / 86400000
|
|
37
|
+
is_overdue: (date(prop("due")) < today()) && (prop("status") != "done")
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Common gotchas
|
|
41
|
+
|
|
42
|
+
- Property names with spaces must be quoted: `prop("Project Status")`.
|
|
43
|
+
- `today()` is midnight UTC; for day-level comparisons use
|
|
44
|
+
`date(prop("due")) < today()` rather than raw string compare.
|
|
45
|
+
- `groupBy` on a missing property silently groups everything into `null`.
|
|
46
|
+
|
|
47
|
+
## When to use
|
|
48
|
+
|
|
49
|
+
- A "Project dashboard" → `groupBy: status, orderBy: due`
|
|
50
|
+
- A "Reading list" → `filter: type == "resource" && status == "to-read"`
|
|
51
|
+
- A "By author" view → `groupBy: author`
|