grounder 0.4.0 → 0.6.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/README.md +150 -271
- package/dist/agents/claude.d.ts +4 -4
- package/dist/agents/claude.d.ts.map +1 -1
- package/dist/agents/claude.js +158 -178
- package/dist/agents/claude.js.map +1 -1
- package/dist/agents/cursor.d.ts +3 -3
- package/dist/agents/cursor.d.ts.map +1 -1
- package/dist/agents/cursor.js +97 -143
- package/dist/agents/cursor.js.map +1 -1
- package/dist/agents/home-skills.d.ts +46 -0
- package/dist/agents/home-skills.d.ts.map +1 -0
- package/dist/agents/home-skills.js +83 -0
- package/dist/agents/home-skills.js.map +1 -0
- package/dist/agents/hook-fragment.d.ts +52 -0
- package/dist/agents/hook-fragment.d.ts.map +1 -0
- package/dist/agents/hook-fragment.js +76 -0
- package/dist/agents/hook-fragment.js.map +1 -0
- package/dist/agents/hook-install.d.ts +62 -0
- package/dist/agents/hook-install.d.ts.map +1 -0
- package/dist/agents/hook-install.js +74 -0
- package/dist/agents/hook-install.js.map +1 -0
- package/dist/agents/hook-runtime.d.ts +80 -13
- package/dist/agents/hook-runtime.d.ts.map +1 -1
- package/dist/agents/hook-runtime.js +278 -74
- package/dist/agents/hook-runtime.js.map +1 -1
- package/dist/agents/index.d.ts +8 -14
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +13 -19
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/types.d.ts +56 -16
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/cli.js +15 -10
- package/dist/cli.js.map +1 -1
- package/dist/commands/apply.d.ts +69 -0
- package/dist/commands/apply.d.ts.map +1 -0
- package/dist/commands/apply.js +238 -0
- package/dist/commands/apply.js.map +1 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +197 -101
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/handoff/list.d.ts +23 -13
- package/dist/commands/handoff/list.d.ts.map +1 -1
- package/dist/commands/handoff/list.js +28 -16
- package/dist/commands/handoff/list.js.map +1 -1
- package/dist/commands/handoff/peek.d.ts +1 -1
- package/dist/commands/handoff/peek.d.ts.map +1 -1
- package/dist/commands/handoff/peek.js +28 -12
- package/dist/commands/handoff/peek.js.map +1 -1
- package/dist/commands/handoff.d.ts +2 -0
- package/dist/commands/handoff.d.ts.map +1 -1
- package/dist/commands/handoff.js +10 -1
- package/dist/commands/handoff.js.map +1 -1
- package/dist/commands/install-drift.d.ts +34 -0
- package/dist/commands/install-drift.d.ts.map +1 -0
- package/dist/commands/install-drift.js +72 -0
- package/dist/commands/install-drift.js.map +1 -0
- package/dist/commands/link.d.ts +12 -0
- package/dist/commands/link.d.ts.map +1 -0
- package/dist/commands/{repo/init.js → link.js} +35 -27
- package/dist/commands/link.js.map +1 -0
- package/dist/commands/migrate.d.ts +11 -3
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +66 -34
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/note/list.d.ts +17 -9
- package/dist/commands/note/list.d.ts.map +1 -1
- package/dist/commands/note/list.js +19 -14
- package/dist/commands/note/list.js.map +1 -1
- package/dist/commands/note.d.ts +2 -0
- package/dist/commands/note.d.ts.map +1 -1
- package/dist/commands/note.js +10 -1
- package/dist/commands/note.js.map +1 -1
- package/dist/commands/output.d.ts +22 -2
- package/dist/commands/output.d.ts.map +1 -1
- package/dist/commands/output.js +18 -6
- package/dist/commands/output.js.map +1 -1
- package/dist/commands/overview.d.ts +33 -0
- package/dist/commands/overview.d.ts.map +1 -0
- package/dist/commands/overview.js +150 -0
- package/dist/commands/overview.js.map +1 -0
- package/dist/commands/plan/list.d.ts +20 -12
- package/dist/commands/plan/list.d.ts.map +1 -1
- package/dist/commands/plan/list.js +22 -17
- package/dist/commands/plan/list.js.map +1 -1
- package/dist/commands/plan.d.ts +2 -0
- package/dist/commands/plan.d.ts.map +1 -1
- package/dist/commands/plan.js +12 -2
- package/dist/commands/plan.js.map +1 -1
- package/dist/commands/render-artifact-table.d.ts +85 -0
- package/dist/commands/render-artifact-table.d.ts.map +1 -0
- package/dist/commands/render-artifact-table.js +232 -0
- package/dist/commands/render-artifact-table.js.map +1 -0
- package/dist/commands/require-linked.js +2 -2
- package/dist/commands/require-linked.js.map +1 -1
- package/dist/commands/search.d.ts +23 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +288 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/{vault/init.d.ts → setup.d.ts} +5 -4
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +210 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/status.d.ts +7 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +273 -83
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/upgrade-banner.d.ts +2 -2
- package/dist/commands/upgrade-banner.js +2 -2
- package/dist/connector/home.d.ts +12 -0
- package/dist/connector/home.d.ts.map +1 -1
- package/dist/connector/home.js +26 -2
- package/dist/connector/home.js.map +1 -1
- package/dist/connector/ledger-migrations.d.ts +55 -0
- package/dist/connector/ledger-migrations.d.ts.map +1 -0
- package/dist/connector/ledger-migrations.js +94 -0
- package/dist/connector/ledger-migrations.js.map +1 -0
- package/dist/connector/state.d.ts +97 -60
- package/dist/connector/state.d.ts.map +1 -1
- package/dist/connector/state.js +165 -107
- package/dist/connector/state.js.map +1 -1
- package/dist/connector/vault.d.ts +2 -0
- package/dist/connector/vault.d.ts.map +1 -1
- package/dist/connector/vault.js +6 -1
- package/dist/connector/vault.js.map +1 -1
- package/dist/help.d.ts +3 -3
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +97 -56
- package/dist/help.js.map +1 -1
- package/dist/reconcile/apply.d.ts +31 -0
- package/dist/reconcile/apply.d.ts.map +1 -0
- package/dist/reconcile/apply.js +97 -0
- package/dist/reconcile/apply.js.map +1 -0
- package/dist/reconcile/core.d.ts +82 -0
- package/dist/reconcile/core.d.ts.map +1 -0
- package/dist/reconcile/core.js +163 -0
- package/dist/reconcile/core.js.map +1 -0
- package/dist/reconcile/disk.d.ts +13 -0
- package/dist/reconcile/disk.d.ts.map +1 -0
- package/dist/reconcile/disk.js +28 -0
- package/dist/reconcile/disk.js.map +1 -0
- package/dist/util/frontmatter.d.ts +9 -7
- package/dist/util/frontmatter.d.ts.map +1 -1
- package/dist/util/frontmatter.js +29 -4
- package/dist/util/frontmatter.js.map +1 -1
- package/dist/util/fs.d.ts +14 -0
- package/dist/util/fs.d.ts.map +1 -1
- package/dist/util/fs.js +27 -1
- package/dist/util/fs.js.map +1 -1
- package/dist/util/merge-json.d.ts +13 -2
- package/dist/util/merge-json.d.ts.map +1 -1
- package/dist/util/merge-json.js +24 -10
- package/dist/util/merge-json.js.map +1 -1
- package/dist/util/path.d.ts +23 -0
- package/dist/util/path.d.ts.map +1 -1
- package/dist/util/path.js +39 -0
- package/dist/util/path.js.map +1 -1
- package/dist/vault/list-handoffs.d.ts +14 -2
- package/dist/vault/list-handoffs.d.ts.map +1 -1
- package/dist/vault/list-handoffs.js +40 -23
- package/dist/vault/list-handoffs.js.map +1 -1
- package/dist/vault/list-markdown.d.ts +8 -0
- package/dist/vault/list-markdown.d.ts.map +1 -0
- package/dist/vault/list-markdown.js +35 -0
- package/dist/vault/list-markdown.js.map +1 -0
- package/dist/vault/list-notes.d.ts +15 -6
- package/dist/vault/list-notes.d.ts.map +1 -1
- package/dist/vault/list-notes.js +23 -27
- package/dist/vault/list-notes.js.map +1 -1
- package/dist/vault/list-plans.d.ts +12 -3
- package/dist/vault/list-plans.d.ts.map +1 -1
- package/dist/vault/list-plans.js +20 -24
- package/dist/vault/list-plans.js.map +1 -1
- package/dist/vault/search.d.ts +55 -0
- package/dist/vault/search.d.ts.map +1 -0
- package/dist/vault/search.js +432 -0
- package/dist/vault/search.js.map +1 -0
- package/dist/vault/write-handoff.d.ts +2 -0
- package/dist/vault/write-handoff.d.ts.map +1 -1
- package/dist/vault/write-handoff.js +5 -0
- package/dist/vault/write-handoff.js.map +1 -1
- package/dist/vault/write-note.d.ts +2 -0
- package/dist/vault/write-note.d.ts.map +1 -1
- package/dist/vault/write-note.js +9 -1
- package/dist/vault/write-note.js.map +1 -1
- package/dist/vault/write-plan.d.ts +4 -0
- package/dist/vault/write-plan.d.ts.map +1 -1
- package/dist/vault/write-plan.js +14 -1
- package/dist/vault/write-plan.js.map +1 -1
- package/package.json +11 -4
- package/templates/agents/claude/skills/grounder-handoff/SKILL.md +73 -0
- package/templates/agents/claude/{commands/grounder-note.md → skills/grounder-note/SKILL.md} +12 -2
- package/templates/agents/claude/skills/grounder-overview/SKILL.md +21 -0
- package/templates/agents/claude/{commands/grounder-plan.md → skills/grounder-plan/SKILL.md} +13 -5
- package/templates/agents/claude/skills/grounder-recall/SKILL.md +34 -0
- package/templates/agents/claude/skills/grounder-search/SKILL.md +152 -0
- package/templates/agents/cursor/skills/grounder-handoff/SKILL.md +73 -0
- package/templates/agents/cursor/{commands/grounder-note.md → skills/grounder-note/SKILL.md} +12 -2
- package/templates/agents/cursor/skills/grounder-overview/SKILL.md +21 -0
- package/templates/agents/cursor/{commands/grounder-plan.md → skills/grounder-plan/SKILL.md} +13 -5
- package/templates/agents/cursor/skills/grounder-recall/SKILL.md +34 -0
- package/templates/agents/cursor/skills/grounder-search/SKILL.md +152 -0
- package/templates/vault/plan.md +1 -1
- package/templates/vault/session-handoff.md +2 -1
- package/dist/agents/install-command.d.ts +0 -35
- package/dist/agents/install-command.d.ts.map +0 -1
- package/dist/agents/install-command.js +0 -65
- package/dist/agents/install-command.js.map +0 -1
- package/dist/commands/apply-agent-installs.d.ts +0 -34
- package/dist/commands/apply-agent-installs.d.ts.map +0 -1
- package/dist/commands/apply-agent-installs.js +0 -137
- package/dist/commands/apply-agent-installs.js.map +0 -1
- package/dist/commands/repo/init.d.ts +0 -11
- package/dist/commands/repo/init.d.ts.map +0 -1
- package/dist/commands/repo/init.js.map +0 -1
- package/dist/commands/vault/init.d.ts.map +0 -1
- package/dist/commands/vault/init.js +0 -90
- package/dist/commands/vault/init.js.map +0 -1
- package/templates/agents/claude/commands/grounder-task-handoff.md +0 -54
- package/templates/agents/claude/commands/grounder-task.md +0 -22
- package/templates/agents/cursor/commands/grounder-task-handoff.md +0 -54
- package/templates/agents/cursor/commands/grounder-task.md +0 -22
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import { readFile, stat } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parseHandoffFrontmatter } from "../util/frontmatter.js";
|
|
4
|
+
import { listMarkdownFiles } from "./list-markdown.js";
|
|
5
|
+
const DEFAULT_LIMIT = 10;
|
|
6
|
+
const DEFAULT_MAX_HITS = 50;
|
|
7
|
+
const DEFAULT_CONTEXT = 1;
|
|
8
|
+
const DEFAULT_MAX_HITS_PER_FILE = 1;
|
|
9
|
+
/** Cap line hits stored per file during scan (counts stay full for ranking). */
|
|
10
|
+
const MAX_STORED_HITS_PER_FILE = 50;
|
|
11
|
+
/** Known vault subfolders — light tiebreaker after recency. */
|
|
12
|
+
const FOLDER_SIGNAL = {
|
|
13
|
+
notes: 2,
|
|
14
|
+
plans: 2,
|
|
15
|
+
logs: 1,
|
|
16
|
+
};
|
|
17
|
+
function escapeRegex(value) {
|
|
18
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
19
|
+
}
|
|
20
|
+
/** Single-token terms only — phrases may contain spaces or punctuation. */
|
|
21
|
+
function isWordLikeTerm(term) {
|
|
22
|
+
return /^[\w-]+$/.test(term);
|
|
23
|
+
}
|
|
24
|
+
function pruneOverlappingTerms(query, terms) {
|
|
25
|
+
const queryKey = query.trim().toLowerCase();
|
|
26
|
+
return terms.filter((term) => {
|
|
27
|
+
const lower = term.toLowerCase();
|
|
28
|
+
if (lower === queryKey) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
return !terms.some((other) => {
|
|
32
|
+
if (other === term) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
const otherLower = other.toLowerCase();
|
|
36
|
+
if (otherLower.length <= lower.length || !isWordLikeTerm(term) || !isWordLikeTerm(other)) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
return otherLower.startsWith(lower);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function normalizeTerms(query, extra) {
|
|
44
|
+
const seen = new Set();
|
|
45
|
+
const out = [];
|
|
46
|
+
// Always include the query — multi-word phrases use substring matching in
|
|
47
|
+
// termMatchesLine, so exact phrases only match lines that contain them verbatim.
|
|
48
|
+
for (const raw of [query, ...(extra ?? [])]) {
|
|
49
|
+
const term = raw.trim();
|
|
50
|
+
if (!term) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const key = term.toLowerCase();
|
|
54
|
+
if (seen.has(key)) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
seen.add(key);
|
|
58
|
+
out.push(term);
|
|
59
|
+
}
|
|
60
|
+
return pruneOverlappingTerms(query, out);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Soft-demote search dogfood notes when the user is not asking about search.
|
|
64
|
+
* (`discussions/search/…`, `search-feature.md`, `Search Results.md`)
|
|
65
|
+
*/
|
|
66
|
+
function searchMetaPenalty(rootDir, filePath, query) {
|
|
67
|
+
if (/\bsearch\b/i.test(query)) {
|
|
68
|
+
return 0;
|
|
69
|
+
}
|
|
70
|
+
const rel = path.relative(rootDir, filePath);
|
|
71
|
+
const segments = rel.split(path.sep).map((segment) => segment.toLowerCase());
|
|
72
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
73
|
+
if (segments[i] === "discussions" && segments[i + 1] === "search") {
|
|
74
|
+
return 1;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const stem = path.basename(filePath, path.extname(filePath)).toLowerCase();
|
|
78
|
+
if (stem === "search-feature" || stem === "search results") {
|
|
79
|
+
return 1;
|
|
80
|
+
}
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
// Deliberately separate from termMatchesHaystack's dot-aware boundary below —
|
|
84
|
+
// body content has no dotted-pseudo-extension convention to guard against, so
|
|
85
|
+
// plain `\b` is correct here. Do not "unify" the two matchers: a shared regex
|
|
86
|
+
// would either reintroduce `plan` matching `<id>.plan.md` in filenames, or
|
|
87
|
+
// stop `.plan` matching `plan` in body text, silently changing one side.
|
|
88
|
+
/** One compiled matcher per term, built once per search so the per-line scan never recompiles a RegExp. */
|
|
89
|
+
function buildTermMatchers(terms) {
|
|
90
|
+
const matchers = new Map();
|
|
91
|
+
for (const term of terms) {
|
|
92
|
+
matchers.set(term, term.includes(" ") ? null : new RegExp(`\\b${escapeRegex(term)}\\b`, "i"));
|
|
93
|
+
}
|
|
94
|
+
return matchers;
|
|
95
|
+
}
|
|
96
|
+
function termMatchesLine(line, term, matcher) {
|
|
97
|
+
if (matcher === null) {
|
|
98
|
+
return line.toLowerCase().includes(term.toLowerCase());
|
|
99
|
+
}
|
|
100
|
+
return matcher.test(line);
|
|
101
|
+
}
|
|
102
|
+
function matchingTermsOnLine(line, terms, matchers) {
|
|
103
|
+
return terms.filter((term) => termMatchesLine(line, term, matchers.get(term) ?? null));
|
|
104
|
+
}
|
|
105
|
+
function longestTerm(matches) {
|
|
106
|
+
return matches.reduce((best, term) => (term.length > best.length ? term : best));
|
|
107
|
+
}
|
|
108
|
+
function topicsMatchTerms(topics, terms) {
|
|
109
|
+
if (!topics?.length) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
const lowered = topics.map((t) => t.toLowerCase());
|
|
113
|
+
return terms.some((term) => lowered.includes(term.toLowerCase()));
|
|
114
|
+
}
|
|
115
|
+
function folderSignal(rootDir, filePath) {
|
|
116
|
+
const rel = path.relative(rootDir, filePath);
|
|
117
|
+
const first = rel.split(path.sep)[0];
|
|
118
|
+
return first ? (FOLDER_SIGNAL[first] ?? 0) : 0;
|
|
119
|
+
}
|
|
120
|
+
/** Deprioritize archived plans/notes — still searchable, ranked lower. */
|
|
121
|
+
function archivePenalty(rootDir, filePath) {
|
|
122
|
+
const rel = path.relative(rootDir, filePath);
|
|
123
|
+
const segments = rel.split(path.sep);
|
|
124
|
+
return segments.some((segment) => segment.toLowerCase() === "archive") ? 1 : 0;
|
|
125
|
+
}
|
|
126
|
+
function buildSnippet(lines, lineIndex, context) {
|
|
127
|
+
const start = Math.max(0, lineIndex - context);
|
|
128
|
+
const end = Math.min(lines.length - 1, lineIndex + context);
|
|
129
|
+
const parts = [];
|
|
130
|
+
for (let i = start; i <= end; i++) {
|
|
131
|
+
parts.push(lines[i] ?? "");
|
|
132
|
+
}
|
|
133
|
+
return parts.join("\n");
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* `.` only counts as a word character on the *leading* side of a match
|
|
137
|
+
* (unlike `\b`'s default), so a term can't start right after a dot — this
|
|
138
|
+
* stops a dotted filename convention like `<id>.plan.md` from letting a
|
|
139
|
+
* generic term match its dotted suffix as a standalone word (query "plan"
|
|
140
|
+
* must not match every `*.plan.md` file), while still letting the id itself
|
|
141
|
+
* match (`schema_versioning` must match `schema_versioning.plan.md`) since a
|
|
142
|
+
* term is still allowed to *end* right before a dot. `\w`-based boundaries
|
|
143
|
+
* are otherwise unchanged from before this fix: a hyphen still splits words
|
|
144
|
+
* (`search` matches `search-feature.md`), but `_` does not (`search` does
|
|
145
|
+
* *not* match `search_feature.md` — same as `\b`'s existing behavior).
|
|
146
|
+
*/
|
|
147
|
+
function termMatchesHaystack(haystack, lower, matcher) {
|
|
148
|
+
if (matcher === null) {
|
|
149
|
+
return haystack.includes(lower);
|
|
150
|
+
}
|
|
151
|
+
return matcher.test(haystack);
|
|
152
|
+
}
|
|
153
|
+
/** One compiled matcher per lowercased term, built once per search — same rationale as {@link buildTermMatchers}. */
|
|
154
|
+
function buildHaystackMatchers(terms) {
|
|
155
|
+
const matchers = new Map();
|
|
156
|
+
for (const term of terms) {
|
|
157
|
+
const lower = term.toLowerCase();
|
|
158
|
+
matchers.set(lower, lower.includes(" ") ? null : new RegExp(`(?<![\\w.])${escapeRegex(lower)}(?!\\w)`, "i"));
|
|
159
|
+
}
|
|
160
|
+
return matchers;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Lowercased `terms` that appear in `filePath`'s vault-relative path,
|
|
164
|
+
* including parent directory names (e.g. `plans/p1.md` matches both `plans`
|
|
165
|
+
* and `p1`). Ranking signal only (`filenameTermCount`) — never a matching
|
|
166
|
+
* gate, since a query for a common folder name (`plans`, `notes`, `archive`)
|
|
167
|
+
* would otherwise return every file in that folder regardless of content.
|
|
168
|
+
*/
|
|
169
|
+
/** Shared by {@link pathMatchedTerms} and {@link stemMatchedTerms} — only the haystack differs between the two. */
|
|
170
|
+
function matchTermsAgainstHaystack(haystack, terms, haystackMatchers) {
|
|
171
|
+
const matched = new Set();
|
|
172
|
+
for (const term of terms) {
|
|
173
|
+
const lower = term.toLowerCase();
|
|
174
|
+
if (termMatchesHaystack(haystack, lower, haystackMatchers.get(lower) ?? null)) {
|
|
175
|
+
matched.add(lower);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return matched;
|
|
179
|
+
}
|
|
180
|
+
function pathMatchedTerms(rootDir, filePath, terms, haystackMatchers) {
|
|
181
|
+
const rel = path.relative(rootDir, filePath);
|
|
182
|
+
const haystack = rel.replace(/[/\\]/g, " ").replace(/\.md$/i, "").toLowerCase();
|
|
183
|
+
return matchTermsAgainstHaystack(haystack, terms, haystackMatchers);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Lowercased `terms` that appear in `filePath`'s own filename stem only (no
|
|
187
|
+
* parent directories, no extension) — e.g. `plans/pluggable.md` matches
|
|
188
|
+
* `pluggable` but not `plans`. Narrow enough to gate inclusion for a file
|
|
189
|
+
* with no content match, unlike {@link pathMatchedTerms}.
|
|
190
|
+
*/
|
|
191
|
+
/**
|
|
192
|
+
* Strips a leading vault timestamp prefix (`YYYY-MM-DD-HHmm[ss]`, see
|
|
193
|
+
* `dateSecondPrefix`/`dateMinutePrefix` in `timestamp-slug.ts`) so a bare
|
|
194
|
+
* date/time query doesn't stem-match every handoff/log filename — hyphens
|
|
195
|
+
* alone don't stop it, since each numeric segment still matches standalone
|
|
196
|
+
* as a "word" via termMatchesHaystack's boundary check. Strips to empty for
|
|
197
|
+
* a slug-less date-only stem, same as any other narrow-to-nothing case.
|
|
198
|
+
*/
|
|
199
|
+
function stripTimestampPrefix(stem) {
|
|
200
|
+
// `_` terminates too, not just `-`/end — a slug-less collision-suffixed
|
|
201
|
+
// stem (`writeUniqueMarkdown`'s `_02`, `_03`, …) attaches directly to the
|
|
202
|
+
// date with no separating hyphen.
|
|
203
|
+
return stem.replace(/^\d{4}-\d{2}-\d{2}-\d{4,6}(-|_|$)/, "");
|
|
204
|
+
}
|
|
205
|
+
function stemMatchedTerms(filePath, terms, haystackMatchers) {
|
|
206
|
+
const stem = stripTimestampPrefix(path.basename(filePath, path.extname(filePath)).toLowerCase());
|
|
207
|
+
return matchTermsAgainstHaystack(stem, terms, haystackMatchers);
|
|
208
|
+
}
|
|
209
|
+
function contentHasPhrase(content, query) {
|
|
210
|
+
const trimmed = query.trim();
|
|
211
|
+
if (!trimmed.includes(" ")) {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
return content.toLowerCase().includes(trimmed.toLowerCase());
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Partial n-gram match: 2 consecutive words for 3-word queries, 3 consecutive
|
|
218
|
+
* words for 4+ word queries. Trigrams cut false positives where a doc only
|
|
219
|
+
* shares a loose bigram (e.g. "slash commands") without migration context.
|
|
220
|
+
*/
|
|
221
|
+
function contentHasPartialPhrase(content, query) {
|
|
222
|
+
const words = query.trim().split(/\s+/).filter(Boolean);
|
|
223
|
+
if (words.length < 3) {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
const lower = content.toLowerCase();
|
|
227
|
+
const windowSize = words.length >= 4 ? 3 : 2;
|
|
228
|
+
for (let i = 0; i <= words.length - windowSize; i++) {
|
|
229
|
+
const ngram = words
|
|
230
|
+
.slice(i, i + windowSize)
|
|
231
|
+
.join(" ")
|
|
232
|
+
.toLowerCase();
|
|
233
|
+
if (lower.includes(ngram)) {
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
function relevanceScore(file, rootDir, query) {
|
|
240
|
+
return (file.distinctTermCount * 1000 +
|
|
241
|
+
Math.min(file.idfDensity, 100) * 10 +
|
|
242
|
+
(file.topicsMatch ? 800 : 0) +
|
|
243
|
+
file.filenameTermCount * 200 +
|
|
244
|
+
(file.phraseMatch ? 300 : 0) +
|
|
245
|
+
(file.partialPhraseMatch ? 100 : 0) -
|
|
246
|
+
// Strong enough to lose to real notes with similar distinct-term coverage
|
|
247
|
+
// (meta dumps / search dogfood often win on raw hit density alone).
|
|
248
|
+
searchMetaPenalty(rootDir, file.filePath, query) * 5000);
|
|
249
|
+
}
|
|
250
|
+
function pickBestHits(hits, maxHitsPerFile) {
|
|
251
|
+
if (hits.length <= maxHitsPerFile) {
|
|
252
|
+
return hits;
|
|
253
|
+
}
|
|
254
|
+
const sorted = [...hits].sort((a, b) => b.matchedTerm.length - a.matchedTerm.length);
|
|
255
|
+
return sorted.slice(0, maxHitsPerFile);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Case-insensitive markdown scan under `rootDir`.
|
|
259
|
+
* Frontmatter `topics:` matches boost file ranking; body and frontmatter lines
|
|
260
|
+
* both contribute line hits. Files rank by relevance (distinct terms, hit
|
|
261
|
+
* density, filename/path terms, topics; demotes search dogfood when query is
|
|
262
|
+
* unrelated), then archive, recency, folder. Pure fs — no index, no deps.
|
|
263
|
+
*/
|
|
264
|
+
export async function searchVault(options) {
|
|
265
|
+
const terms = normalizeTerms(options.query, options.terms);
|
|
266
|
+
const limit = options.limit ?? DEFAULT_LIMIT;
|
|
267
|
+
const maxHits = options.maxHits ?? DEFAULT_MAX_HITS;
|
|
268
|
+
const context = options.context ?? DEFAULT_CONTEXT;
|
|
269
|
+
const maxHitsPerFile = options.maxHitsPerFile ?? DEFAULT_MAX_HITS_PER_FILE;
|
|
270
|
+
const perFileStoreCap = Math.min(MAX_STORED_HITS_PER_FILE, maxHits);
|
|
271
|
+
if (terms.length === 0) {
|
|
272
|
+
return {
|
|
273
|
+
query: options.query,
|
|
274
|
+
terms: [],
|
|
275
|
+
termHitCounts: {},
|
|
276
|
+
totalMatchCount: 0,
|
|
277
|
+
totalFileCount: 0,
|
|
278
|
+
files: [],
|
|
279
|
+
truncated: false,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
const filePaths = await listMarkdownFiles(options.rootDir);
|
|
283
|
+
const termMatchers = buildTermMatchers(terms);
|
|
284
|
+
const haystackMatchers = buildHaystackMatchers(terms);
|
|
285
|
+
const rawFiles = [];
|
|
286
|
+
let totalMatchCount = 0;
|
|
287
|
+
// Lowercased doc-freq for ranking; JSON output remaps to original `terms` spelling.
|
|
288
|
+
const termDocFreq = Object.fromEntries(terms.map((t) => [t.toLowerCase(), 0]));
|
|
289
|
+
for (const filePath of filePaths) {
|
|
290
|
+
let content;
|
|
291
|
+
let mtimeMs;
|
|
292
|
+
try {
|
|
293
|
+
[content, { mtimeMs }] = await Promise.all([readFile(filePath, "utf8"), stat(filePath)]);
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
if (options.since !== undefined && mtimeMs < options.since.getTime()) {
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
const lines = content.split(/\r?\n/);
|
|
302
|
+
const frontmatter = parseHandoffFrontmatter(content);
|
|
303
|
+
const topicsMatch = topicsMatchTerms(frontmatter.topics, terms);
|
|
304
|
+
const fileHits = [];
|
|
305
|
+
const matchedTerms = new Set();
|
|
306
|
+
const perTermHits = new Map();
|
|
307
|
+
let totalHitCount = 0;
|
|
308
|
+
for (let i = 0; i < lines.length; i++) {
|
|
309
|
+
const line = lines[i] ?? "";
|
|
310
|
+
const lineMatches = matchingTermsOnLine(line, terms, termMatchers);
|
|
311
|
+
if (lineMatches.length === 0) {
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
for (const term of lineMatches) {
|
|
315
|
+
const termKey = term.toLowerCase();
|
|
316
|
+
matchedTerms.add(termKey);
|
|
317
|
+
perTermHits.set(termKey, (perTermHits.get(termKey) ?? 0) + 1);
|
|
318
|
+
}
|
|
319
|
+
totalHitCount++;
|
|
320
|
+
totalMatchCount++;
|
|
321
|
+
if (fileHits.length < perFileStoreCap) {
|
|
322
|
+
fileHits.push({
|
|
323
|
+
line: i + 1,
|
|
324
|
+
matchedTerm: longestTerm(lineMatches),
|
|
325
|
+
snippet: buildSnippet(lines, i, context),
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
// Path terms (dir segments + stem) stay a ranking-only signal — they must
|
|
330
|
+
// never gate inclusion, or a query for a common folder name (`plans`,
|
|
331
|
+
// `notes`, `archive`) would return every file in that folder regardless
|
|
332
|
+
// of content. The *matcher* underneath did change (shares
|
|
333
|
+
// termMatchesHaystack's dot-boundary fix with stem matching below), so a
|
|
334
|
+
// content-matching `<id>.plan.md` no longer earns filenameTermCount for
|
|
335
|
+
// its dotted suffix — only the gating behavior is unchanged, not the
|
|
336
|
+
// matcher itself.
|
|
337
|
+
const pathTerms = pathMatchedTerms(options.rootDir, filePath, terms, haystackMatchers);
|
|
338
|
+
// Stem terms are narrow enough (the file's own name, not its folder) to
|
|
339
|
+
// justify surfacing a file that has no content match at all — e.g.
|
|
340
|
+
// `pluggable.md`, whose body never repeats the word "pluggable".
|
|
341
|
+
const stemTerms = stemMatchedTerms(filePath, terms, haystackMatchers);
|
|
342
|
+
if (matchedTerms.size === 0 && stemTerms.size > 0) {
|
|
343
|
+
// Every other zero-hit check in the CLI and its consumers (summary
|
|
344
|
+
// text, JSON, the extension's QuickPick) keys off `totalMatchCount`,
|
|
345
|
+
// not file count — count the title match itself so a filename-only
|
|
346
|
+
// result doesn't get reported as "no matches" while still returning a hit.
|
|
347
|
+
totalMatchCount++;
|
|
348
|
+
}
|
|
349
|
+
if (matchedTerms.size > 0 || stemTerms.size > 0) {
|
|
350
|
+
for (const t of stemTerms) {
|
|
351
|
+
// Only stem terms feed doc-freq (not the wider path terms): a term
|
|
352
|
+
// that only ever appears in a title should still show a nonzero
|
|
353
|
+
// `termHitCounts`, so the skill's zero-hit "bad term" broaden check
|
|
354
|
+
// doesn't misfire on it — but a common folder name shouldn't inflate
|
|
355
|
+
// every other term's IDF weighting.
|
|
356
|
+
if (!matchedTerms.has(t)) {
|
|
357
|
+
termDocFreq[t] = (termDocFreq[t] ?? 0) + 1;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
for (const t of matchedTerms) {
|
|
361
|
+
termDocFreq[t] = (termDocFreq[t] ?? 0) + 1;
|
|
362
|
+
}
|
|
363
|
+
rawFiles.push({
|
|
364
|
+
filePath,
|
|
365
|
+
mtimeMs,
|
|
366
|
+
topicsMatch,
|
|
367
|
+
hits: fileHits,
|
|
368
|
+
// Content-only: a filename/stem match justifies inclusion (above)
|
|
369
|
+
// and still earns the flat `filenameTermCount` rank bonus below, but
|
|
370
|
+
// doesn't inflate distinct-term coverage — a file that only matches
|
|
371
|
+
// by title shouldn't outrank one that actually discusses the topic.
|
|
372
|
+
distinctTermCount: matchedTerms.size,
|
|
373
|
+
totalHitCount,
|
|
374
|
+
idfDensity: 0,
|
|
375
|
+
filenameTermCount: pathTerms.size,
|
|
376
|
+
stemMatchedTerms: stemTerms,
|
|
377
|
+
phraseMatch: contentHasPhrase(content, options.query),
|
|
378
|
+
partialPhraseMatch: contentHasPartialPhrase(content, options.query),
|
|
379
|
+
perTermHits,
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
// Scale hit density by IDF so rare identifiers outweigh common tokens like "grounder".
|
|
384
|
+
for (const file of rawFiles) {
|
|
385
|
+
let density = 0;
|
|
386
|
+
for (const [term, count] of file.perTermHits) {
|
|
387
|
+
const df = termDocFreq[term] ?? 1;
|
|
388
|
+
density += count / Math.log(1 + df);
|
|
389
|
+
}
|
|
390
|
+
file.idfDensity = density;
|
|
391
|
+
}
|
|
392
|
+
rawFiles.sort((a, b) => {
|
|
393
|
+
const scoreDiff = relevanceScore(b, options.rootDir, options.query) -
|
|
394
|
+
relevanceScore(a, options.rootDir, options.query);
|
|
395
|
+
if (scoreDiff !== 0) {
|
|
396
|
+
return scoreDiff;
|
|
397
|
+
}
|
|
398
|
+
const archiveDiff = archivePenalty(options.rootDir, a.filePath) - archivePenalty(options.rootDir, b.filePath);
|
|
399
|
+
if (archiveDiff !== 0) {
|
|
400
|
+
return archiveDiff;
|
|
401
|
+
}
|
|
402
|
+
if (a.mtimeMs !== b.mtimeMs) {
|
|
403
|
+
return b.mtimeMs - a.mtimeMs;
|
|
404
|
+
}
|
|
405
|
+
const folderDiff = folderSignal(options.rootDir, b.filePath) - folderSignal(options.rootDir, a.filePath);
|
|
406
|
+
if (folderDiff !== 0) {
|
|
407
|
+
return folderDiff;
|
|
408
|
+
}
|
|
409
|
+
return a.filePath.localeCompare(b.filePath);
|
|
410
|
+
});
|
|
411
|
+
const totalFileCount = rawFiles.length;
|
|
412
|
+
const truncated = totalFileCount > limit;
|
|
413
|
+
const files = rawFiles.slice(0, limit).map((file) => ({
|
|
414
|
+
filePath: file.filePath,
|
|
415
|
+
mtimeMs: file.mtimeMs,
|
|
416
|
+
topicsMatch: file.topicsMatch,
|
|
417
|
+
hits: pickBestHits(file.hits, maxHitsPerFile),
|
|
418
|
+
matchedTerms: terms
|
|
419
|
+
.filter((term) => file.perTermHits.has(term.toLowerCase()) || file.stemMatchedTerms.has(term.toLowerCase()))
|
|
420
|
+
.sort((a, b) => b.length - a.length),
|
|
421
|
+
}));
|
|
422
|
+
return {
|
|
423
|
+
query: options.query,
|
|
424
|
+
terms,
|
|
425
|
+
termHitCounts: Object.fromEntries(terms.map((term) => [term, termDocFreq[term.toLowerCase()] ?? 0])),
|
|
426
|
+
totalMatchCount,
|
|
427
|
+
totalFileCount,
|
|
428
|
+
files,
|
|
429
|
+
truncated,
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/vault/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,8 @@ export interface WriteHandoffOptions {
|
|
|
6
6
|
title?: string;
|
|
7
7
|
/** Git branch when known; omitted from frontmatter if unset. */
|
|
8
8
|
branch?: string;
|
|
9
|
+
/** 3-5 topic keywords for search (flat list, omitted when empty/unset). */
|
|
10
|
+
topics?: string[];
|
|
9
11
|
/** Timestamp for filename prefix and `created` (default: now). */
|
|
10
12
|
now?: Date;
|
|
11
13
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write-handoff.d.ts","sourceRoot":"","sources":["../../src/vault/write-handoff.ts"],"names":[],"mappings":"AAKA,wCAAwC;AACxC,MAAM,WAAW,mBAAmB;IAClC,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;
|
|
1
|
+
{"version":3,"file":"write-handoff.d.ts","sourceRoot":"","sources":["../../src/vault/write-handoff.ts"],"names":[],"mappings":"AAKA,wCAAwC;AACxC,MAAM,WAAW,mBAAmB;IAClC,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,kEAAkE;IAClE,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAyBD;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,MAAM,CAAC,CAkBjB"}
|
|
@@ -11,6 +11,10 @@ function buildFrontmatter(options) {
|
|
|
11
11
|
if (options.title) {
|
|
12
12
|
lines.push(`title: ${yamlDoubleQuoted(options.title)}`);
|
|
13
13
|
}
|
|
14
|
+
if (options.topics && options.topics.length > 0) {
|
|
15
|
+
const items = options.topics.map((t) => yamlDoubleQuoted(t)).join(", ");
|
|
16
|
+
lines.push(`topics: [${items}]`);
|
|
17
|
+
}
|
|
14
18
|
lines.push("---");
|
|
15
19
|
return `${lines.join("\n")}\n\n`;
|
|
16
20
|
}
|
|
@@ -34,6 +38,7 @@ export async function writeHandoff(logsDir, body, options) {
|
|
|
34
38
|
branch: options.branch,
|
|
35
39
|
created: now.toISOString(),
|
|
36
40
|
title: options.title,
|
|
41
|
+
topics: options.topics,
|
|
37
42
|
}) + body;
|
|
38
43
|
return writeUniqueMarkdown(logsDir, basename, content);
|
|
39
44
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write-handoff.js","sourceRoot":"","sources":["../../src/vault/write-handoff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"write-handoff.js","sourceRoot":"","sources":["../../src/vault/write-handoff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAgBnD,SAAS,gBAAgB,CAAC,OAMzB;IACC,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,YAAY,gBAAgB,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACzE,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,WAAW,gBAAgB,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,YAAY,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5D,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,KAAK,CAAC,IAAI,CAAC,UAAU,gBAAgB,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChD,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxE,KAAK,CAAC,IAAI,CAAC,YAAY,KAAK,GAAG,CAAC,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AACnC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAe,EACf,IAAY,EACZ,OAA4B;IAE5B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;IACtC,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1C,MAAM,QAAQ,GAAG,mBAAmB,CAAC,IAAI,EAAE;QACzC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,GAAG;KACJ,CAAC,CAAC;IACH,MAAM,OAAO,GACX,gBAAgB,CAAC;QACf,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,OAAO,EAAE,GAAG,CAAC,WAAW,EAAE;QAC1B,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,GAAG,IAAI,CAAC;IAEZ,OAAO,mBAAmB,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write-note.d.ts","sourceRoot":"","sources":["../../src/vault/write-note.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"write-note.d.ts","sourceRoot":"","sources":["../../src/vault/write-note.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAQD;;;;GAIG;AACH,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,MAAM,CAAC,CAOjB"}
|
package/dist/vault/write-note.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { mkdir } from "node:fs/promises";
|
|
2
2
|
import { writeUniqueMarkdown } from "../util/fs.js";
|
|
3
3
|
import { timestampedBasename } from "../util/timestamp-slug.js";
|
|
4
|
+
import { yamlDoubleQuoted } from "../util/yaml.js";
|
|
5
|
+
function buildNoteContent(text, topics) {
|
|
6
|
+
if (!topics || topics.length === 0)
|
|
7
|
+
return text;
|
|
8
|
+
const items = topics.map((t) => yamlDoubleQuoted(t)).join(", ");
|
|
9
|
+
return `---\ntopics: [${items}]\n---\n\n${text}`;
|
|
10
|
+
}
|
|
4
11
|
/**
|
|
5
12
|
* Writes a new note markdown file under `notesDir` (created if missing).
|
|
6
13
|
* Never overwrites — exclusive create with `_NN` on collision.
|
|
@@ -10,6 +17,7 @@ export async function writeNote(notesDir, text, options = {}) {
|
|
|
10
17
|
const now = options.now ?? new Date();
|
|
11
18
|
await mkdir(notesDir, { recursive: true });
|
|
12
19
|
const basename = timestampedBasename(text, { title: options.title, now });
|
|
13
|
-
|
|
20
|
+
const content = buildNoteContent(text, options.topics);
|
|
21
|
+
return writeUniqueMarkdown(notesDir, basename, content);
|
|
14
22
|
}
|
|
15
23
|
//# sourceMappingURL=write-note.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write-note.js","sourceRoot":"","sources":["../../src/vault/write-note.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"write-note.js","sourceRoot":"","sources":["../../src/vault/write-note.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AASnD,SAAS,gBAAgB,CAAC,IAAY,EAAE,MAAiB;IACvD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAChD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChE,OAAO,iBAAiB,KAAK,aAAa,IAAI,EAAE,CAAC;AACnD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,QAAgB,EAChB,IAAY,EACZ,UAA4B,EAAE;IAE9B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;IACtC,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3C,MAAM,QAAQ,GAAG,mBAAmB,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACvD,OAAO,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AAC1D,CAAC"}
|
|
@@ -4,6 +4,8 @@ export interface WritePlanOptions {
|
|
|
4
4
|
projectId: string;
|
|
5
5
|
/** When true, overwrite an existing plan (preserving original `created`). */
|
|
6
6
|
force?: boolean;
|
|
7
|
+
/** 3-5 topic keywords for search (flat list, omitted when empty/unset). */
|
|
8
|
+
topics?: string[];
|
|
7
9
|
/** Timestamp for `created` / `updated` (default: now). */
|
|
8
10
|
now?: Date;
|
|
9
11
|
}
|
|
@@ -15,6 +17,7 @@ export interface WritePlanResult {
|
|
|
15
17
|
/**
|
|
16
18
|
* Overwrites an existing plan at an absolute path.
|
|
17
19
|
* Preserves original `created` (falls back to `now` if missing) and sets `updated`.
|
|
20
|
+
* Omitting `topics` keeps existing frontmatter topics; passing `topics` replaces them.
|
|
18
21
|
* Caller must validate the path (e.g. inside this project's `plans/` dir).
|
|
19
22
|
*/
|
|
20
23
|
export declare function updatePlanAtPath(filePath: string, body: string, options: Omit<WritePlanOptions, "force">): Promise<WritePlanResult>;
|
|
@@ -23,6 +26,7 @@ export declare function updatePlanAtPath(filePath: string, body: string, options
|
|
|
23
26
|
* Target is always `plansDir/<name>.md` — no collision suffixes.
|
|
24
27
|
* Without `force`, an existing file is left untouched and status `"exists"` is returned.
|
|
25
28
|
* With `force`, overwrites the body, preserves original `created`, and sets `updated`.
|
|
29
|
+
* Omitting `topics` on overwrite keeps existing frontmatter topics.
|
|
26
30
|
*/
|
|
27
31
|
export declare function writePlan(plansDir: string, name: string, body: string, options: WritePlanOptions): Promise<WritePlanResult>;
|
|
28
32
|
//# sourceMappingURL=write-plan.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write-plan.d.ts","sourceRoot":"","sources":["../../src/vault/write-plan.ts"],"names":[],"mappings":"AAMA,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0DAA0D;IAC1D,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,aAAa,GAAG,QAAQ,CAAC;AAEnE,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,eAAe,CAAC;CACzB;
|
|
1
|
+
{"version":3,"file":"write-plan.d.ts","sourceRoot":"","sources":["../../src/vault/write-plan.ts"],"names":[],"mappings":"AAMA,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,0DAA0D;IAC1D,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,aAAa,GAAG,QAAQ,CAAC;AAEnE,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,eAAe,CAAC;CACzB;AAwBD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC,GACvC,OAAO,CAAC,eAAe,CAAC,CAkB1B;AAED;;;;;;GAMG;AACH,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,eAAe,CAAC,CA4B1B"}
|
package/dist/vault/write-plan.js
CHANGED
|
@@ -12,12 +12,17 @@ function buildFrontmatter(options) {
|
|
|
12
12
|
if (options.updated) {
|
|
13
13
|
lines.push(`updated: ${yamlDoubleQuoted(options.updated)}`);
|
|
14
14
|
}
|
|
15
|
+
if (options.topics && options.topics.length > 0) {
|
|
16
|
+
const items = options.topics.map((t) => yamlDoubleQuoted(t)).join(", ");
|
|
17
|
+
lines.push(`topics: [${items}]`);
|
|
18
|
+
}
|
|
15
19
|
lines.push("---");
|
|
16
20
|
return `${lines.join("\n")}\n\n`;
|
|
17
21
|
}
|
|
18
22
|
/**
|
|
19
23
|
* Overwrites an existing plan at an absolute path.
|
|
20
24
|
* Preserves original `created` (falls back to `now` if missing) and sets `updated`.
|
|
25
|
+
* Omitting `topics` keeps existing frontmatter topics; passing `topics` replaces them.
|
|
21
26
|
* Caller must validate the path (e.g. inside this project's `plans/` dir).
|
|
22
27
|
*/
|
|
23
28
|
export async function updatePlanAtPath(filePath, body, options) {
|
|
@@ -26,10 +31,12 @@ export async function updatePlanAtPath(filePath, body, options) {
|
|
|
26
31
|
const fm = parseHandoffFrontmatter(existing);
|
|
27
32
|
const created = fm.created ?? now.toISOString();
|
|
28
33
|
const updated = now.toISOString();
|
|
34
|
+
const topics = options.topics ?? fm.topics;
|
|
29
35
|
const content = buildFrontmatter({
|
|
30
36
|
projectId: options.projectId,
|
|
31
37
|
created,
|
|
32
38
|
updated,
|
|
39
|
+
topics,
|
|
33
40
|
}) + body;
|
|
34
41
|
await writeFile(filePath, content, "utf8");
|
|
35
42
|
return { path: filePath, status: "overwritten" };
|
|
@@ -39,6 +46,7 @@ export async function updatePlanAtPath(filePath, body, options) {
|
|
|
39
46
|
* Target is always `plansDir/<name>.md` — no collision suffixes.
|
|
40
47
|
* Without `force`, an existing file is left untouched and status `"exists"` is returned.
|
|
41
48
|
* With `force`, overwrites the body, preserves original `created`, and sets `updated`.
|
|
49
|
+
* Omitting `topics` on overwrite keeps existing frontmatter topics.
|
|
42
50
|
*/
|
|
43
51
|
export async function writePlan(plansDir, name, body, options) {
|
|
44
52
|
const now = options.now ?? new Date();
|
|
@@ -49,11 +57,16 @@ export async function writePlan(plansDir, name, body, options) {
|
|
|
49
57
|
return { path: filePath, status: "exists" };
|
|
50
58
|
}
|
|
51
59
|
if (exists && options.force) {
|
|
52
|
-
return updatePlanAtPath(filePath, body, {
|
|
60
|
+
return updatePlanAtPath(filePath, body, {
|
|
61
|
+
projectId: options.projectId,
|
|
62
|
+
topics: options.topics,
|
|
63
|
+
now,
|
|
64
|
+
});
|
|
53
65
|
}
|
|
54
66
|
const content = buildFrontmatter({
|
|
55
67
|
projectId: options.projectId,
|
|
56
68
|
created: now.toISOString(),
|
|
69
|
+
topics: options.topics,
|
|
57
70
|
}) + body;
|
|
58
71
|
await writeFile(filePath, content, "utf8");
|
|
59
72
|
return { path: filePath, status: "created" };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write-plan.js","sourceRoot":"","sources":["../../src/vault/write-plan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"write-plan.js","sourceRoot":"","sources":["../../src/vault/write-plan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAqBnD,SAAS,gBAAgB,CAAC,OAKzB;IACC,MAAM,KAAK,GAAG;QACZ,KAAK;QACL,YAAY,gBAAgB,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;QACjD,YAAY,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;KAChD,CAAC;IACF,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,KAAK,CAAC,IAAI,CAAC,YAAY,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChD,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxE,KAAK,CAAC,IAAI,CAAC,YAAY,KAAK,GAAG,CAAC,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AACnC,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAAgB,EAChB,IAAY,EACZ,OAAwC;IAExC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;IACtC,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAClD,MAAM,EAAE,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;IAChD,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,MAAM,CAAC;IAE3C,MAAM,OAAO,GACX,gBAAgB,CAAC;QACf,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,OAAO;QACP,OAAO;QACP,MAAM;KACP,CAAC,GAAG,IAAI,CAAC;IAEZ,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC3C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;AACnD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,QAAgB,EAChB,IAAY,EACZ,IAAY,EACZ,OAAyB;IAEzB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;IACtC,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC;IAE1C,IAAI,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAC9C,CAAC;IAED,IAAI,MAAM,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAC5B,OAAO,gBAAgB,CAAC,QAAQ,EAAE,IAAI,EAAE;YACtC,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,GAAG;SACJ,CAAC,CAAC;IACL,CAAC;IAED,MAAM,OAAO,GACX,gBAAgB,CAAC;QACf,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,OAAO,EAAE,GAAG,CAAC,WAAW,EAAE;QAC1B,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,GAAG,IAAI,CAAC;IAEZ,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC3C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AAC/C,CAAC"}
|