@vortex-os/base 0.0.1 → 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/README.md +50 -36
- package/dist/index.d.ts +1526 -23
- package/dist/index.js +3279 -20
- package/dist/index.js.map +1 -1
- package/package.json +16 -9
- package/dist/index.d.ts.map +0 -1
- package/src/index.ts +0 -33
package/dist/index.d.ts
CHANGED
|
@@ -1,24 +1,1527 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
2
|
+
* Three-tier privacy classification used across VortEX.
|
|
3
|
+
*
|
|
4
|
+
* - `public` — safe to share with anyone, including in published repositories.
|
|
5
|
+
* - `internal` — visible to the operator and their organization; not for public release.
|
|
6
|
+
* - `personal` — personal data; never shared, never published.
|
|
7
|
+
*/
|
|
8
|
+
declare const Privacy: {
|
|
9
|
+
readonly Public: "public";
|
|
10
|
+
readonly Internal: "internal";
|
|
11
|
+
readonly Personal: "personal";
|
|
12
|
+
};
|
|
13
|
+
type Privacy = (typeof Privacy)[keyof typeof Privacy];
|
|
14
|
+
/**
|
|
15
|
+
* Parsed markdown document with separated YAML frontmatter and body.
|
|
16
|
+
*/
|
|
17
|
+
interface FrontmatterDoc<T = Record<string, unknown>> {
|
|
18
|
+
frontmatter: T & {
|
|
19
|
+
privacy?: Privacy;
|
|
20
|
+
};
|
|
21
|
+
body: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Resolved paths for a VortEX repository root.
|
|
25
|
+
*
|
|
26
|
+
* Every module receives a `ModuleContext` from the host (CLI, plugin runtime,
|
|
27
|
+
* or test harness) and resolves its own paths against it. Modules must not
|
|
28
|
+
* derive paths by string manipulation against an assumed layout.
|
|
29
|
+
*/
|
|
30
|
+
interface ModuleContext {
|
|
31
|
+
repoRoot: string;
|
|
32
|
+
agentDir: string;
|
|
33
|
+
dataDir: string;
|
|
34
|
+
modulesDir: string;
|
|
35
|
+
pluginsDir: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Parse a markdown source into its YAML frontmatter and body. If no frontmatter
|
|
40
|
+
* fence is present, returns an empty frontmatter object and the source unchanged.
|
|
41
|
+
*
|
|
42
|
+
* A leading UTF-8 BOM is stripped before matching. Windows-authored files
|
|
43
|
+
* frequently begin with ``, which would otherwise prevent the fence
|
|
44
|
+
* regex from anchoring to `---` at byte 0.
|
|
45
|
+
*/
|
|
46
|
+
declare function parseFrontmatter<T = Record<string, unknown>>(source: string): FrontmatterDoc<T>;
|
|
47
|
+
/**
|
|
48
|
+
* Serialize a `FrontmatterDoc` back into markdown text. If the frontmatter is
|
|
49
|
+
* empty, the body is returned unchanged (no empty fence is emitted).
|
|
50
|
+
*/
|
|
51
|
+
declare function serializeFrontmatter<T = Record<string, unknown>>(doc: FrontmatterDoc<T>): string;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Returns true if a document with `docPrivacy` is visible to a viewer authorized
|
|
55
|
+
* at `viewerPrivacy`. Viewers see content at or below their own level.
|
|
56
|
+
*
|
|
57
|
+
* - `public` viewer sees → public only
|
|
58
|
+
* - `internal` viewer sees → public + internal
|
|
59
|
+
* - `personal` viewer sees → all three
|
|
60
|
+
*/
|
|
61
|
+
declare function isVisibleAt(docPrivacy: Privacy, viewerPrivacy: Privacy): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Returns the more-restrictive of two privacy levels.
|
|
64
|
+
* Useful when combining content from multiple sources for sharing.
|
|
65
|
+
*/
|
|
66
|
+
declare function maxPrivacy(a: Privacy, b: Privacy): Privacy;
|
|
67
|
+
/**
|
|
68
|
+
* Coerce an unknown value (e.g. user input or untyped frontmatter) into a
|
|
69
|
+
* valid `Privacy`. Falls back to `internal` by default — the safest default
|
|
70
|
+
* for unclassified content.
|
|
71
|
+
*/
|
|
72
|
+
declare function normalizePrivacy(value: unknown, fallback?: Privacy): Privacy;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Build a `ModuleContext` for the given VortEX repository root. The root is
|
|
76
|
+
* resolved to an absolute path; standard subdirectories are derived by
|
|
77
|
+
* convention and are not guaranteed to exist on disk.
|
|
78
|
+
*/
|
|
79
|
+
declare function makeContext(repoRoot: string): ModuleContext;
|
|
80
|
+
/**
|
|
81
|
+
* Resolve the directory of a named module within the repository.
|
|
82
|
+
*/
|
|
83
|
+
declare function moduleDir(ctx: ModuleContext, moduleName: string): string;
|
|
84
|
+
|
|
85
|
+
//# sourceMappingURL=index.d.ts.map
|
|
86
|
+
|
|
87
|
+
type index_d$c_FrontmatterDoc<T = Record<string, unknown>> = FrontmatterDoc<T>;
|
|
88
|
+
type index_d$c_ModuleContext = ModuleContext;
|
|
89
|
+
type index_d$c_Privacy = Privacy;
|
|
90
|
+
declare const index_d$c_isVisibleAt: typeof isVisibleAt;
|
|
91
|
+
declare const index_d$c_makeContext: typeof makeContext;
|
|
92
|
+
declare const index_d$c_maxPrivacy: typeof maxPrivacy;
|
|
93
|
+
declare const index_d$c_moduleDir: typeof moduleDir;
|
|
94
|
+
declare const index_d$c_normalizePrivacy: typeof normalizePrivacy;
|
|
95
|
+
declare const index_d$c_parseFrontmatter: typeof parseFrontmatter;
|
|
96
|
+
declare const index_d$c_serializeFrontmatter: typeof serializeFrontmatter;
|
|
97
|
+
declare namespace index_d$c {
|
|
98
|
+
export { type index_d$c_FrontmatterDoc as FrontmatterDoc, type index_d$c_ModuleContext as ModuleContext, type index_d$c_Privacy as Privacy, index_d$c_isVisibleAt as isVisibleAt, index_d$c_makeContext as makeContext, index_d$c_maxPrivacy as maxPrivacy, index_d$c_moduleDir as moduleDir, index_d$c_normalizePrivacy as normalizePrivacy, index_d$c_parseFrontmatter as parseFrontmatter, index_d$c_serializeFrontmatter as serializeFrontmatter };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Declaration of a single argument expected by a command.
|
|
103
|
+
*
|
|
104
|
+
* Argument parsing in Phase 2 is positional: arguments are read from the
|
|
105
|
+
* tokens following the command name, in declaration order. Named flags
|
|
106
|
+
* (e.g. `--foo bar`) are not handled at this layer — hosts that need them
|
|
107
|
+
* can pre-process input before calling `runSlash`.
|
|
108
|
+
*/
|
|
109
|
+
interface CommandArg {
|
|
110
|
+
readonly name: string;
|
|
111
|
+
readonly description: string;
|
|
112
|
+
readonly required?: boolean;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Value passed to a command's handler.
|
|
116
|
+
*
|
|
117
|
+
* - `raw` — the full input string with any leading `/` removed.
|
|
118
|
+
* - `args` — positional arguments matched against the command's declared
|
|
119
|
+
* `args` schema, keyed by argument name.
|
|
120
|
+
* - `rest` — the unparsed trailing portion of the input (everything after
|
|
121
|
+
* the command name), provided as-is for commands that prefer to handle
|
|
122
|
+
* their own parsing.
|
|
123
|
+
* - `context` — resolved repository paths from `@vortex-os/core.makeContext`.
|
|
124
|
+
*/
|
|
125
|
+
interface CommandInput {
|
|
126
|
+
readonly raw: string;
|
|
127
|
+
readonly args: Readonly<Record<string, string>>;
|
|
128
|
+
readonly rest: string;
|
|
129
|
+
readonly context: ModuleContext;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* A registrable, callable command.
|
|
133
|
+
*/
|
|
134
|
+
interface Command<Result = unknown> {
|
|
135
|
+
readonly name: string;
|
|
136
|
+
readonly description: string;
|
|
137
|
+
readonly args?: readonly CommandArg[];
|
|
138
|
+
readonly handler: (input: CommandInput) => Result | Promise<Result>;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Holds registered commands and looks them up by name.
|
|
143
|
+
*
|
|
144
|
+
* Names are matched exactly. Registering two commands with the same name
|
|
145
|
+
* is an error — the second call throws. Callers that want to override an
|
|
146
|
+
* existing command must `unregister` first.
|
|
147
|
+
*/
|
|
148
|
+
declare class CommandRegistry {
|
|
149
|
+
private readonly commands;
|
|
150
|
+
register(command: Command): void;
|
|
151
|
+
unregister(name: string): boolean;
|
|
152
|
+
has(name: string): boolean;
|
|
153
|
+
get(name: string): Command | undefined;
|
|
154
|
+
list(): readonly Command[];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
interface RunOptions {
|
|
158
|
+
readonly registry: CommandRegistry;
|
|
159
|
+
readonly context: ModuleContext;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Thrown by `runSlash` when the requested command name does not exist
|
|
163
|
+
* in the registry. The unknown name is exposed for caller diagnostics.
|
|
164
|
+
*/
|
|
165
|
+
declare class CommandNotFoundError extends Error {
|
|
166
|
+
readonly commandName: string;
|
|
167
|
+
constructor(commandName: string);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Parse an input string and dispatch the matching command.
|
|
171
|
+
*
|
|
172
|
+
* Accepted forms (leading slash optional):
|
|
173
|
+
* "name"
|
|
174
|
+
* "/name"
|
|
175
|
+
* "name arg1 arg2 ..."
|
|
176
|
+
*
|
|
177
|
+
* Returns whatever the command's handler returns (awaited if it is async).
|
|
178
|
+
*/
|
|
179
|
+
declare function runSlash(input: string, { registry, context }: RunOptions): Promise<unknown>;
|
|
180
|
+
|
|
181
|
+
//# sourceMappingURL=index.d.ts.map
|
|
182
|
+
|
|
183
|
+
type index_d$b_Command<Result = unknown> = Command<Result>;
|
|
184
|
+
type index_d$b_CommandArg = CommandArg;
|
|
185
|
+
type index_d$b_CommandInput = CommandInput;
|
|
186
|
+
type index_d$b_CommandNotFoundError = CommandNotFoundError;
|
|
187
|
+
declare const index_d$b_CommandNotFoundError: typeof CommandNotFoundError;
|
|
188
|
+
type index_d$b_CommandRegistry = CommandRegistry;
|
|
189
|
+
declare const index_d$b_CommandRegistry: typeof CommandRegistry;
|
|
190
|
+
type index_d$b_RunOptions = RunOptions;
|
|
191
|
+
declare const index_d$b_runSlash: typeof runSlash;
|
|
192
|
+
declare namespace index_d$b {
|
|
193
|
+
export { type index_d$b_Command as Command, type index_d$b_CommandArg as CommandArg, type index_d$b_CommandInput as CommandInput, index_d$b_CommandNotFoundError as CommandNotFoundError, index_d$b_CommandRegistry as CommandRegistry, type index_d$b_RunOptions as RunOptions, index_d$b_runSlash as runSlash };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Canonical memory categories.
|
|
198
|
+
*
|
|
199
|
+
* - `user` — facts about the operator (role, preferences, working style).
|
|
200
|
+
* - `feedback` — corrections and validated approaches from the operator.
|
|
201
|
+
* - `project` — ongoing work context (goals, deadlines, stakeholders).
|
|
202
|
+
* - `reference` — pointers to external systems (dashboards, repos, channels).
|
|
203
|
+
*
|
|
204
|
+
* Hosts may extend the set, but stability of these four is preserved.
|
|
205
|
+
*/
|
|
206
|
+
declare const MemoryType: {
|
|
207
|
+
readonly User: "user";
|
|
208
|
+
readonly Feedback: "feedback";
|
|
209
|
+
readonly Project: "project";
|
|
210
|
+
readonly Reference: "reference";
|
|
211
|
+
};
|
|
212
|
+
type MemoryType = (typeof MemoryType)[keyof typeof MemoryType];
|
|
213
|
+
/**
|
|
214
|
+
* Frontmatter required on every memory file.
|
|
215
|
+
*
|
|
216
|
+
* `name` should match the file id (filename without `.md`). `description`
|
|
217
|
+
* is a single-line summary used in the generated index. `type` places the
|
|
218
|
+
* memory in one of the canonical categories. Additional keys (e.g.
|
|
219
|
+
* `originSessionId`, `created`, custom tags) are tolerated and preserved
|
|
220
|
+
* on round-trip but are not required.
|
|
221
|
+
*/
|
|
222
|
+
interface MemoryFrontmatter {
|
|
223
|
+
name: string;
|
|
224
|
+
description: string;
|
|
225
|
+
type: MemoryType;
|
|
226
|
+
[key: string]: unknown;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* A parsed memory document, ready to be written back or rendered.
|
|
230
|
+
*
|
|
231
|
+
* `id` is the filename stem (no `.md`); it is the address by which the
|
|
232
|
+
* store retrieves and overwrites the memory.
|
|
233
|
+
*/
|
|
234
|
+
interface Memory {
|
|
235
|
+
id: string;
|
|
236
|
+
frontmatter: MemoryFrontmatter;
|
|
237
|
+
body: string;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* A directory-backed memory store.
|
|
242
|
+
*
|
|
243
|
+
* Each memory lives in a single `.md` file. The `MEMORY.md` (generated index)
|
|
244
|
+
* and `_INDEX.md` (Obsidian-friendly index) files are excluded — they are
|
|
245
|
+
* derived views, not memories themselves.
|
|
246
|
+
*/
|
|
247
|
+
declare class MemoryStore {
|
|
248
|
+
readonly dir: string;
|
|
249
|
+
constructor(dir: string);
|
|
250
|
+
/** Ensure the backing directory exists. Safe to call repeatedly. */
|
|
251
|
+
ensure(): Promise<void>;
|
|
252
|
+
/** List memory ids (filename stems), sorted lexicographically. */
|
|
253
|
+
list(): Promise<readonly string[]>;
|
|
254
|
+
/** Read a memory by id. Throws if the file does not exist. */
|
|
255
|
+
read(id: string): Promise<Memory>;
|
|
256
|
+
/** Write (or overwrite) a memory. Ensures the directory exists first. */
|
|
257
|
+
write(memory: Memory): Promise<void>;
|
|
258
|
+
/** Delete a memory. Returns false if it did not exist. */
|
|
259
|
+
delete(id: string): Promise<boolean>;
|
|
260
|
+
/** Test whether a memory exists by id. */
|
|
261
|
+
has(id: string): Promise<boolean>;
|
|
262
|
+
/** Absolute path of a memory file (file may not exist). */
|
|
263
|
+
pathFor(id: string): string;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
interface WriteMemoryIndexOptions {
|
|
267
|
+
/** Top-level heading. Defaults to "Memory Index". */
|
|
268
|
+
title?: string;
|
|
269
|
+
/** Optional text placed above the heading (e.g. an HTML comment). */
|
|
270
|
+
preamble?: string;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Render a `MEMORY.md` index from the entries currently in `store` and
|
|
274
|
+
* write it to `<store.dir>/MEMORY.md`. Existing `MEMORY.md` is overwritten.
|
|
275
|
+
*
|
|
276
|
+
* The index is a flat bullet list: one line per memory, linking to the
|
|
277
|
+
* memory file and including the memory's `description`.
|
|
278
|
+
*/
|
|
279
|
+
declare function writeMemoryIndex(store: MemoryStore, options?: WriteMemoryIndexOptions): Promise<void>;
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Difference between two memory stores. All three lists may be empty,
|
|
283
|
+
* which means the stores are in sync.
|
|
284
|
+
*/
|
|
285
|
+
interface SyncDiff {
|
|
286
|
+
/** Ids present in `a` but not in `b`. */
|
|
287
|
+
onlyInA: readonly string[];
|
|
288
|
+
/** Ids present in `b` but not in `a`. */
|
|
289
|
+
onlyInB: readonly string[];
|
|
290
|
+
/** Ids present in both but whose raw file contents differ. */
|
|
291
|
+
changed: readonly string[];
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Compute the diff between two memory stores. Neither store is modified.
|
|
295
|
+
*
|
|
296
|
+
* `changed` is determined by exact byte comparison of the underlying
|
|
297
|
+
* `.md` files. Frontmatter ordering or whitespace differences therefore
|
|
298
|
+
* count as a change — callers that want semantic equality should
|
|
299
|
+
* re-serialize through `parseFrontmatter` / `serializeFrontmatter` before
|
|
300
|
+
* comparing.
|
|
301
|
+
*/
|
|
302
|
+
declare function diffStores(a: MemoryStore, b: MemoryStore): Promise<SyncDiff>;
|
|
303
|
+
|
|
304
|
+
//# sourceMappingURL=index.d.ts.map
|
|
305
|
+
|
|
306
|
+
type index_d$a_Memory = Memory;
|
|
307
|
+
type index_d$a_MemoryFrontmatter = MemoryFrontmatter;
|
|
308
|
+
type index_d$a_MemoryStore = MemoryStore;
|
|
309
|
+
declare const index_d$a_MemoryStore: typeof MemoryStore;
|
|
310
|
+
type index_d$a_MemoryType = MemoryType;
|
|
311
|
+
type index_d$a_SyncDiff = SyncDiff;
|
|
312
|
+
type index_d$a_WriteMemoryIndexOptions = WriteMemoryIndexOptions;
|
|
313
|
+
declare const index_d$a_diffStores: typeof diffStores;
|
|
314
|
+
declare const index_d$a_writeMemoryIndex: typeof writeMemoryIndex;
|
|
315
|
+
declare namespace index_d$a {
|
|
316
|
+
export { type index_d$a_Memory as Memory, type index_d$a_MemoryFrontmatter as MemoryFrontmatter, index_d$a_MemoryStore as MemoryStore, type index_d$a_MemoryType as MemoryType, type index_d$a_SyncDiff as SyncDiff, type index_d$a_WriteMemoryIndexOptions as WriteMemoryIndexOptions, index_d$a_diffStores as diffStores, index_d$a_writeMemoryIndex as writeMemoryIndex };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
type Severity = "error" | "warning" | "info";
|
|
320
|
+
/**
|
|
321
|
+
* A single problem found by a rule.
|
|
322
|
+
*/
|
|
323
|
+
interface LintFinding {
|
|
324
|
+
readonly rule: string;
|
|
325
|
+
readonly severity: Severity;
|
|
326
|
+
readonly file: string;
|
|
327
|
+
readonly line?: number;
|
|
328
|
+
readonly message: string;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Input passed to a rule's `check` function.
|
|
332
|
+
*/
|
|
333
|
+
interface LintInput {
|
|
334
|
+
readonly file: string;
|
|
335
|
+
readonly content: string;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* A registrable lint rule.
|
|
339
|
+
*
|
|
340
|
+
* Rules are pure: same input produces the same findings, no side effects.
|
|
341
|
+
* `check` may be async — useful for rules that need to consult other
|
|
342
|
+
* files (e.g. resolving wiki links).
|
|
343
|
+
*/
|
|
344
|
+
interface LintRule {
|
|
345
|
+
readonly id: string;
|
|
346
|
+
readonly description: string;
|
|
347
|
+
readonly check: (input: LintInput) => readonly LintFinding[] | Promise<readonly LintFinding[]>;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Aggregated result of a lint run.
|
|
351
|
+
*/
|
|
352
|
+
interface LintReport {
|
|
353
|
+
readonly findings: readonly LintFinding[];
|
|
354
|
+
readonly filesScanned: number;
|
|
355
|
+
readonly rulesRun: number;
|
|
356
|
+
readonly durationMs: number;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
interface LintOptions {
|
|
360
|
+
/** Directory to scan recursively. */
|
|
361
|
+
readonly dir: string;
|
|
362
|
+
/** Rules to apply to every file. */
|
|
363
|
+
readonly rules: readonly LintRule[];
|
|
364
|
+
/** File extensions to include. Defaults to `[".md"]`. */
|
|
365
|
+
readonly extensions?: readonly string[];
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Recursively scan `dir` for files with the configured extensions and run
|
|
369
|
+
* every rule against each file. Findings from all rules are aggregated into
|
|
370
|
+
* a single `LintReport`. Order of findings within the report is not
|
|
371
|
+
* guaranteed beyond "file by file, rule by rule".
|
|
372
|
+
*/
|
|
373
|
+
declare function lintDirectory(options: LintOptions): Promise<LintReport>;
|
|
374
|
+
|
|
375
|
+
interface RequireFrontmatterOptions {
|
|
376
|
+
/** Frontmatter keys that must be present and non-empty. */
|
|
377
|
+
readonly required: readonly string[];
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Rule that ensures the listed frontmatter keys are present and non-empty.
|
|
381
|
+
* Empty string, null, and undefined values all fail the check; `0`, `false`,
|
|
382
|
+
* and structured values (arrays, objects) pass as long as they exist.
|
|
383
|
+
*/
|
|
384
|
+
declare function requireFrontmatter(options: RequireFrontmatterOptions): LintRule;
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Rule that ensures, if a `privacy` frontmatter field is present, its value
|
|
388
|
+
* is one of the canonical three: `public`, `internal`, `personal`.
|
|
389
|
+
* Documents without any `privacy` field pass.
|
|
390
|
+
*/
|
|
391
|
+
declare function privacyValid(): LintRule;
|
|
392
|
+
|
|
393
|
+
interface WikiLinkResolvesOptions {
|
|
394
|
+
/** Directory under which valid link targets live. Searched recursively. */
|
|
395
|
+
readonly searchRoot: string;
|
|
396
|
+
/** Target file extensions. Defaults to `[".md"]`. */
|
|
397
|
+
readonly extensions?: readonly string[];
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Rule that checks wiki-style links `[[target]]` resolve to an existing
|
|
401
|
+
* file under `searchRoot` (by basename match, recursive). Aliases
|
|
402
|
+
* (`[[target|alias]]`) and anchors (`[[target#section]]`) are stripped
|
|
403
|
+
* before lookup.
|
|
404
|
+
*
|
|
405
|
+
* The target index is built lazily on the first invocation and cached for
|
|
406
|
+
* the lifetime of the rule instance.
|
|
407
|
+
*/
|
|
408
|
+
declare function wikiLinkResolves(options: WikiLinkResolvesOptions): LintRule;
|
|
409
|
+
|
|
410
|
+
//# sourceMappingURL=index.d.ts.map
|
|
411
|
+
|
|
412
|
+
type index_d$9_LintFinding = LintFinding;
|
|
413
|
+
type index_d$9_LintInput = LintInput;
|
|
414
|
+
type index_d$9_LintOptions = LintOptions;
|
|
415
|
+
type index_d$9_LintReport = LintReport;
|
|
416
|
+
type index_d$9_LintRule = LintRule;
|
|
417
|
+
type index_d$9_RequireFrontmatterOptions = RequireFrontmatterOptions;
|
|
418
|
+
type index_d$9_Severity = Severity;
|
|
419
|
+
type index_d$9_WikiLinkResolvesOptions = WikiLinkResolvesOptions;
|
|
420
|
+
declare const index_d$9_lintDirectory: typeof lintDirectory;
|
|
421
|
+
declare const index_d$9_privacyValid: typeof privacyValid;
|
|
422
|
+
declare const index_d$9_requireFrontmatter: typeof requireFrontmatter;
|
|
423
|
+
declare const index_d$9_wikiLinkResolves: typeof wikiLinkResolves;
|
|
424
|
+
declare namespace index_d$9 {
|
|
425
|
+
export { type index_d$9_LintFinding as LintFinding, type index_d$9_LintInput as LintInput, type index_d$9_LintOptions as LintOptions, type index_d$9_LintReport as LintReport, type index_d$9_LintRule as LintRule, type index_d$9_RequireFrontmatterOptions as RequireFrontmatterOptions, type index_d$9_Severity as Severity, type index_d$9_WikiLinkResolvesOptions as WikiLinkResolvesOptions, index_d$9_lintDirectory as lintDirectory, index_d$9_privacyValid as privacyValid, index_d$9_requireFrontmatter as requireFrontmatter, index_d$9_wikiLinkResolves as wikiLinkResolves };
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
type PitfallSeverity = "info" | "warning" | "error";
|
|
429
|
+
/**
|
|
430
|
+
* A single AI coding pitfall.
|
|
431
|
+
*
|
|
432
|
+
* Pitfalls describe failure modes that recur across AI coding work, along
|
|
433
|
+
* with how to recognize them and what to do instead. They are catalog
|
|
434
|
+
* entries, not active detectors.
|
|
435
|
+
*/
|
|
436
|
+
interface Pitfall {
|
|
437
|
+
readonly id: string;
|
|
438
|
+
readonly title: string;
|
|
439
|
+
readonly category: string;
|
|
440
|
+
readonly severity: PitfallSeverity;
|
|
441
|
+
readonly signal: string;
|
|
442
|
+
readonly cause: string;
|
|
443
|
+
readonly mitigation: string;
|
|
444
|
+
/** Free-form trailing markdown (examples, notes); empty string if none. */
|
|
445
|
+
readonly body: string;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Frontmatter shape expected on a pitfall `.md` file.
|
|
449
|
+
*
|
|
450
|
+
* `id` is optional in the source — if omitted, the filename stem is used.
|
|
451
|
+
*/
|
|
452
|
+
interface PitfallFrontmatter {
|
|
453
|
+
id?: string;
|
|
454
|
+
title: string;
|
|
455
|
+
category: string;
|
|
456
|
+
severity: PitfallSeverity;
|
|
457
|
+
signal: string;
|
|
458
|
+
cause: string;
|
|
459
|
+
mitigation: string;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Directory-backed pitfall catalog. One `.md` file per pitfall.
|
|
464
|
+
*
|
|
465
|
+
* The catalog reads all `.md` files in `dir` on each query (no caching).
|
|
466
|
+
* Callers that need cached behavior should wrap or call `list()` once and
|
|
467
|
+
* reuse the result.
|
|
468
|
+
*/
|
|
469
|
+
declare class PitfallCatalog {
|
|
470
|
+
readonly dir: string;
|
|
471
|
+
constructor(dir: string);
|
|
472
|
+
/** Load every pitfall in the directory, sorted by id. */
|
|
473
|
+
list(): Promise<readonly Pitfall[]>;
|
|
474
|
+
/** Load a single pitfall by id. Returns `undefined` if not found. */
|
|
475
|
+
get(id: string): Promise<Pitfall | undefined>;
|
|
476
|
+
/** Return only pitfalls matching the given category. */
|
|
477
|
+
filterByCategory(category: string): Promise<readonly Pitfall[]>;
|
|
478
|
+
private entries;
|
|
479
|
+
private loadFile;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
//# sourceMappingURL=index.d.ts.map
|
|
483
|
+
|
|
484
|
+
type index_d$8_Pitfall = Pitfall;
|
|
485
|
+
type index_d$8_PitfallCatalog = PitfallCatalog;
|
|
486
|
+
declare const index_d$8_PitfallCatalog: typeof PitfallCatalog;
|
|
487
|
+
type index_d$8_PitfallFrontmatter = PitfallFrontmatter;
|
|
488
|
+
type index_d$8_PitfallSeverity = PitfallSeverity;
|
|
489
|
+
declare namespace index_d$8 {
|
|
490
|
+
export { type index_d$8_Pitfall as Pitfall, index_d$8_PitfallCatalog as PitfallCatalog, type index_d$8_PitfallFrontmatter as PitfallFrontmatter, type index_d$8_PitfallSeverity as PitfallSeverity };
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
type ToolRuleSeverity = "advisory" | "strict" | "absolute";
|
|
494
|
+
/**
|
|
495
|
+
* A single tool-usage rule.
|
|
496
|
+
*
|
|
497
|
+
* Tool rules express constraints the operator wants agents to obey when
|
|
498
|
+
* invoking specific tools. They are catalog entries, not active enforcers.
|
|
499
|
+
*/
|
|
500
|
+
interface ToolRule {
|
|
501
|
+
readonly id: string;
|
|
502
|
+
readonly title: string;
|
|
503
|
+
readonly scope: string;
|
|
504
|
+
readonly severity: ToolRuleSeverity;
|
|
505
|
+
readonly condition: string;
|
|
506
|
+
readonly action: string;
|
|
507
|
+
/** Free-form trailing markdown (examples, notes); empty string if none. */
|
|
508
|
+
readonly body: string;
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Frontmatter shape expected on a tool-rule `.md` file.
|
|
512
|
+
*
|
|
513
|
+
* `id` is optional in the source — if omitted, the filename stem is used.
|
|
514
|
+
*/
|
|
515
|
+
interface ToolRuleFrontmatter {
|
|
516
|
+
id?: string;
|
|
517
|
+
title: string;
|
|
518
|
+
scope: string;
|
|
519
|
+
severity: ToolRuleSeverity;
|
|
520
|
+
condition: string;
|
|
521
|
+
action: string;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Directory-backed tool-rule catalog. One `.md` file per rule.
|
|
526
|
+
*
|
|
527
|
+
* The catalog reads all `.md` files in `dir` on each query (no caching).
|
|
528
|
+
*/
|
|
529
|
+
declare class ToolRuleCatalog {
|
|
530
|
+
readonly dir: string;
|
|
531
|
+
constructor(dir: string);
|
|
532
|
+
/** Load every rule in the directory, sorted by id. */
|
|
533
|
+
list(): Promise<readonly ToolRule[]>;
|
|
534
|
+
/** Load a single rule by id. Returns `undefined` if not found. */
|
|
535
|
+
get(id: string): Promise<ToolRule | undefined>;
|
|
536
|
+
/** Return only rules whose `scope` matches exactly. */
|
|
537
|
+
filterByScope(scope: string): Promise<readonly ToolRule[]>;
|
|
538
|
+
/** Return only rules whose `severity` matches. */
|
|
539
|
+
filterBySeverity(severity: ToolRuleSeverity): Promise<readonly ToolRule[]>;
|
|
540
|
+
private entries;
|
|
541
|
+
private loadFile;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
//# sourceMappingURL=index.d.ts.map
|
|
545
|
+
|
|
546
|
+
type index_d$7_ToolRule = ToolRule;
|
|
547
|
+
type index_d$7_ToolRuleCatalog = ToolRuleCatalog;
|
|
548
|
+
declare const index_d$7_ToolRuleCatalog: typeof ToolRuleCatalog;
|
|
549
|
+
type index_d$7_ToolRuleFrontmatter = ToolRuleFrontmatter;
|
|
550
|
+
type index_d$7_ToolRuleSeverity = ToolRuleSeverity;
|
|
551
|
+
declare namespace index_d$7 {
|
|
552
|
+
export { type index_d$7_ToolRule as ToolRule, index_d$7_ToolRuleCatalog as ToolRuleCatalog, type index_d$7_ToolRuleFrontmatter as ToolRuleFrontmatter, type index_d$7_ToolRuleSeverity as ToolRuleSeverity };
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
interface RenderOptions {
|
|
556
|
+
/** Target viewer privacy level. Content above this is stripped. */
|
|
557
|
+
readonly targetPrivacy: Privacy;
|
|
558
|
+
/**
|
|
559
|
+
* Optional HTML template. The placeholders `{{title}}` and `{{content}}`
|
|
560
|
+
* are replaced. If omitted, a minimal default template is used.
|
|
561
|
+
*/
|
|
562
|
+
readonly template?: string;
|
|
563
|
+
/** Optional title for the `{{title}}` placeholder. */
|
|
564
|
+
readonly title?: string;
|
|
565
|
+
}
|
|
566
|
+
type WarningKind = "section-stripped" | "document-not-visible";
|
|
567
|
+
interface RenderWarning {
|
|
568
|
+
readonly kind: WarningKind;
|
|
569
|
+
readonly reason: string;
|
|
570
|
+
}
|
|
571
|
+
interface RenderResult {
|
|
572
|
+
/** Rendered HTML. Empty string if the document is not visible at target. */
|
|
573
|
+
readonly html: string;
|
|
574
|
+
/** Effective document privacy (frontmatter value or default `internal`). */
|
|
575
|
+
readonly documentPrivacy: Privacy;
|
|
576
|
+
/** Whether the document was visible at the requested target privacy. */
|
|
577
|
+
readonly visible: boolean;
|
|
578
|
+
/** Warnings collected during render (stripped sections, skipped docs). */
|
|
579
|
+
readonly warnings: readonly RenderWarning[];
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Render a markdown source to HTML, applying document-level and
|
|
584
|
+
* section-level privacy filtering before conversion.
|
|
585
|
+
*
|
|
586
|
+
* If the document's own privacy exceeds the target, an empty result is
|
|
587
|
+
* returned with a `document-not-visible` warning and no body conversion
|
|
588
|
+
* is performed.
|
|
589
|
+
*/
|
|
590
|
+
declare function renderHtml(source: string, options: RenderOptions): Promise<RenderResult>;
|
|
591
|
+
|
|
592
|
+
interface StripResult {
|
|
593
|
+
readonly content: string;
|
|
594
|
+
readonly warnings: readonly RenderWarning[];
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Remove section blocks whose declared privacy exceeds the target.
|
|
598
|
+
*
|
|
599
|
+
* Each section is delimited by `<!-- vortex:privacy LEVEL -->` and
|
|
600
|
+
* `<!-- /vortex:privacy -->`. Sections at or below target privacy keep
|
|
601
|
+
* their body (markers themselves are removed). Sections above target are
|
|
602
|
+
* stripped entirely and a `section-stripped` warning is reported.
|
|
603
|
+
*
|
|
604
|
+
* Sections do not nest; the parser does not support nesting.
|
|
605
|
+
*/
|
|
606
|
+
declare function stripPrivateSections(content: string, targetPrivacy: Privacy): StripResult;
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Minimal default template. Hosts that want styling, navigation, or
|
|
610
|
+
* additional metadata should pass a custom `template` to `renderHtml`.
|
|
611
|
+
*/
|
|
612
|
+
declare const DEFAULT_TEMPLATE = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>{{title}}</title>\n</head>\n<body>\n{{content}}\n</body>\n</html>\n";
|
|
613
|
+
/**
|
|
614
|
+
* Replace `{{name}}` placeholders in a template string with values from
|
|
615
|
+
* `vars`. Missing keys are replaced with the empty string.
|
|
616
|
+
*/
|
|
617
|
+
declare function applyTemplate(template: string, vars: Readonly<Record<string, string>>): string;
|
|
618
|
+
|
|
619
|
+
//# sourceMappingURL=index.d.ts.map
|
|
620
|
+
|
|
621
|
+
declare const index_d$6_DEFAULT_TEMPLATE: typeof DEFAULT_TEMPLATE;
|
|
622
|
+
type index_d$6_RenderOptions = RenderOptions;
|
|
623
|
+
type index_d$6_RenderResult = RenderResult;
|
|
624
|
+
type index_d$6_RenderWarning = RenderWarning;
|
|
625
|
+
type index_d$6_StripResult = StripResult;
|
|
626
|
+
type index_d$6_WarningKind = WarningKind;
|
|
627
|
+
declare const index_d$6_applyTemplate: typeof applyTemplate;
|
|
628
|
+
declare const index_d$6_renderHtml: typeof renderHtml;
|
|
629
|
+
declare const index_d$6_stripPrivateSections: typeof stripPrivateSections;
|
|
630
|
+
declare namespace index_d$6 {
|
|
631
|
+
export { index_d$6_DEFAULT_TEMPLATE as DEFAULT_TEMPLATE, type index_d$6_RenderOptions as RenderOptions, type index_d$6_RenderResult as RenderResult, type index_d$6_RenderWarning as RenderWarning, type index_d$6_StripResult as StripResult, type index_d$6_WarningKind as WarningKind, index_d$6_applyTemplate as applyTemplate, index_d$6_renderHtml as renderHtml, index_d$6_stripPrivateSections as stripPrivateSections };
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Frontmatter expected on a TIL file. All fields besides `type` are
|
|
636
|
+
* conventional — the store tolerates absence and surfaces what is present.
|
|
637
|
+
*/
|
|
638
|
+
interface TilFrontmatter {
|
|
639
|
+
type: "til";
|
|
640
|
+
status?: string;
|
|
641
|
+
privacy?: string;
|
|
642
|
+
created?: string;
|
|
643
|
+
updated?: string;
|
|
644
|
+
tags?: readonly string[];
|
|
645
|
+
related?: readonly string[];
|
|
646
|
+
[key: string]: unknown;
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* A parsed TIL entry.
|
|
650
|
+
*
|
|
651
|
+
* `date` is the ISO date portion of the filename (`YYYY-MM-DD`).
|
|
652
|
+
* `keyword` is the trailing slug portion of the filename without `.md`.
|
|
653
|
+
* `path` is the absolute path of the file on disk.
|
|
654
|
+
*/
|
|
655
|
+
interface TilEntry {
|
|
656
|
+
readonly date: string;
|
|
657
|
+
readonly keyword: string;
|
|
658
|
+
readonly path: string;
|
|
659
|
+
readonly frontmatter: TilFrontmatter;
|
|
660
|
+
readonly body: string;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Directory-backed TIL store. Expected layout: `<rootDir>/YYYY/MM/YYYY-MM-DD-keyword.md`.
|
|
665
|
+
*
|
|
666
|
+
* The store treats missing subdirectories as empty, never as errors —
|
|
667
|
+
* a brand-new month with no entries returns an empty list, not a throw.
|
|
668
|
+
*/
|
|
669
|
+
declare class TilStore {
|
|
670
|
+
readonly rootDir: string;
|
|
671
|
+
constructor(rootDir: string);
|
|
672
|
+
/** All entries across all years and months, sorted by date ascending. */
|
|
673
|
+
list(): Promise<readonly TilEntry[]>;
|
|
674
|
+
/** Entries within one calendar month. */
|
|
675
|
+
listByMonth(year: number, month: number): Promise<readonly TilEntry[]>;
|
|
676
|
+
/**
|
|
677
|
+
* The first entry matching `date` (`YYYY-MM-DD`). If multiple files exist
|
|
678
|
+
* for that date with different keywords, the lexicographically-first one
|
|
679
|
+
* is returned. Use `list()` when all are needed.
|
|
680
|
+
*/
|
|
681
|
+
get(date: string): Promise<TilEntry | undefined>;
|
|
682
|
+
/** Most recent entry by date (descending), then keyword (descending). */
|
|
683
|
+
getLatest(): Promise<TilEntry | undefined>;
|
|
684
|
+
/** Resolve the file path for a given (date, keyword), without creating it. */
|
|
685
|
+
pathFor(date: string, keyword: string): string;
|
|
686
|
+
private listSubdirs;
|
|
687
|
+
private entriesIn;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Append a new section to the end of an existing TIL entry's file.
|
|
692
|
+
*
|
|
693
|
+
* The resulting markdown adds two leading blank lines, then `## <title>`,
|
|
694
|
+
* then a blank line, then the body. The entry's frontmatter is not touched.
|
|
695
|
+
*
|
|
696
|
+
* Returns the updated raw markdown that was written.
|
|
697
|
+
*/
|
|
698
|
+
declare function appendSection(entry: TilEntry, title: string, body: string): Promise<string>;
|
|
699
|
+
|
|
700
|
+
//# sourceMappingURL=index.d.ts.map
|
|
701
|
+
|
|
702
|
+
type index_d$5_TilEntry = TilEntry;
|
|
703
|
+
type index_d$5_TilFrontmatter = TilFrontmatter;
|
|
704
|
+
type index_d$5_TilStore = TilStore;
|
|
705
|
+
declare const index_d$5_TilStore: typeof TilStore;
|
|
706
|
+
declare const index_d$5_appendSection: typeof appendSection;
|
|
707
|
+
declare namespace index_d$5 {
|
|
708
|
+
export { type index_d$5_TilEntry as TilEntry, type index_d$5_TilFrontmatter as TilFrontmatter, index_d$5_TilStore as TilStore, index_d$5_appendSection as appendSection };
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Frontmatter expected on a Decision-Log entry. `type` is the only required
|
|
713
|
+
* field — the store tolerates absence of the rest and surfaces what is present.
|
|
714
|
+
*
|
|
715
|
+
* `privacy` defaults to `personal` by convention; callers should not rely on
|
|
716
|
+
* the store to enforce it.
|
|
717
|
+
*/
|
|
718
|
+
interface DecisionLogFrontmatter {
|
|
719
|
+
type: "decision-log";
|
|
720
|
+
status?: "active" | "template" | "archived" | string;
|
|
721
|
+
privacy?: "personal" | "internal" | "public" | string;
|
|
722
|
+
created?: string;
|
|
723
|
+
updated?: string;
|
|
724
|
+
tags?: readonly string[];
|
|
725
|
+
related?: readonly string[];
|
|
726
|
+
[key: string]: unknown;
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* A parsed Decision-Log entry.
|
|
730
|
+
*
|
|
731
|
+
* `date` is the ISO date portion of the filename (`YYYY-MM-DD`).
|
|
732
|
+
* `slug` is the trailing portion of the filename without `.md`.
|
|
733
|
+
* `path` is the absolute path of the file on disk.
|
|
734
|
+
*/
|
|
735
|
+
interface DecisionEntry {
|
|
736
|
+
readonly date: string;
|
|
737
|
+
readonly slug: string;
|
|
738
|
+
readonly path: string;
|
|
739
|
+
readonly frontmatter: DecisionLogFrontmatter;
|
|
740
|
+
readonly body: string;
|
|
741
|
+
}
|
|
742
|
+
/** Filter criteria for {@link DecisionStore.filter}. Empty filter matches all. */
|
|
743
|
+
interface DecisionFilter {
|
|
744
|
+
/** Match entries with `frontmatter.status` equal to this value. */
|
|
745
|
+
status?: string;
|
|
746
|
+
/** Match entries that contain this tag (case-sensitive). */
|
|
747
|
+
tag?: string;
|
|
748
|
+
/** Match entries with date >= this value (`YYYY-MM-DD`). */
|
|
749
|
+
fromDate?: string;
|
|
750
|
+
/** Match entries with date <= this value (`YYYY-MM-DD`). */
|
|
751
|
+
toDate?: string;
|
|
752
|
+
}
|
|
753
|
+
/** Input for {@link renderTemplate}. */
|
|
754
|
+
interface DecisionTemplateInput {
|
|
755
|
+
/** ISO date (`YYYY-MM-DD`). Also written into the body header. */
|
|
756
|
+
date: string;
|
|
757
|
+
/** Short kebab-style identifier used in the filename. */
|
|
758
|
+
slug: string;
|
|
759
|
+
/** One-line decision title shown as the H1. */
|
|
760
|
+
title: string;
|
|
761
|
+
/** Free-form area label (e.g. `work`, `personal`, `home-lab`). */
|
|
762
|
+
area?: string;
|
|
763
|
+
/** Extra tags appended after the default `decision-log` tag. */
|
|
764
|
+
tags?: readonly string[];
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Directory-backed Decision-Log store. Expected layout is flat —
|
|
769
|
+
* `<rootDir>/YYYY-MM-DD-<slug>.md`, no year/month subdirectories.
|
|
770
|
+
*
|
|
771
|
+
* Non-entry files at the root (README, _TEMPLATE, anything not matching
|
|
772
|
+
* the date-prefix pattern) are silently ignored.
|
|
773
|
+
*
|
|
774
|
+
* A missing root directory returns an empty list rather than throwing,
|
|
775
|
+
* so a brand-new template clone with no entries is a normal state.
|
|
776
|
+
*/
|
|
777
|
+
declare class DecisionStore {
|
|
778
|
+
readonly rootDir: string;
|
|
779
|
+
constructor(rootDir: string);
|
|
780
|
+
/** All entries, sorted by date ascending, then slug ascending. */
|
|
781
|
+
list(): Promise<readonly DecisionEntry[]>;
|
|
782
|
+
/**
|
|
783
|
+
* Entries whose filename starts with `date` (`YYYY-MM-DD`). Multiple
|
|
784
|
+
* decisions on the same day are returned in slug-ascending order.
|
|
785
|
+
*/
|
|
786
|
+
getByDate(date: string): Promise<readonly DecisionEntry[]>;
|
|
787
|
+
/**
|
|
788
|
+
* The first entry matching `date` and (optionally) `slug`. When no slug is
|
|
789
|
+
* provided and multiple entries share the date, the lexicographically-first
|
|
790
|
+
* one is returned.
|
|
791
|
+
*/
|
|
792
|
+
get(date: string, slug?: string): Promise<DecisionEntry | undefined>;
|
|
793
|
+
/** Most recent entry by date (descending), then slug (descending). */
|
|
794
|
+
getLatest(): Promise<DecisionEntry | undefined>;
|
|
795
|
+
/**
|
|
796
|
+
* Subset of entries matching the given criteria. Empty/undefined fields
|
|
797
|
+
* are ignored. Returns entries in the same order as {@link list}.
|
|
798
|
+
*/
|
|
799
|
+
filter(criteria: DecisionFilter): Promise<readonly DecisionEntry[]>;
|
|
800
|
+
/** Resolve the file path for a given (date, slug), without creating it. */
|
|
801
|
+
pathFor(date: string, slug: string): string;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* Render a new Decision-Log entry body using an obsidian-style template
|
|
806
|
+
* convention. Caller is responsible for writing the result to disk via
|
|
807
|
+
* {@link DecisionStore.pathFor}.
|
|
808
|
+
*
|
|
809
|
+
* The output deliberately mirrors a human-authored template so the
|
|
810
|
+
* shape stays consistent whether the entry was created by hand or by
|
|
811
|
+
* this helper.
|
|
812
|
+
*/
|
|
813
|
+
declare function renderTemplate(input: DecisionTemplateInput): string;
|
|
814
|
+
|
|
815
|
+
//# sourceMappingURL=index.d.ts.map
|
|
816
|
+
|
|
817
|
+
type index_d$4_DecisionEntry = DecisionEntry;
|
|
818
|
+
type index_d$4_DecisionFilter = DecisionFilter;
|
|
819
|
+
type index_d$4_DecisionLogFrontmatter = DecisionLogFrontmatter;
|
|
820
|
+
type index_d$4_DecisionStore = DecisionStore;
|
|
821
|
+
declare const index_d$4_DecisionStore: typeof DecisionStore;
|
|
822
|
+
type index_d$4_DecisionTemplateInput = DecisionTemplateInput;
|
|
823
|
+
declare const index_d$4_renderTemplate: typeof renderTemplate;
|
|
824
|
+
declare namespace index_d$4 {
|
|
825
|
+
export { type index_d$4_DecisionEntry as DecisionEntry, type index_d$4_DecisionFilter as DecisionFilter, type index_d$4_DecisionLogFrontmatter as DecisionLogFrontmatter, index_d$4_DecisionStore as DecisionStore, type index_d$4_DecisionTemplateInput as DecisionTemplateInput, index_d$4_renderTemplate as renderTemplate };
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* One entry surfaced in a generated `_INDEX.md`.
|
|
830
|
+
*/
|
|
831
|
+
interface IndexEntry {
|
|
832
|
+
/** Path relative to the directory being indexed (forward slashes). */
|
|
833
|
+
readonly relPath: string;
|
|
834
|
+
/** Filename without extension. */
|
|
835
|
+
readonly name: string;
|
|
836
|
+
/** Title — `# H1` from the body, or filename fallback. */
|
|
837
|
+
readonly title: string;
|
|
838
|
+
/** Short description — frontmatter `description`, or first body paragraph fallback. */
|
|
839
|
+
readonly description?: string;
|
|
840
|
+
/** Frontmatter `type` value, if present (e.g. `til`, `decision-log`, `memory`). */
|
|
841
|
+
readonly type?: string;
|
|
842
|
+
/** Frontmatter `updated` or `created` value, ISO `YYYY-MM-DD` when parseable. */
|
|
843
|
+
readonly updated?: string;
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Options controlling {@link scanDirectory}.
|
|
847
|
+
*/
|
|
848
|
+
interface ScanOptions {
|
|
849
|
+
/**
|
|
850
|
+
* Recurse into subdirectories. Default: false (flat scan).
|
|
851
|
+
*
|
|
852
|
+
* When true, the scanner descends into all subdirectories whose name does
|
|
853
|
+
* not start with `.` or `_`. The reserved files `README.md` and
|
|
854
|
+
* `_INDEX.md` are always skipped at every depth.
|
|
855
|
+
*/
|
|
856
|
+
recursive?: boolean;
|
|
857
|
+
/**
|
|
858
|
+
* Filenames to skip in addition to the always-skipped reserved files
|
|
859
|
+
* (`README.md`, `_INDEX.md`). Comparison is case-sensitive on the basename.
|
|
860
|
+
*/
|
|
861
|
+
skipFilenames?: readonly string[];
|
|
862
|
+
/**
|
|
863
|
+
* Filename prefixes to skip (e.g. `["_TEMPLATE"]`). Comparison is
|
|
864
|
+
* case-sensitive against the basename without extension.
|
|
865
|
+
*/
|
|
866
|
+
skipPrefixes?: readonly string[];
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* Input for {@link renderIndex}.
|
|
870
|
+
*/
|
|
871
|
+
interface RenderIndexInput {
|
|
872
|
+
/** Page H1 — typically the directory's human name (e.g. "Memory", "TIL"). */
|
|
873
|
+
title: string;
|
|
874
|
+
/**
|
|
875
|
+
* One-line blockquote shown beneath the H1. Pass an empty string to omit
|
|
876
|
+
* the blockquote.
|
|
877
|
+
*/
|
|
878
|
+
description?: string;
|
|
879
|
+
/** Entries to list. Order is preserved as given. */
|
|
880
|
+
entries: readonly IndexEntry[];
|
|
881
|
+
/** Frontmatter `updated` field. Default: today's date in `YYYY-MM-DD`. */
|
|
882
|
+
updated?: string;
|
|
883
|
+
/** Frontmatter `privacy` field. Default: `internal`. */
|
|
884
|
+
privacy?: "public" | "internal" | "personal" | string;
|
|
885
|
+
/** Extra frontmatter tags besides the default `[index]`. */
|
|
886
|
+
extraTags?: readonly string[];
|
|
887
|
+
/** Optional "관련" links rendered after the entry list. */
|
|
888
|
+
related?: readonly string[];
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/**
|
|
892
|
+
* Scan a directory of markdown notes and produce one {@link IndexEntry}
|
|
893
|
+
* per file, sorted by `relPath` ascending.
|
|
894
|
+
*
|
|
895
|
+
* - Files whose names are `README.md` or `_INDEX.md` are always skipped.
|
|
896
|
+
* - Hidden entries (name starting with `.` or `_`, except `_TEMPLATE` which
|
|
897
|
+
* is still surfaced but can be excluded via `skipPrefixes: ["_TEMPLATE"]`)
|
|
898
|
+
* are not descended into when `recursive: true`.
|
|
899
|
+
* - A missing directory returns an empty list rather than throwing.
|
|
900
|
+
*/
|
|
901
|
+
declare function scanDirectory(rootDir: string, opts?: ScanOptions): Promise<readonly IndexEntry[]>;
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Render an `_INDEX.md` body from a {@link RenderIndexInput}.
|
|
905
|
+
*
|
|
906
|
+
* Output shape:
|
|
907
|
+
*
|
|
908
|
+
* ---
|
|
909
|
+
* type: index
|
|
910
|
+
* status: active
|
|
911
|
+
* privacy: <privacy>
|
|
912
|
+
* updated: <updated>
|
|
913
|
+
* tags: [index, <extraTags...>]
|
|
914
|
+
* ---
|
|
915
|
+
*
|
|
916
|
+
* # <title>
|
|
917
|
+
*
|
|
918
|
+
* > <description>
|
|
919
|
+
*
|
|
920
|
+
* ## 항목 (<count>)
|
|
921
|
+
*
|
|
922
|
+
* | 파일 | 설명 | 갱신 |
|
|
923
|
+
* |---|---|---|
|
|
924
|
+
* | [[<name>]] | <description or title> | <updated> |
|
|
925
|
+
* ...
|
|
926
|
+
*
|
|
927
|
+
* ## 관련 (only if `related` is non-empty)
|
|
928
|
+
*
|
|
929
|
+
* - [[<related[0]>]]
|
|
930
|
+
* ...
|
|
931
|
+
*
|
|
932
|
+
* Caller is responsible for writing this body to disk. The renderer never
|
|
933
|
+
* touches the filesystem.
|
|
934
|
+
*/
|
|
935
|
+
declare function renderIndex(input: RenderIndexInput): string;
|
|
936
|
+
|
|
937
|
+
/**
|
|
938
|
+
* Walk a directory tree and return every subdirectory that contains at
|
|
939
|
+
* least `minEntries` markdown files at its top level. The root directory
|
|
940
|
+
* itself is included if it qualifies.
|
|
941
|
+
*
|
|
942
|
+
* "At its top level" means `.md` files **directly inside** the directory
|
|
943
|
+
* (not in its subdirectories) — this is what an `_INDEX.md` in that
|
|
944
|
+
* directory would index.
|
|
945
|
+
*
|
|
946
|
+
* `README.md` and `_INDEX.md` files are not counted (they are not
|
|
947
|
+
* indexable entries). `.md` files starting with prefixes in `skipPrefixes`
|
|
948
|
+
* are also not counted.
|
|
949
|
+
*
|
|
950
|
+
* Hidden directories (`.foo`) are not descended into. `_foo` directories
|
|
951
|
+
* are descended into — they may legitimately contain content
|
|
952
|
+
* (`_HUB-*.md`, `_INDEX.md` of subdirectories).
|
|
953
|
+
*
|
|
954
|
+
* A missing root directory returns an empty list rather than throwing.
|
|
955
|
+
*
|
|
956
|
+
* Use case — splitting a giant flat `_INDEX.md` into per-folder
|
|
957
|
+
* indexes: scan a tree, find the meaningful directories, write an
|
|
958
|
+
* `_INDEX.md` in each.
|
|
959
|
+
*/
|
|
960
|
+
declare function findIndexableDirs(rootDir: string, options?: {
|
|
961
|
+
minEntries?: number;
|
|
962
|
+
skipPrefixes?: readonly string[];
|
|
963
|
+
}): Promise<readonly string[]>;
|
|
964
|
+
|
|
965
|
+
//# sourceMappingURL=index.d.ts.map
|
|
966
|
+
|
|
967
|
+
type index_d$3_IndexEntry = IndexEntry;
|
|
968
|
+
type index_d$3_RenderIndexInput = RenderIndexInput;
|
|
969
|
+
type index_d$3_ScanOptions = ScanOptions;
|
|
970
|
+
declare const index_d$3_findIndexableDirs: typeof findIndexableDirs;
|
|
971
|
+
declare const index_d$3_renderIndex: typeof renderIndex;
|
|
972
|
+
declare const index_d$3_scanDirectory: typeof scanDirectory;
|
|
973
|
+
declare namespace index_d$3 {
|
|
974
|
+
export { type index_d$3_IndexEntry as IndexEntry, type index_d$3_RenderIndexInput as RenderIndexInput, type index_d$3_ScanOptions as ScanOptions, index_d$3_findIndexableDirs as findIndexableDirs, index_d$3_renderIndex as renderIndex, index_d$3_scanDirectory as scanDirectory };
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/**
|
|
978
|
+
* Frontmatter expected on a Runbook entry. `type` is the only required
|
|
979
|
+
* field; the store tolerates absence of the rest and surfaces what is present.
|
|
980
|
+
*/
|
|
981
|
+
interface RunbookFrontmatter {
|
|
982
|
+
type: "runbook";
|
|
983
|
+
status?: "active" | "draft" | "archived" | string;
|
|
984
|
+
privacy?: "public" | "internal" | "personal" | string;
|
|
985
|
+
/** ISO date (`YYYY-MM-DD`) when this runbook was last verified end-to-end. */
|
|
986
|
+
last_tested?: string;
|
|
987
|
+
/** Free-form incident category (e.g. `네트워크-순단`, `mail-outage`). */
|
|
988
|
+
"incident-type"?: string;
|
|
989
|
+
created?: string;
|
|
990
|
+
updated?: string;
|
|
991
|
+
tags?: readonly string[];
|
|
992
|
+
related?: readonly string[] | string;
|
|
993
|
+
[key: string]: unknown;
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* A parsed runbook entry.
|
|
997
|
+
*
|
|
998
|
+
* `slug` is the filename without the `.md` extension. Runbooks live in a
|
|
999
|
+
* flat directory — no date-prefix convention, since the name is typically
|
|
1000
|
+
* descriptive (`K3s-노드-재부팅-절차`, `메일서버-Mbox-장애복구`).
|
|
1001
|
+
*/
|
|
1002
|
+
interface RunbookEntry {
|
|
1003
|
+
readonly slug: string;
|
|
1004
|
+
readonly path: string;
|
|
1005
|
+
readonly frontmatter: RunbookFrontmatter;
|
|
1006
|
+
readonly body: string;
|
|
1007
|
+
}
|
|
1008
|
+
/** Filter criteria for {@link RunbookStore.filter}. */
|
|
1009
|
+
interface RunbookFilter {
|
|
1010
|
+
/** Match entries with `frontmatter.status` equal to this value. */
|
|
1011
|
+
status?: string;
|
|
1012
|
+
/** Match entries that contain this tag (case-sensitive). */
|
|
1013
|
+
tag?: string;
|
|
1014
|
+
/** Match entries with `frontmatter['incident-type']` equal to this value. */
|
|
1015
|
+
incidentType?: string;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
/**
|
|
1019
|
+
* Directory-backed runbook store. Expected layout is flat —
|
|
1020
|
+
* `<rootDir>/<slug>.md`, no subdirectories.
|
|
1021
|
+
*
|
|
1022
|
+
* Non-entry files at the root (README, _INDEX, anything not ending in `.md`)
|
|
1023
|
+
* are silently ignored. A missing root directory returns an empty list
|
|
1024
|
+
* rather than throwing.
|
|
1025
|
+
*/
|
|
1026
|
+
declare class RunbookStore {
|
|
1027
|
+
readonly rootDir: string;
|
|
1028
|
+
constructor(rootDir: string);
|
|
1029
|
+
/** All entries, sorted by slug ascending. */
|
|
1030
|
+
list(): Promise<readonly RunbookEntry[]>;
|
|
1031
|
+
/** A single entry by slug, or undefined if not found. */
|
|
1032
|
+
get(slug: string): Promise<RunbookEntry | undefined>;
|
|
1033
|
+
/**
|
|
1034
|
+
* Subset of entries matching the given criteria. Empty/undefined fields
|
|
1035
|
+
* are ignored. Returns entries in the same order as {@link list}.
|
|
1036
|
+
*/
|
|
1037
|
+
filter(criteria: RunbookFilter): Promise<readonly RunbookEntry[]>;
|
|
1038
|
+
/**
|
|
1039
|
+
* Entries whose `last_tested` is older than `staleAfterDays` from the
|
|
1040
|
+
* given reference date (default: today). Entries without a `last_tested`
|
|
1041
|
+
* field are treated as "never tested" and are always returned.
|
|
1042
|
+
*
|
|
1043
|
+
* This is the practical reason runbooks are a module rather than plain
|
|
1044
|
+
* data — periodic reverification is a real operational need.
|
|
1045
|
+
*/
|
|
1046
|
+
getStaleByLastTested(staleAfterDays: number, referenceDate?: Date): Promise<readonly RunbookEntry[]>;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
//# sourceMappingURL=index.d.ts.map
|
|
1050
|
+
|
|
1051
|
+
type index_d$2_RunbookEntry = RunbookEntry;
|
|
1052
|
+
type index_d$2_RunbookFilter = RunbookFilter;
|
|
1053
|
+
type index_d$2_RunbookFrontmatter = RunbookFrontmatter;
|
|
1054
|
+
type index_d$2_RunbookStore = RunbookStore;
|
|
1055
|
+
declare const index_d$2_RunbookStore: typeof RunbookStore;
|
|
1056
|
+
declare namespace index_d$2 {
|
|
1057
|
+
export { type index_d$2_RunbookEntry as RunbookEntry, type index_d$2_RunbookFilter as RunbookFilter, type index_d$2_RunbookFrontmatter as RunbookFrontmatter, index_d$2_RunbookStore as RunbookStore };
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
/**
|
|
1061
|
+
* A wiki link extracted from a markdown body.
|
|
1062
|
+
*
|
|
1063
|
+
* Examples (input → parsed shape):
|
|
1064
|
+
* `[[Foo]]` → { name: "Foo" }
|
|
1065
|
+
* `[[Foo|bar]]` → { name: "Foo", alias: "bar" }
|
|
1066
|
+
* `[[Foo#Section]]` → { name: "Foo", anchor: "Section" }
|
|
1067
|
+
* `[[Foo#Sec|bar]]` → { name: "Foo", anchor: "Sec", alias: "bar" }
|
|
1068
|
+
*/
|
|
1069
|
+
interface WikiLink {
|
|
1070
|
+
/** Target page name as written, without the `.md` extension. */
|
|
1071
|
+
readonly name: string;
|
|
1072
|
+
/** Section anchor after `#`, if present. */
|
|
1073
|
+
readonly anchor?: string;
|
|
1074
|
+
/** Display alias after `|`, if present. */
|
|
1075
|
+
readonly alias?: string;
|
|
1076
|
+
/** Original raw text including `[[...]]` brackets. */
|
|
1077
|
+
readonly raw: string;
|
|
1078
|
+
}
|
|
1079
|
+
/**
|
|
1080
|
+
* A wiki link that did not resolve against the filesystem index.
|
|
1081
|
+
*
|
|
1082
|
+
* `sourcePath` is the absolute path of the file that contained the link.
|
|
1083
|
+
* `link` is the parsed link itself. Reason is a short string identifying
|
|
1084
|
+
* why resolution failed (e.g. `not-found`).
|
|
1085
|
+
*/
|
|
1086
|
+
interface BrokenLink {
|
|
1087
|
+
readonly sourcePath: string;
|
|
1088
|
+
readonly link: WikiLink;
|
|
1089
|
+
readonly reason: "not-found" | "ambiguous";
|
|
1090
|
+
/** When `ambiguous`, the candidate paths that matched the name. */
|
|
1091
|
+
readonly candidates?: readonly string[];
|
|
1092
|
+
}
|
|
1093
|
+
/**
|
|
1094
|
+
* Aggregate result of {@link checkDirectory}.
|
|
1095
|
+
*/
|
|
1096
|
+
interface LinkCheckResult {
|
|
1097
|
+
/** Number of `.md` files scanned. */
|
|
1098
|
+
readonly filesScanned: number;
|
|
1099
|
+
/** Total wiki links encountered across all files. */
|
|
1100
|
+
readonly totalLinks: number;
|
|
1101
|
+
/** Links that resolved to a unique target. */
|
|
1102
|
+
readonly resolved: number;
|
|
1103
|
+
/** Detail of unresolved links. */
|
|
1104
|
+
readonly broken: readonly BrokenLink[];
|
|
1105
|
+
/** Detail of ambiguous links (name matched multiple files). */
|
|
1106
|
+
readonly ambiguous: readonly BrokenLink[];
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
/**
|
|
1110
|
+
* Extract every wiki link from a markdown body. Returns links in
|
|
1111
|
+
* document order; duplicates are preserved (callers can dedupe if they
|
|
1112
|
+
* want, but a broken link in two places is still two repairs).
|
|
1113
|
+
*
|
|
1114
|
+
* Code fences and inline code spans are not stripped — this module
|
|
1115
|
+
* treats markdown as text. Hosts that need to ignore links inside
|
|
1116
|
+
* code blocks should pre-filter the body.
|
|
1117
|
+
*/
|
|
1118
|
+
declare function extractWikiLinks(body: string): readonly WikiLink[];
|
|
1119
|
+
|
|
1120
|
+
/**
|
|
1121
|
+
* Filesystem index of every `.md` file under a root.
|
|
1122
|
+
*
|
|
1123
|
+
* Provides two lookup paths:
|
|
1124
|
+
*
|
|
1125
|
+
* - `byBasename` — `name` (no `.md`) → list of absolute paths. Used for
|
|
1126
|
+
* bare wiki links like `[[Foo]]`, which Obsidian resolves by filename
|
|
1127
|
+
* anywhere in the vault.
|
|
1128
|
+
* - `byRelPath` — forward-slash relative path (no `.md`) → absolute path.
|
|
1129
|
+
* Used for path-aware wiki links like `[[Projects/Home/Foo]]` or
|
|
1130
|
+
* `[[../Foo]]`, where the operator wrote a path on purpose to
|
|
1131
|
+
* disambiguate.
|
|
1132
|
+
*
|
|
1133
|
+
* `rootDir` is retained so resolvers can interpret root-relative paths.
|
|
1134
|
+
*/
|
|
1135
|
+
interface FileIndex {
|
|
1136
|
+
readonly byBasename: ReadonlyMap<string, readonly string[]>;
|
|
1137
|
+
readonly byRelPath: ReadonlyMap<string, string>;
|
|
1138
|
+
/**
|
|
1139
|
+
* Optional lowercase rel-path → absolute-path map for case-insensitive
|
|
1140
|
+
* fallback. Present only when {@link buildFileIndex} was called with
|
|
1141
|
+
* `caseInsensitive: true`. If two rel-paths collide after lowercasing,
|
|
1142
|
+
* the first walker-visited path wins; the conflict is silent (rare in
|
|
1143
|
+
* a well-organized tree).
|
|
1144
|
+
*/
|
|
1145
|
+
readonly byRelPathLower?: ReadonlyMap<string, string>;
|
|
1146
|
+
readonly rootDir: string;
|
|
1147
|
+
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Options for {@link buildFileIndex}.
|
|
1150
|
+
*/
|
|
1151
|
+
interface BuildIndexOptions {
|
|
1152
|
+
/**
|
|
1153
|
+
* Build an additional lowercase `byRelPathLower` map so {@link resolveLink}
|
|
1154
|
+
* can fall back to case-insensitive matching when the exact-case path
|
|
1155
|
+
* lookup fails. Useful when the operator's wiki-link convention uses
|
|
1156
|
+
* different casing than the on-disk layout (a frequent situation when
|
|
1157
|
+
* content is migrated from one vault into another with renamed roots,
|
|
1158
|
+
* e.g. `[[Projects/Home/foo]]` vs `data/projects/home/foo.md`).
|
|
1159
|
+
*
|
|
1160
|
+
* Default: false. Bare-name lookup is unaffected — Obsidian historically
|
|
1161
|
+
* treats bare names case-sensitively, and we keep that.
|
|
1162
|
+
*/
|
|
1163
|
+
caseInsensitive?: boolean;
|
|
1164
|
+
/**
|
|
1165
|
+
* Extra file extensions (besides `.md`) to include in the index. Each
|
|
1166
|
+
* extension must include the leading dot, e.g. `[".hwp", ".docx", ".pdf"]`.
|
|
1167
|
+
*
|
|
1168
|
+
* `.md` files are always indexed with the extension stripped from their
|
|
1169
|
+
* key — `[[Foo]]` matches `Foo.md`. Files with one of the additional
|
|
1170
|
+
* extensions are indexed with the extension *kept*, so they only match
|
|
1171
|
+
* when the operator writes the full filename — `[[Foo.hwp]]` matches
|
|
1172
|
+
* `Foo.hwp`. This avoids surprise collisions where `[[Foo]]` would
|
|
1173
|
+
* suddenly match a non-markdown file.
|
|
1174
|
+
*
|
|
1175
|
+
* Default: `[]` (only `.md` is indexed; preserves v1 behavior).
|
|
1176
|
+
*
|
|
1177
|
+
* Note: only `.md` files are scanned for wiki links by
|
|
1178
|
+
* {@link import("./checker.js").checkDirectory} and rewritten by
|
|
1179
|
+
* {@link import("./rewrite.js").rewriteDirectory}. Additional extensions
|
|
1180
|
+
* affect *resolution targets* (what a wiki link can point at), not
|
|
1181
|
+
* *scan sources* (what a wiki link can appear in).
|
|
1182
|
+
*/
|
|
1183
|
+
additionalExtensions?: readonly string[];
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
* Walk `rootDir` recursively and build a {@link FileIndex} of every `.md`
|
|
1187
|
+
* file (plus any `additionalExtensions` requested).
|
|
1188
|
+
*
|
|
1189
|
+
* Hidden directories (`.foo`) are skipped. `_foo` directories ARE indexed —
|
|
1190
|
+
* Obsidian wiki links can target any markdown file regardless of underscore
|
|
1191
|
+
* prefix, so we mirror that. A missing root returns an empty index.
|
|
1192
|
+
*/
|
|
1193
|
+
declare function buildFileIndex(rootDir: string, options?: BuildIndexOptions): Promise<FileIndex>;
|
|
1194
|
+
/**
|
|
1195
|
+
* Resolution outcome for a single wiki link.
|
|
1196
|
+
*
|
|
1197
|
+
* - `unique`: one and only one file matched.
|
|
1198
|
+
* - `not-found`: no file matched.
|
|
1199
|
+
* - `ambiguous`: multiple files share the basename (only possible for
|
|
1200
|
+
* bare-name links; path-aware links always resolve uniquely or fail).
|
|
1201
|
+
*/
|
|
1202
|
+
type ResolveOutcome = {
|
|
1203
|
+
kind: "unique";
|
|
1204
|
+
path: string;
|
|
1205
|
+
} | {
|
|
1206
|
+
kind: "not-found";
|
|
1207
|
+
} | {
|
|
1208
|
+
kind: "ambiguous";
|
|
1209
|
+
candidates: readonly string[];
|
|
1210
|
+
};
|
|
1211
|
+
/**
|
|
1212
|
+
* Optional hints that turn on path-aware resolution.
|
|
1213
|
+
*
|
|
1214
|
+
* - `sourcePath` — absolute path of the file the link was found in.
|
|
1215
|
+
* Required to resolve `../foo`-style relative links.
|
|
1216
|
+
*
|
|
1217
|
+
* When neither hint is set, behavior collapses to bare-name lookup
|
|
1218
|
+
* (basename only), matching the original v1 semantics.
|
|
1219
|
+
*/
|
|
1220
|
+
interface ResolveOpts {
|
|
1221
|
+
sourcePath?: string;
|
|
1222
|
+
}
|
|
1223
|
+
/**
|
|
1224
|
+
* Look up a wiki link in the index. Three cases:
|
|
1225
|
+
*
|
|
1226
|
+
* 1. **Bare name** (`[[Foo]]`) — basename lookup only. Returns `unique`
|
|
1227
|
+
* if exactly one `Foo.md` exists, `ambiguous` if multiple, `not-found`
|
|
1228
|
+
* otherwise.
|
|
1229
|
+
* 2. **Root-relative path** (`[[Projects/Foo]]`) — exact rel-path lookup
|
|
1230
|
+
* against the index. Always `unique` or `not-found`.
|
|
1231
|
+
* 3. **Source-relative path** (`[[../Foo]]`, `[[./Foo]]`) — resolved
|
|
1232
|
+
* against `dirname(sourcePath)` first, then looked up by rel-path.
|
|
1233
|
+
* Requires `opts.sourcePath`; without it, returns `not-found`.
|
|
1234
|
+
*
|
|
1235
|
+
* Trailing `.md` in the link name is stripped before matching.
|
|
1236
|
+
*/
|
|
1237
|
+
declare function resolveLink(name: string, index: FileIndex, opts?: ResolveOpts): ResolveOutcome;
|
|
1238
|
+
/**
|
|
1239
|
+
* Reduce an absolute path to one relative to `rootDir`, using forward
|
|
1240
|
+
* slashes. Useful for reporting.
|
|
1241
|
+
*/
|
|
1242
|
+
declare function toRel(path: string, rootDir: string): string;
|
|
1243
|
+
|
|
1244
|
+
/**
|
|
1245
|
+
* Options for {@link checkDirectory}.
|
|
1246
|
+
*/
|
|
1247
|
+
interface CheckDirectoryOptions extends BuildIndexOptions {
|
|
1248
|
+
}
|
|
1249
|
+
/**
|
|
1250
|
+
* Scan every `.md` file under `rootDir`, extract wiki links, and
|
|
1251
|
+
* report which ones cannot be resolved (or resolve to multiple files).
|
|
1252
|
+
*
|
|
1253
|
+
* This is read-only — it does not modify any file. The function returns
|
|
1254
|
+
* a structured result so hosts can decide whether to log, fail a build,
|
|
1255
|
+
* propose rewrites, etc.
|
|
1256
|
+
*
|
|
1257
|
+
* Pass `caseInsensitive: true` when wiki-link casing may differ from
|
|
1258
|
+
* the on-disk path (e.g. content migrated from a vault with different
|
|
1259
|
+
* directory naming conventions).
|
|
1260
|
+
*/
|
|
1261
|
+
declare function checkDirectory(rootDir: string, options?: CheckDirectoryOptions): Promise<LinkCheckResult>;
|
|
1262
|
+
/**
|
|
1263
|
+
* Group broken links by target name and return counts in descending order.
|
|
1264
|
+
* Useful for quickly identifying the most-cited missing pages.
|
|
1265
|
+
*/
|
|
1266
|
+
declare function topBrokenTargets(broken: readonly BrokenLink[], limit?: number): readonly {
|
|
1267
|
+
readonly name: string;
|
|
1268
|
+
readonly count: number;
|
|
1269
|
+
}[];
|
|
1270
|
+
|
|
1271
|
+
/**
|
|
1272
|
+
* Map of wiki-link names to replace.
|
|
1273
|
+
*
|
|
1274
|
+
* Both keys and values are the `name` portion of a wiki link — what
|
|
1275
|
+
* appears between `[[` and the optional `#anchor` / `|alias`. Anchors
|
|
1276
|
+
* and aliases on the original link are preserved automatically.
|
|
1277
|
+
*
|
|
1278
|
+
* Examples:
|
|
1279
|
+
* { "API-Tokens": "secrets/api-tokens" }
|
|
1280
|
+
* [[API-Tokens]] → [[secrets/api-tokens]]
|
|
1281
|
+
* [[API-Tokens|토큰]] → [[secrets/api-tokens|토큰]]
|
|
1282
|
+
* [[API-Tokens#A|토큰]] → [[secrets/api-tokens#A|토큰]]
|
|
1283
|
+
*
|
|
1284
|
+
* Use the exact name string the operator wrote — no normalization is
|
|
1285
|
+
* applied. If the same broken target appears with different spellings
|
|
1286
|
+
* (e.g. case differences), provide one entry per spelling.
|
|
1287
|
+
*/
|
|
1288
|
+
type RedirectionMap = ReadonlyMap<string, string>;
|
|
1289
|
+
/**
|
|
1290
|
+
* Options for {@link rewriteDirectory}.
|
|
1291
|
+
*/
|
|
1292
|
+
interface RewriteOptions {
|
|
1293
|
+
/**
|
|
1294
|
+
* The redirection map driving the rewrite. Links whose name is not
|
|
1295
|
+
* a key in this map are left untouched.
|
|
1296
|
+
*/
|
|
1297
|
+
redirections: RedirectionMap;
|
|
1298
|
+
/**
|
|
1299
|
+
* When true, do not write any files. The result still describes the
|
|
1300
|
+
* rewrites that would happen — useful for showing the operator what
|
|
1301
|
+
* a redirection map will do before it does it.
|
|
1302
|
+
*/
|
|
1303
|
+
dryRun?: boolean;
|
|
1304
|
+
}
|
|
1305
|
+
/**
|
|
1306
|
+
* Per-file detail of a rewrite operation.
|
|
1307
|
+
*/
|
|
1308
|
+
interface FileRewrite {
|
|
1309
|
+
readonly sourcePath: string;
|
|
1310
|
+
readonly rewrites: readonly {
|
|
1311
|
+
readonly from: string;
|
|
1312
|
+
readonly to: string;
|
|
1313
|
+
}[];
|
|
1314
|
+
}
|
|
1315
|
+
/**
|
|
1316
|
+
* Aggregate result of {@link rewriteDirectory}.
|
|
1317
|
+
*/
|
|
1318
|
+
interface RewriteResult {
|
|
1319
|
+
readonly filesScanned: number;
|
|
1320
|
+
/** Files whose body was changed (or would be changed under dry-run). */
|
|
1321
|
+
readonly filesChanged: number;
|
|
1322
|
+
/** Total number of link replacements (may exceed `filesChanged`). */
|
|
1323
|
+
readonly rewritesApplied: number;
|
|
1324
|
+
/** Links matching a redirection key but ultimately not replaced — currently always 0; reserved for future skip reasons. */
|
|
1325
|
+
readonly skipped: number;
|
|
1326
|
+
readonly details: readonly FileRewrite[];
|
|
1327
|
+
readonly dryRun: boolean;
|
|
1328
|
+
}
|
|
1329
|
+
/**
|
|
1330
|
+
* Walk every `.md` file under `rootDir`, replace wiki links whose name
|
|
1331
|
+
* is a key in `redirections`, and write the changed files back to disk
|
|
1332
|
+
* (or describe what would change when `dryRun: true`).
|
|
1333
|
+
*
|
|
1334
|
+
* Only the link `name` is replaced. Anchors (`#Section`) and aliases
|
|
1335
|
+
* (`|display`) carry over verbatim onto the replacement link. The
|
|
1336
|
+
* surrounding markdown body is untouched.
|
|
1337
|
+
*
|
|
1338
|
+
* Rewriting is deterministic and order-independent — within a file,
|
|
1339
|
+
* every occurrence of every mapped key is replaced exactly once per
|
|
1340
|
+
* occurrence, with no chaining (the replacement is not re-scanned for
|
|
1341
|
+
* further matches).
|
|
1342
|
+
*/
|
|
1343
|
+
declare function rewriteDirectory(rootDir: string, opts: RewriteOptions): Promise<RewriteResult>;
|
|
1344
|
+
/**
|
|
1345
|
+
* Pure transformation: take a markdown body, return the body with all
|
|
1346
|
+
* `[[…]]` links whose name appears in `redirections` rewritten. Exported
|
|
1347
|
+
* for testing and for callers that need to rewrite an in-memory string.
|
|
1348
|
+
*
|
|
1349
|
+
* The transformation does not touch markdown outside `[[…]]` patterns.
|
|
1350
|
+
*/
|
|
1351
|
+
declare function rewriteBody(body: string, redirections: RedirectionMap): {
|
|
1352
|
+
newBody: string;
|
|
1353
|
+
fileRewrites: {
|
|
1354
|
+
from: string;
|
|
1355
|
+
to: string;
|
|
1356
|
+
}[];
|
|
1357
|
+
};
|
|
1358
|
+
|
|
1359
|
+
//# sourceMappingURL=index.d.ts.map
|
|
1360
|
+
|
|
1361
|
+
type index_d$1_BrokenLink = BrokenLink;
|
|
1362
|
+
type index_d$1_BuildIndexOptions = BuildIndexOptions;
|
|
1363
|
+
type index_d$1_CheckDirectoryOptions = CheckDirectoryOptions;
|
|
1364
|
+
type index_d$1_FileIndex = FileIndex;
|
|
1365
|
+
type index_d$1_FileRewrite = FileRewrite;
|
|
1366
|
+
type index_d$1_LinkCheckResult = LinkCheckResult;
|
|
1367
|
+
type index_d$1_RedirectionMap = RedirectionMap;
|
|
1368
|
+
type index_d$1_ResolveOpts = ResolveOpts;
|
|
1369
|
+
type index_d$1_ResolveOutcome = ResolveOutcome;
|
|
1370
|
+
type index_d$1_RewriteOptions = RewriteOptions;
|
|
1371
|
+
type index_d$1_RewriteResult = RewriteResult;
|
|
1372
|
+
type index_d$1_WikiLink = WikiLink;
|
|
1373
|
+
declare const index_d$1_buildFileIndex: typeof buildFileIndex;
|
|
1374
|
+
declare const index_d$1_checkDirectory: typeof checkDirectory;
|
|
1375
|
+
declare const index_d$1_extractWikiLinks: typeof extractWikiLinks;
|
|
1376
|
+
declare const index_d$1_resolveLink: typeof resolveLink;
|
|
1377
|
+
declare const index_d$1_rewriteBody: typeof rewriteBody;
|
|
1378
|
+
declare const index_d$1_rewriteDirectory: typeof rewriteDirectory;
|
|
1379
|
+
declare const index_d$1_toRel: typeof toRel;
|
|
1380
|
+
declare const index_d$1_topBrokenTargets: typeof topBrokenTargets;
|
|
1381
|
+
declare namespace index_d$1 {
|
|
1382
|
+
export { type index_d$1_BrokenLink as BrokenLink, type index_d$1_BuildIndexOptions as BuildIndexOptions, type index_d$1_CheckDirectoryOptions as CheckDirectoryOptions, type index_d$1_FileIndex as FileIndex, type index_d$1_FileRewrite as FileRewrite, type index_d$1_LinkCheckResult as LinkCheckResult, type index_d$1_RedirectionMap as RedirectionMap, type index_d$1_ResolveOpts as ResolveOpts, type index_d$1_ResolveOutcome as ResolveOutcome, type index_d$1_RewriteOptions as RewriteOptions, type index_d$1_RewriteResult as RewriteResult, type index_d$1_WikiLink as WikiLink, index_d$1_buildFileIndex as buildFileIndex, index_d$1_checkDirectory as checkDirectory, index_d$1_extractWikiLinks as extractWikiLinks, index_d$1_resolveLink as resolveLink, index_d$1_rewriteBody as rewriteBody, index_d$1_rewriteDirectory as rewriteDirectory, index_d$1_toRel as toRel, index_d$1_topBrokenTargets as topBrokenTargets };
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
/**
|
|
1386
|
+
* Build a {@link CommandRegistry} with all ritual commands registered.
|
|
1387
|
+
*
|
|
1388
|
+
* Hosts that want a subset can register the individual exports instead.
|
|
1389
|
+
* This factory exists for the common case — "give me everything."
|
|
1390
|
+
*/
|
|
1391
|
+
declare function createRitualRegistry(): CommandRegistry;
|
|
1392
|
+
|
|
1393
|
+
/**
|
|
1394
|
+
* Output of {@link sessionStartCommand}'s handler. Pure data — the host
|
|
1395
|
+
* decides how to display it. Returning structured output rather than
|
|
1396
|
+
* printing keeps the command usable from non-CLI hosts (tests, web UIs).
|
|
1397
|
+
*/
|
|
1398
|
+
interface SessionStartReport {
|
|
1399
|
+
readonly time: string;
|
|
1400
|
+
readonly repoRoot: string;
|
|
1401
|
+
readonly dataDir: string;
|
|
1402
|
+
readonly counts: Readonly<Record<string, number>>;
|
|
1403
|
+
readonly missing: readonly string[];
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* `/session-start` — Emit a small report that anchors a new session.
|
|
1407
|
+
* No side effects: reads filesystem counts only.
|
|
1408
|
+
*
|
|
1409
|
+
* The host (e.g. Claude Code session loop) is expected to display the
|
|
1410
|
+
* report and decide what to do next. This command's job is to surface
|
|
1411
|
+
* the facts, not to take action.
|
|
1412
|
+
*/
|
|
1413
|
+
declare const sessionStartCommand: Command<SessionStartReport>;
|
|
1414
|
+
|
|
1415
|
+
interface ReindexResult {
|
|
1416
|
+
readonly dir: string;
|
|
1417
|
+
readonly status: "written" | "unchanged" | "missing";
|
|
1418
|
+
readonly entries: number;
|
|
1419
|
+
readonly bytes: number;
|
|
1420
|
+
}
|
|
1421
|
+
/**
|
|
1422
|
+
* `/reindex [dir]` — Regenerate `_INDEX.md` for one or all known data
|
|
1423
|
+
* directories. When called with no argument, processes all targets;
|
|
1424
|
+
* when called with a directory name, processes only that target.
|
|
1425
|
+
*
|
|
1426
|
+
* Returns a list of results so the host can summarize. Unchanged
|
|
1427
|
+
* indexes are reported as `unchanged` (no write performed); missing
|
|
1428
|
+
* directories are reported as `missing` (no write attempted).
|
|
1429
|
+
*/
|
|
1430
|
+
declare const reindexCommand: Command<readonly ReindexResult[]>;
|
|
1431
|
+
|
|
1432
|
+
interface NewDecisionResult {
|
|
1433
|
+
readonly path: string;
|
|
1434
|
+
readonly date: string;
|
|
1435
|
+
readonly slug: string;
|
|
1436
|
+
}
|
|
1437
|
+
/**
|
|
1438
|
+
* `/decision <slug> <title...>` — Create a new Decision Log entry from
|
|
1439
|
+
* the canonical template at `data/decision-log/<today>-<slug>.md`.
|
|
1440
|
+
*
|
|
1441
|
+
* `slug` is required and used in the filename. The remaining tokens form
|
|
1442
|
+
* the entry title (the H1 in the rendered body). The command refuses to
|
|
1443
|
+
* overwrite an existing file — it errors out so the caller can decide.
|
|
1444
|
+
*/
|
|
1445
|
+
declare const decisionCommand: Command<NewDecisionResult>;
|
|
1446
|
+
|
|
1447
|
+
interface TilAppendResult {
|
|
1448
|
+
readonly path: string;
|
|
1449
|
+
readonly date: string;
|
|
1450
|
+
readonly keyword: string;
|
|
1451
|
+
readonly sectionTitle: string;
|
|
1452
|
+
}
|
|
1453
|
+
/**
|
|
1454
|
+
* `/til <section-title>` — Append a `## <section-title>` section to today's
|
|
1455
|
+
* TIL entry. If no TIL exists for today, the command errors (entry creation
|
|
1456
|
+
* with frontmatter is left to the host so it can apply project-specific
|
|
1457
|
+
* conventions). The body of the new section is left empty for the caller
|
|
1458
|
+
* to fill in.
|
|
1459
|
+
*
|
|
1460
|
+
* This is a deliberately small command — the goal is to make "add a quick
|
|
1461
|
+
* note to today's TIL" a one-liner, not to replace a real editor.
|
|
1462
|
+
*/
|
|
1463
|
+
declare const tilCommand: Command<TilAppendResult>;
|
|
1464
|
+
|
|
1465
|
+
/**
|
|
1466
|
+
* `/vortex <sub>` — Root command for VortEX instance operations.
|
|
1467
|
+
*
|
|
1468
|
+
* Subcommands:
|
|
1469
|
+
* init — first-time setup wizard (creates user profile memory, first TIL, first topic hub)
|
|
1470
|
+
* status — (planned) instance state report
|
|
1471
|
+
* import — (planned) bring an existing folder into data/imported/
|
|
1472
|
+
* doctor — (planned) diagnose common setup issues
|
|
1473
|
+
* help — list available subcommands
|
|
1474
|
+
*
|
|
1475
|
+
* Phase 8 ships `init` and `help` as active; the rest are stubs that
|
|
1476
|
+
* advertise their planned name so users can discover them.
|
|
1477
|
+
*/
|
|
1478
|
+
declare const PLANNED_SUBS: readonly ["status", "import", "doctor"];
|
|
1479
|
+
type PlannedSub = (typeof PLANNED_SUBS)[number];
|
|
1480
|
+
interface VortexInitResult {
|
|
1481
|
+
readonly subcommand: "init";
|
|
1482
|
+
readonly status: "completed" | "needs-input" | "already-initialized";
|
|
1483
|
+
readonly created: readonly string[];
|
|
1484
|
+
readonly nextActions: readonly string[];
|
|
1485
|
+
readonly missingInputs?: readonly {
|
|
1486
|
+
name: string;
|
|
1487
|
+
prompt: string;
|
|
1488
|
+
}[];
|
|
1489
|
+
}
|
|
1490
|
+
interface VortexPlannedResult {
|
|
1491
|
+
readonly subcommand: PlannedSub | "unknown";
|
|
1492
|
+
readonly status: "not-implemented";
|
|
1493
|
+
readonly message: string;
|
|
1494
|
+
}
|
|
1495
|
+
interface VortexHelpResult {
|
|
1496
|
+
readonly subcommand: "help";
|
|
1497
|
+
readonly status: "ok";
|
|
1498
|
+
readonly subcommands: readonly {
|
|
1499
|
+
readonly name: string;
|
|
1500
|
+
readonly description: string;
|
|
1501
|
+
readonly state: "active" | "planned";
|
|
1502
|
+
}[];
|
|
1503
|
+
}
|
|
1504
|
+
type VortexResult = VortexInitResult | VortexPlannedResult | VortexHelpResult;
|
|
1505
|
+
declare const vortexCommand: Command<VortexResult>;
|
|
1506
|
+
|
|
1507
|
+
//# sourceMappingURL=index.d.ts.map
|
|
1508
|
+
|
|
1509
|
+
type index_d_NewDecisionResult = NewDecisionResult;
|
|
1510
|
+
type index_d_ReindexResult = ReindexResult;
|
|
1511
|
+
type index_d_SessionStartReport = SessionStartReport;
|
|
1512
|
+
type index_d_TilAppendResult = TilAppendResult;
|
|
1513
|
+
type index_d_VortexHelpResult = VortexHelpResult;
|
|
1514
|
+
type index_d_VortexInitResult = VortexInitResult;
|
|
1515
|
+
type index_d_VortexPlannedResult = VortexPlannedResult;
|
|
1516
|
+
type index_d_VortexResult = VortexResult;
|
|
1517
|
+
declare const index_d_createRitualRegistry: typeof createRitualRegistry;
|
|
1518
|
+
declare const index_d_decisionCommand: typeof decisionCommand;
|
|
1519
|
+
declare const index_d_reindexCommand: typeof reindexCommand;
|
|
1520
|
+
declare const index_d_sessionStartCommand: typeof sessionStartCommand;
|
|
1521
|
+
declare const index_d_tilCommand: typeof tilCommand;
|
|
1522
|
+
declare const index_d_vortexCommand: typeof vortexCommand;
|
|
1523
|
+
declare namespace index_d {
|
|
1524
|
+
export { type index_d_NewDecisionResult as NewDecisionResult, type index_d_ReindexResult as ReindexResult, type index_d_SessionStartReport as SessionStartReport, type index_d_TilAppendResult as TilAppendResult, type index_d_VortexHelpResult as VortexHelpResult, type index_d_VortexInitResult as VortexInitResult, type index_d_VortexPlannedResult as VortexPlannedResult, type index_d_VortexResult as VortexResult, index_d_createRitualRegistry as createRitualRegistry, index_d_decisionCommand as decisionCommand, index_d_reindexCommand as reindexCommand, index_d_sessionStartCommand as sessionStartCommand, index_d_tilCommand as tilCommand, index_d_vortexCommand as vortexCommand };
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
export { index_d$8 as aiCodingPitfalls, index_d$c as core, index_d$9 as dataLint, index_d$4 as decisionLog, index_d$3 as indexGenerator, index_d$1 as linkRewriter, index_d$a as memorySystem, index_d$6 as reportGenerator, index_d$2 as runbooks, index_d as sessionRituals, index_d$b as slashCommands, index_d$5 as til, index_d$7 as toolRules };
|