@novis10813/secondbrain-cli 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -81
- package/dist/commands/backlinks.d.ts.map +1 -1
- package/dist/commands/backlinks.js +16 -33
- package/dist/commands/backlinks.js.map +1 -1
- package/dist/commands/capture.d.ts.map +1 -1
- package/dist/commands/capture.js +71 -57
- package/dist/commands/capture.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +5 -20
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/get.js +27 -26
- package/dist/commands/get.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +21 -4
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/migrate.d.ts +3 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +22 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/open.d.ts +3 -0
- package/dist/commands/open.d.ts.map +1 -0
- package/dist/commands/open.js +28 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/orphans.d.ts.map +1 -1
- package/dist/commands/orphans.js +9 -27
- package/dist/commands/orphans.js.map +1 -1
- package/dist/commands/outlinks.d.ts +3 -0
- package/dist/commands/outlinks.d.ts.map +1 -0
- package/dist/commands/outlinks.js +48 -0
- package/dist/commands/outlinks.js.map +1 -0
- package/dist/commands/search.d.ts +2 -0
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +57 -39
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/stats.d.ts.map +1 -1
- package/dist/commands/stats.js +4 -18
- package/dist/commands/stats.js.map +1 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +3 -17
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/template.d.ts +3 -0
- package/dist/commands/template.d.ts.map +1 -0
- package/dist/commands/template.js +63 -0
- package/dist/commands/template.js.map +1 -0
- package/dist/commands/vault.d.ts +3 -0
- package/dist/commands/vault.d.ts.map +1 -0
- package/dist/commands/vault.js +233 -0
- package/dist/commands/vault.js.map +1 -0
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +134 -10
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/config.d.ts +3 -1
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +12 -0
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/database.d.ts +58 -14
- package/dist/utils/database.d.ts.map +1 -1
- package/dist/utils/database.js +627 -207
- package/dist/utils/database.js.map +1 -1
- package/dist/utils/global-config.d.ts +53 -0
- package/dist/utils/global-config.d.ts.map +1 -0
- package/dist/utils/global-config.js +144 -0
- package/dist/utils/global-config.js.map +1 -0
- package/dist/utils/parser.d.ts +95 -2
- package/dist/utils/parser.d.ts.map +1 -1
- package/dist/utils/parser.js +466 -39
- package/dist/utils/parser.js.map +1 -1
- package/dist/utils/placeholder.d.ts +37 -0
- package/dist/utils/placeholder.d.ts.map +1 -0
- package/dist/utils/placeholder.js +113 -0
- package/dist/utils/placeholder.js.map +1 -0
- package/dist/utils/position.d.ts +10 -0
- package/dist/utils/position.d.ts.map +1 -0
- package/dist/utils/position.js +24 -0
- package/dist/utils/position.js.map +1 -0
- package/dist/utils/sqlite-adapter.d.ts +8 -0
- package/dist/utils/sqlite-adapter.d.ts.map +1 -0
- package/dist/utils/sqlite-adapter.js +14 -0
- package/dist/utils/sqlite-adapter.js.map +1 -0
- package/dist/utils/template.d.ts +2 -2
- package/dist/utils/template.d.ts.map +1 -1
- package/dist/utils/template.js +8 -3
- package/dist/utils/template.js.map +1 -1
- package/dist/utils/vault-resolve.d.ts +23 -0
- package/dist/utils/vault-resolve.d.ts.map +1 -0
- package/dist/utils/vault-resolve.js +86 -0
- package/dist/utils/vault-resolve.js.map +1 -0
- package/dist/utils/vault.d.ts +77 -10
- package/dist/utils/vault.d.ts.map +1 -1
- package/dist/utils/vault.js +262 -98
- package/dist/utils/vault.js.map +1 -1
- package/package.json +9 -3
package/README.md
CHANGED
|
@@ -1,133 +1,123 @@
|
|
|
1
|
-
|
|
1
|
+
## SecondBrain CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
SecondBrain CLI is a command-line tool for LLM agents and power users to work with Obsidian
|
|
4
|
+
vaults. It keeps your vault fully compatible with Obsidian while providing a fast SQLite index
|
|
5
|
+
and JSON-friendly APIs.
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
For a Chinese version of this document, see `README_zh.md`.
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
- **完整的連結系統**: 支援 `[[wikilinks]]`、backlinks、orphans 偵測
|
|
9
|
-
- **Agent-First 設計**: JSON 輸出、結構化資料、CLI 可 pipe
|
|
10
|
-
- **Obsidian 相容**: 100% 相容現有 Obsidian vault
|
|
11
|
-
- **標準化 Capture**: Template 系統強制 Agent 遵守格式
|
|
9
|
+
## Features
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
- **Dual-storage architecture**: SQLite index + raw Markdown files (never rewrites your notes)
|
|
12
|
+
- **Rich link system**: `[[wikilinks]]`, backlinks, outlinks, orphan detection
|
|
13
|
+
- **Agent-first design**: JSON output, structured data, easy to pipe and script
|
|
14
|
+
- **Obsidian compatibility**: Aligned with TFile / CachedMetadata, safe to use on existing vaults
|
|
15
|
+
- **Standardized capture**: Template system that enforces consistent note formats
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
14
18
|
|
|
15
19
|
```bash
|
|
16
|
-
# npm registry(公開套件)
|
|
17
20
|
npm install -g @novis10813/secondbrain-cli
|
|
18
21
|
```
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
如果你用 `bun` 從 GitHub 安裝並看到 `Blocked ... postinstall/prepare`,需要先信任再重裝一次:
|
|
23
|
+
- **Runtime**: Node.js 18+ (required)
|
|
24
|
+
- **Optional**: Bun for local development and tests (`bun test`, `bun run dev`)
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
bun pm -g trust @novis10813/secondbrain-cli
|
|
26
|
-
bun add -g github:novis10813/secondbrain-cli#<tag>
|
|
27
|
-
```
|
|
26
|
+
After global install you can use the `sb` binary from anywhere.
|
|
28
27
|
|
|
29
|
-
##
|
|
28
|
+
## Quick start
|
|
30
29
|
|
|
31
30
|
```bash
|
|
32
|
-
#
|
|
31
|
+
# 1) Initialize in an existing Obsidian vault
|
|
33
32
|
cd ~/my-obsidian-vault
|
|
34
33
|
sb init
|
|
35
34
|
|
|
36
|
-
#
|
|
35
|
+
# 2) Index existing notes into SQLite
|
|
37
36
|
sb sync
|
|
38
37
|
|
|
39
|
-
#
|
|
40
|
-
sb capture "
|
|
38
|
+
# 3) Capture a new note with title and tags
|
|
39
|
+
sb capture "This is the note content" \
|
|
40
|
+
--title="My note" \
|
|
41
|
+
--tags="idea,work"
|
|
42
|
+
|
|
43
|
+
# 4) Search notes (JSON output for agents)
|
|
44
|
+
sb search "API design" --tags="tech" --format=json
|
|
41
45
|
|
|
42
|
-
#
|
|
43
|
-
sb
|
|
46
|
+
# 5) Backlinks and outlinks
|
|
47
|
+
sb backlinks <path-or-id>
|
|
48
|
+
sb outlinks <path-or-id>
|
|
44
49
|
|
|
45
|
-
#
|
|
46
|
-
sb
|
|
50
|
+
# 6) Resolve linkpaths to path:line:col (for editors)
|
|
51
|
+
sb open "My Note#Section"
|
|
47
52
|
|
|
48
|
-
#
|
|
53
|
+
# 7) Find orphan notes (no links in or out)
|
|
49
54
|
sb orphans
|
|
50
55
|
```
|
|
51
56
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
### 初始化與設定
|
|
57
|
+
`<path-or-id>` accepts either a relative path inside the vault (e.g. `Projects/api-design.md`) or
|
|
58
|
+
a basename that can be resolved uniquely.
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
sb init # 初始化 vault
|
|
58
|
-
sb config list # 查看設定
|
|
59
|
-
sb config get dailyNotesFolder # 取得特定設定
|
|
60
|
-
sb config set dailyNotesFolder Daily # 修改設定
|
|
61
|
-
```
|
|
60
|
+
## CLI overview
|
|
62
61
|
|
|
63
|
-
|
|
62
|
+
SecondBrain CLI groups commands into a few core utilities. Each has its own usage guide under
|
|
63
|
+
`docs/`:
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
sb search
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
sb
|
|
78
|
-
|
|
65
|
+
- **Vault management**: `sb vault ...` — multi-vault registry and active vault selection
|
|
66
|
+
See `docs/vault.md`.
|
|
67
|
+
- **Sync**: `sb sync` — scan Markdown files, parse, and update the SQLite index
|
|
68
|
+
See `docs/sync.md`.
|
|
69
|
+
- **Capture & templates**: `sb capture`, `sb template ...` — create notes and enforce formats
|
|
70
|
+
See `docs/capture.md` and `docs/template.md`.
|
|
71
|
+
- **Search**: `sb search` — query by name, tags, path prefix, links, headings, modification time
|
|
72
|
+
See `docs/search.md`.
|
|
73
|
+
- **Links & navigation**: `sb backlinks`, `sb outlinks`, `sb open` — link graph and positions
|
|
74
|
+
See `docs/backlinks.md` and `docs/open.md`.
|
|
75
|
+
- **Note access**: `sb get` — retrieve a note's content and metadata by path or basename
|
|
76
|
+
See `docs/get.md`.
|
|
77
|
+
- **Config & maintenance**: `sb config`, `sb stats`, `sb orphans`, `sb migrate`
|
|
78
|
+
See `docs/config.md`, `docs/stats.md`, and `docs/migrate.md`.
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
For a full command and module reference, see `docs/modules.md`.
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
sb sync # 同步索引
|
|
84
|
-
sb stats # 統計資訊
|
|
85
|
-
sb orphans # 孤兒筆記
|
|
86
|
-
```
|
|
82
|
+
## Data layout
|
|
87
83
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
```
|
|
84
|
+
```text
|
|
91
85
|
/your-vault/
|
|
92
86
|
├── Projects/
|
|
93
|
-
│ └── api-design.md
|
|
87
|
+
│ └── api-design.md # Raw Markdown files (Obsidian-compatible)
|
|
94
88
|
├── Daily/
|
|
95
89
|
│ └── 2024-01-15.md
|
|
96
90
|
└── .secondbrain/
|
|
97
|
-
├── config.json
|
|
98
|
-
└── index.db
|
|
91
|
+
├── config.json # Vault config (paths, folders, DB path)
|
|
92
|
+
└── index.db # SQLite index (files + metadata)
|
|
99
93
|
```
|
|
100
94
|
|
|
101
|
-
|
|
95
|
+
The CLI reads and writes only inside the vault and `.secondbrain/` directory. Note content is
|
|
96
|
+
never rewritten except when you explicitly create notes via `sb capture` or templates.
|
|
97
|
+
|
|
98
|
+
## Development
|
|
102
99
|
|
|
103
100
|
```bash
|
|
104
|
-
#
|
|
101
|
+
# Install dependencies
|
|
105
102
|
bun install
|
|
106
103
|
|
|
107
|
-
#
|
|
104
|
+
# Run from source
|
|
108
105
|
bun run dev
|
|
109
106
|
|
|
110
|
-
#
|
|
107
|
+
# Build TypeScript to dist/
|
|
111
108
|
bun run build
|
|
112
109
|
|
|
113
|
-
#
|
|
110
|
+
# Type-check only
|
|
111
|
+
bun run lint
|
|
112
|
+
|
|
113
|
+
# Run tests
|
|
114
114
|
bun test
|
|
115
115
|
```
|
|
116
116
|
|
|
117
|
+
This repository targets Bun for development, but the published package works on standard Node.js
|
|
118
|
+
18+ environments.
|
|
119
|
+
|
|
117
120
|
## License
|
|
118
121
|
|
|
119
122
|
MIT
|
|
120
123
|
|
|
121
|
-
## 發佈(npm registry)
|
|
122
|
-
|
|
123
|
-
1) 建立 GitHub Personal Access Token(classic 或 fine-grained 皆可)
|
|
124
|
-
|
|
125
|
-
- **最低需要**: `write:packages`(發佈)、`read:packages`(安裝)
|
|
126
|
-
- 如果 repo 是 private,通常也需要能讀取 repo 的權限(依你的帳號/組織設定而定)
|
|
127
|
-
|
|
128
|
-
2) 登入 npm registry 並發佈
|
|
129
|
-
|
|
130
|
-
```bash
|
|
131
|
-
npm login
|
|
132
|
-
npm publish --access public
|
|
133
|
-
```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backlinks.d.ts","sourceRoot":"","sources":["../../src/commands/backlinks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"backlinks.d.ts","sourceRoot":"","sources":["../../src/commands/backlinks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,wBAAgB,sBAAsB,IAAI,OAAO,CA0ChD"}
|
|
@@ -2,63 +2,46 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createBacklinksCommand = createBacklinksCommand;
|
|
4
4
|
const commander_1 = require("commander");
|
|
5
|
-
const
|
|
6
|
-
const vault_js_1 = require("../utils/vault.js");
|
|
5
|
+
const vault_resolve_js_1 = require("../utils/vault-resolve.js");
|
|
7
6
|
function createBacklinksCommand() {
|
|
8
7
|
const command = new commander_1.Command('backlinks')
|
|
9
8
|
.description('Get backlinks for a note')
|
|
10
|
-
.argument('<id>', '
|
|
9
|
+
.argument('<path-or-id>', 'File path or basename')
|
|
11
10
|
.option('-f, --format <format>', 'Output format (json|text)', 'json')
|
|
12
|
-
.action((
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
.action(async (pathOrId, options) => {
|
|
12
|
+
await (0, vault_resolve_js_1.withVault)((vault) => {
|
|
13
|
+
const file = vault.resolvePathOrBasename(pathOrId);
|
|
14
|
+
const resolvedPath = file?.path ?? null;
|
|
15
|
+
if (!resolvedPath) {
|
|
16
|
+
throw new Error('Note not found');
|
|
18
17
|
}
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const vault = new vault_js_1.VaultManager(config);
|
|
22
|
-
// First check if note exists
|
|
23
|
-
const note = vault.getNoteById(id);
|
|
24
|
-
if (!note) {
|
|
25
|
-
console.error('❌ Note not found');
|
|
26
|
-
process.exit(1);
|
|
27
|
-
}
|
|
28
|
-
const backlinks = vault.getBacklinks(id);
|
|
18
|
+
const backlinks = vault.getBacklinksByPath(resolvedPath);
|
|
19
|
+
const title = file?.basename ?? resolvedPath.replace(/\.md$/, '');
|
|
29
20
|
if (options.format === 'json') {
|
|
30
21
|
console.log(JSON.stringify({
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
path: resolvedPath,
|
|
23
|
+
title,
|
|
33
24
|
backlinkCount: backlinks.length,
|
|
34
25
|
backlinks: backlinks.map(b => ({
|
|
35
|
-
id: b.id,
|
|
36
|
-
title: b.title,
|
|
37
26
|
path: b.path,
|
|
38
|
-
|
|
27
|
+
basename: b.basename
|
|
39
28
|
}))
|
|
40
29
|
}, null, 2));
|
|
41
30
|
}
|
|
42
31
|
else {
|
|
43
|
-
console.log(`Backlinks for "${
|
|
32
|
+
console.log(`Backlinks for "${title}":\n`);
|
|
44
33
|
if (backlinks.length === 0) {
|
|
45
34
|
console.log('No backlinks found');
|
|
46
35
|
}
|
|
47
36
|
else {
|
|
48
37
|
backlinks.forEach((b, i) => {
|
|
49
|
-
console.log(`${i + 1}. ${b.
|
|
38
|
+
console.log(`${i + 1}. ${b.basename}`);
|
|
50
39
|
console.log(` Path: ${b.path}`);
|
|
51
|
-
console.log(` ID: ${b.id}`);
|
|
52
40
|
console.log();
|
|
53
41
|
});
|
|
54
42
|
}
|
|
55
43
|
}
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
catch (error) {
|
|
59
|
-
console.error('❌ Failed to get backlinks:', error instanceof Error ? error.message : String(error));
|
|
60
|
-
process.exit(1);
|
|
61
|
-
}
|
|
44
|
+
});
|
|
62
45
|
});
|
|
63
46
|
return command;
|
|
64
47
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backlinks.js","sourceRoot":"","sources":["../../src/commands/backlinks.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"backlinks.js","sourceRoot":"","sources":["../../src/commands/backlinks.ts"],"names":[],"mappings":";;AAGA,wDA0CC;AA7CD,yCAAoC;AACpC,gEAAsD;AAEtD,SAAgB,sBAAsB;IACpC,MAAM,OAAO,GAAG,IAAI,mBAAO,CAAC,WAAW,CAAC;SACrC,WAAW,CAAC,0BAA0B,CAAC;SACvC,QAAQ,CAAC,cAAc,EAAE,uBAAuB,CAAC;SACjD,MAAM,CAAC,uBAAuB,EAAE,2BAA2B,EAAE,MAAM,CAAC;SACpE,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE;QAClC,MAAM,IAAA,4BAAS,EAAC,CAAC,KAAK,EAAE,EAAE;YACxB,MAAM,IAAI,GAAG,KAAK,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC;YACnD,MAAM,YAAY,GAAG,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC;YACxC,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;YACpC,CAAC;YAED,MAAM,SAAS,GAAG,KAAK,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC;YACvD,MAAM,KAAK,GAAG,IAAI,EAAE,QAAQ,IAAI,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAElE,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;oBACzB,IAAI,EAAE,YAAY;oBAClB,KAAK;oBACL,aAAa,EAAE,SAAS,CAAC,MAAM;oBAC/B,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;wBAC7B,IAAI,EAAE,CAAC,CAAC,IAAI;wBACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;qBACrB,CAAC,CAAC;iBACJ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACf,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,MAAM,CAAC,CAAC;gBAC3C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC3B,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;gBACpC,CAAC;qBAAM,CAAC;oBACN,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;wBACzB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;wBACvC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;wBAClC,OAAO,CAAC,GAAG,EAAE,CAAC;oBAChB,CAAC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEL,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/commands/capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/commands/capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,wBAAgB,oBAAoB,IAAI,OAAO,CA6G9C"}
|
package/dist/commands/capture.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createCaptureCommand = createCaptureCommand;
|
|
4
4
|
const commander_1 = require("commander");
|
|
5
|
-
const
|
|
6
|
-
const vault_js_1 = require("../utils/vault.js");
|
|
5
|
+
const vault_resolve_js_1 = require("../utils/vault-resolve.js");
|
|
7
6
|
const parser_js_1 = require("../utils/parser.js");
|
|
7
|
+
const template_js_1 = require("../utils/template.js");
|
|
8
8
|
function createCaptureCommand() {
|
|
9
9
|
const command = new commander_1.Command('capture')
|
|
10
10
|
.description('Capture a new note')
|
|
@@ -12,78 +12,92 @@ function createCaptureCommand() {
|
|
|
12
12
|
.option('-t, --title <title>', 'Note title')
|
|
13
13
|
.option('--tags <tags>', 'Comma-separated tags')
|
|
14
14
|
.option('--template <template>', 'Template name')
|
|
15
|
-
.option('--
|
|
15
|
+
.option('--var <entries...>', 'Template variables (key=value)')
|
|
16
16
|
.action(async (content, options) => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (!vaultPath) {
|
|
21
|
-
console.error('❌ Not in a SecondBrain vault. Run `sb init` first.');
|
|
22
|
-
process.exit(1);
|
|
23
|
-
}
|
|
24
|
-
const configManager = new config_js_1.ConfigManager(vaultPath);
|
|
25
|
-
const config = configManager.getConfig();
|
|
26
|
-
const vault = new vault_js_1.VaultManager(config);
|
|
27
|
-
let notePath;
|
|
17
|
+
const body = content ?? '';
|
|
18
|
+
await (0, vault_resolve_js_1.withVault)(async (vault) => {
|
|
19
|
+
let noteFolder = '';
|
|
28
20
|
let noteContent;
|
|
29
21
|
let frontmatter = {};
|
|
30
|
-
// Handle tags
|
|
31
22
|
const tags = options.tags ? options.tags.split(',').map((t) => t.trim()) : [];
|
|
32
|
-
//
|
|
23
|
+
// Parse --var key=value entries
|
|
24
|
+
const vars = {};
|
|
25
|
+
if (options.var) {
|
|
26
|
+
options.var.forEach((entry) => {
|
|
27
|
+
const [key, ...valueParts] = entry.split('=');
|
|
28
|
+
if (key) {
|
|
29
|
+
vars[key] = valueParts.join('=');
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
// 1. Resolve Template
|
|
33
34
|
if (options.template) {
|
|
34
|
-
const
|
|
35
|
-
|
|
35
|
+
const templateConfig = vault.config.templates?.[options.template];
|
|
36
|
+
if (templateConfig?.targetFolder) {
|
|
37
|
+
noteFolder = templateConfig.targetFolder;
|
|
38
|
+
}
|
|
39
|
+
const templateManager = new template_js_1.TemplateManager(vault.config);
|
|
40
|
+
const templateContent = templateManager.getTemplate(options.template);
|
|
36
41
|
if (templateContent) {
|
|
42
|
+
// Extract metadata from template for merging
|
|
37
43
|
const parsed = parser_js_1.NoteParser.parse(templateContent);
|
|
38
44
|
frontmatter = parsed.frontmatter;
|
|
39
|
-
// Merge tags
|
|
40
45
|
if (parsed.tags.length > 0) {
|
|
41
|
-
tags.push(...parsed.tags);
|
|
46
|
+
tags.push(...parsed.tags.map(t => t.name));
|
|
47
|
+
}
|
|
48
|
+
// Placeholder logic
|
|
49
|
+
const placeholders = templateManager.validateTemplate(options.template);
|
|
50
|
+
const variables = { content: body, ...vars };
|
|
51
|
+
// Check for missing variables and warn
|
|
52
|
+
placeholders.forEach(p => {
|
|
53
|
+
if (!(p in variables)) {
|
|
54
|
+
console.warn(`⚠️ Warning: Template placeholder '{{${p}}}' has no value provided, using empty string.`);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
// Check if content is provided but no {{content}} placeholder exists
|
|
58
|
+
if (body && !placeholders.includes('content')) {
|
|
59
|
+
console.warn(`⚠️ Warning: Note content was provided but no '{{content}}' placeholder exists in template '${options.template}'. Content will be ignored.`);
|
|
42
60
|
}
|
|
61
|
+
noteContent = templateManager.renderTemplate(options.template, variables);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// Fallback if template file not found
|
|
65
|
+
const title = options.title || new Date().toISOString();
|
|
66
|
+
frontmatter.tags = [...new Set(tags)];
|
|
67
|
+
noteContent = parser_js_1.NoteParser.generateNoteContent(title, body, frontmatter);
|
|
43
68
|
}
|
|
44
|
-
}
|
|
45
|
-
// Determine title
|
|
46
|
-
const title = options.title || new Date().toISOString();
|
|
47
|
-
// Determine path
|
|
48
|
-
if (options.path) {
|
|
49
|
-
notePath = options.path.endsWith('.md') ? options.path : `${options.path}.md`;
|
|
50
69
|
}
|
|
51
70
|
else {
|
|
52
|
-
//
|
|
53
|
-
const
|
|
54
|
-
|
|
71
|
+
// No template: use default generator
|
|
72
|
+
const title = options.title || new Date().toISOString();
|
|
73
|
+
frontmatter.tags = [...new Set(tags)];
|
|
74
|
+
noteContent = parser_js_1.NoteParser.generateNoteContent(title, body, frontmatter);
|
|
55
75
|
}
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
// Write note
|
|
60
|
-
vault.writeNote(notePath, noteContent);
|
|
61
|
-
// Sync single note to database (optimized - no full vault scan)
|
|
62
|
-
const noteFileContent = vault.readNote(notePath);
|
|
63
|
-
if (noteFileContent) {
|
|
64
|
-
const hash = parser_js_1.NoteParser.computeHash(noteFileContent);
|
|
65
|
-
const note = await vault.createNoteFromFile(notePath, noteFileContent, hash);
|
|
66
|
-
vault.upsertNote(note);
|
|
76
|
+
// 2. Resolve Default Capture Folder if no template folder
|
|
77
|
+
if (!noteFolder && vault.config.captureFolder) {
|
|
78
|
+
noteFolder = vault.config.captureFolder;
|
|
67
79
|
}
|
|
68
|
-
const
|
|
80
|
+
const title = options.title || new Date().toISOString();
|
|
81
|
+
// Obsidian-friendly filename
|
|
82
|
+
const filename = `${title.replace(/[\/\x3a\x2a\x3f\x22\x3c\x3e\x7c]/g, '-')}.md`;
|
|
83
|
+
const notePath = noteFolder ? (noteFolder.endsWith('/') ? `${noteFolder}${filename}` : `${noteFolder}/${filename}`) : filename;
|
|
84
|
+
// If not using template, frontmatter.tags was already set.
|
|
85
|
+
// If using template, renderTemplate already produced full content.
|
|
86
|
+
// BUT we might want to update frontmatter tags for non-template case.
|
|
87
|
+
// The current logic above handles this.
|
|
88
|
+
vault.writeNote(notePath, noteContent);
|
|
89
|
+
vault.indexSingleFile(notePath);
|
|
90
|
+
const file = vault.getFileByPath(notePath);
|
|
69
91
|
console.log('✅ Note captured!');
|
|
70
92
|
console.log('Path:', notePath);
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}, null, 2));
|
|
80
|
-
}
|
|
81
|
-
vault.close();
|
|
82
|
-
}
|
|
83
|
-
catch (error) {
|
|
84
|
-
console.error('❌ Failed to capture note:', error instanceof Error ? error.message : String(error));
|
|
85
|
-
process.exit(1);
|
|
86
|
-
}
|
|
93
|
+
console.log(JSON.stringify({
|
|
94
|
+
success: true,
|
|
95
|
+
path: notePath,
|
|
96
|
+
basename: file?.basename ?? notePath.replace(/\.md$/, '').split('/').pop(),
|
|
97
|
+
title,
|
|
98
|
+
tags: [...new Set(tags)]
|
|
99
|
+
}, null, 2));
|
|
100
|
+
});
|
|
87
101
|
});
|
|
88
102
|
return command;
|
|
89
103
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/commands/capture.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/commands/capture.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,mBAAmB,IAAI,OAAO,CAgE7C"}
|
package/dist/commands/config.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createConfigCommand = createConfigCommand;
|
|
4
4
|
const commander_1 = require("commander");
|
|
5
|
+
const vault_resolve_js_1 = require("../utils/vault-resolve.js");
|
|
5
6
|
const config_js_1 = require("../utils/config.js");
|
|
6
7
|
function createConfigCommand() {
|
|
7
8
|
const command = new commander_1.Command('config')
|
|
@@ -11,13 +12,7 @@ function createConfigCommand() {
|
|
|
11
12
|
.argument('<key>', 'Configuration key')
|
|
12
13
|
.action((key) => {
|
|
13
14
|
try {
|
|
14
|
-
const
|
|
15
|
-
if (!vaultPath) {
|
|
16
|
-
console.error('❌ Not in a SecondBrain vault. Run `sb init` first.');
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
19
|
-
const configManager = new config_js_1.ConfigManager(vaultPath);
|
|
20
|
-
const config = configManager.getConfig();
|
|
15
|
+
const config = (0, vault_resolve_js_1.getConfigOrExit)();
|
|
21
16
|
if (key in config) {
|
|
22
17
|
console.log(config[key]);
|
|
23
18
|
}
|
|
@@ -38,12 +33,8 @@ function createConfigCommand() {
|
|
|
38
33
|
.argument('<value>', 'Configuration value')
|
|
39
34
|
.action((key, value) => {
|
|
40
35
|
try {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
console.error('❌ Not in a SecondBrain vault. Run `sb init` first.');
|
|
44
|
-
process.exit(1);
|
|
45
|
-
}
|
|
46
|
-
const configManager = new config_js_1.ConfigManager(vaultPath);
|
|
36
|
+
const config = (0, vault_resolve_js_1.getConfigOrExit)();
|
|
37
|
+
const configManager = new config_js_1.ConfigManager(config.vaultPath);
|
|
47
38
|
const validKeys = ['dailyNotesFolder', 'templatesFolder'];
|
|
48
39
|
if (!validKeys.includes(key)) {
|
|
49
40
|
console.error(`❌ Cannot set config key: ${key}`);
|
|
@@ -62,13 +53,7 @@ function createConfigCommand() {
|
|
|
62
53
|
.description('List all configuration')
|
|
63
54
|
.action(() => {
|
|
64
55
|
try {
|
|
65
|
-
const
|
|
66
|
-
if (!vaultPath) {
|
|
67
|
-
console.error('❌ Not in a SecondBrain vault. Run `sb init` first.');
|
|
68
|
-
process.exit(1);
|
|
69
|
-
}
|
|
70
|
-
const configManager = new config_js_1.ConfigManager(vaultPath);
|
|
71
|
-
const config = configManager.getConfig();
|
|
56
|
+
const config = (0, vault_resolve_js_1.getConfigOrExit)();
|
|
72
57
|
console.log('Configuration:\n');
|
|
73
58
|
Object.entries(config).forEach(([key, value]) => {
|
|
74
59
|
console.log(`${key}: ${value}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"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"}
|