@vortex-os/base 0.0.1 → 0.2.3
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/LICENSE +1 -1
- package/README.md +113 -63
- package/dist/index.d.ts +2969 -23
- package/dist/index.js +6120 -20
- package/dist/index.js.map +1 -1
- package/package.json +63 -54
- package/dist/index.d.ts.map +0 -1
- package/src/index.ts +0 -33
package/dist/index.d.ts
CHANGED
|
@@ -1,24 +1,2970 @@
|
|
|
1
|
+
import { vector, recall, sessionArchive } from '@vortex-os/memory-extended';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
4
|
+
* Three-tier privacy classification used across VortEX.
|
|
5
|
+
*
|
|
6
|
+
* - `public` — safe to share with anyone, including in published repositories.
|
|
7
|
+
* - `internal` — visible to the operator and their organization; not for public release.
|
|
8
|
+
* - `personal` — personal data; never shared, never published.
|
|
9
|
+
*/
|
|
10
|
+
declare const Privacy: {
|
|
11
|
+
readonly Public: "public";
|
|
12
|
+
readonly Internal: "internal";
|
|
13
|
+
readonly Personal: "personal";
|
|
14
|
+
};
|
|
15
|
+
type Privacy = (typeof Privacy)[keyof typeof Privacy];
|
|
16
|
+
/**
|
|
17
|
+
* Parsed markdown document with separated YAML frontmatter and body.
|
|
18
|
+
*/
|
|
19
|
+
interface FrontmatterDoc<T = Record<string, unknown>> {
|
|
20
|
+
frontmatter: T & {
|
|
21
|
+
privacy?: Privacy;
|
|
22
|
+
};
|
|
23
|
+
body: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Resolved paths for a VortEX repository root.
|
|
27
|
+
*
|
|
28
|
+
* Every module receives a `ModuleContext` from the host (CLI, plugin runtime,
|
|
29
|
+
* or test harness) and resolves its own paths against it. Modules must not
|
|
30
|
+
* derive paths by string manipulation against an assumed layout.
|
|
31
|
+
*/
|
|
32
|
+
interface ModuleContext {
|
|
33
|
+
repoRoot: string;
|
|
34
|
+
agentDir: string;
|
|
35
|
+
dataDir: string;
|
|
36
|
+
modulesDir: string;
|
|
37
|
+
pluginsDir: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Parse a markdown source into its YAML frontmatter and body. If no frontmatter
|
|
42
|
+
* fence is present, returns an empty frontmatter object and the source unchanged.
|
|
43
|
+
*
|
|
44
|
+
* A leading UTF-8 BOM is stripped before matching. Windows-authored files
|
|
45
|
+
* frequently begin with ``, which would otherwise prevent the fence
|
|
46
|
+
* regex from anchoring to `---` at byte 0.
|
|
47
|
+
*/
|
|
48
|
+
declare function parseFrontmatter<T = Record<string, unknown>>(source: string): FrontmatterDoc<T>;
|
|
49
|
+
/**
|
|
50
|
+
* Serialize a `FrontmatterDoc` back into markdown text. If the frontmatter is
|
|
51
|
+
* empty, the body is returned unchanged (no empty fence is emitted).
|
|
52
|
+
*/
|
|
53
|
+
declare function serializeFrontmatter<T = Record<string, unknown>>(doc: FrontmatterDoc<T>): string;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Returns true if a document with `docPrivacy` is visible to a viewer authorized
|
|
57
|
+
* at `viewerPrivacy`. Viewers see content at or below their own level.
|
|
58
|
+
*
|
|
59
|
+
* - `public` viewer sees → public only
|
|
60
|
+
* - `internal` viewer sees → public + internal
|
|
61
|
+
* - `personal` viewer sees → all three
|
|
62
|
+
*/
|
|
63
|
+
declare function isVisibleAt(docPrivacy: Privacy, viewerPrivacy: Privacy): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Returns the more-restrictive of two privacy levels.
|
|
66
|
+
* Useful when combining content from multiple sources for sharing.
|
|
67
|
+
*/
|
|
68
|
+
declare function maxPrivacy(a: Privacy, b: Privacy): Privacy;
|
|
69
|
+
/**
|
|
70
|
+
* Coerce an unknown value (e.g. user input or untyped frontmatter) into a
|
|
71
|
+
* valid `Privacy`. Falls back to `internal` by default — the safest default
|
|
72
|
+
* for unclassified content.
|
|
73
|
+
*/
|
|
74
|
+
declare function normalizePrivacy(value: unknown, fallback?: Privacy): Privacy;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Build a `ModuleContext` for the given VortEX repository root. The root is
|
|
78
|
+
* resolved to an absolute path; standard subdirectories are derived by
|
|
79
|
+
* convention and are not guaranteed to exist on disk.
|
|
80
|
+
*/
|
|
81
|
+
declare function makeContext(repoRoot: string): ModuleContext;
|
|
82
|
+
/**
|
|
83
|
+
* Resolve the directory of a named module within the repository.
|
|
84
|
+
*/
|
|
85
|
+
declare function moduleDir(ctx: ModuleContext, moduleName: string): string;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Instance configuration for VortEX, read from `<agentDir>/vortex.json`.
|
|
89
|
+
*
|
|
90
|
+
* The config exists to give the user control over the **auto-maintained**
|
|
91
|
+
* operational behaviors (see `AGENT.md` → "Default behaviors") without
|
|
92
|
+
* touching code: toggle any auto-record off, and declare how this machine's
|
|
93
|
+
* environment is detected. A fresh instance has no config file — everything
|
|
94
|
+
* is on, no environment — so the framework works out of the box and the file
|
|
95
|
+
* is purely opt-in tuning.
|
|
96
|
+
*/
|
|
97
|
+
/** Which auto-maintained operational records are enabled. Default: all on. */
|
|
98
|
+
interface AutoRecordConfig {
|
|
99
|
+
readonly sessionStart: boolean;
|
|
100
|
+
readonly worklog: boolean;
|
|
101
|
+
readonly decision: boolean;
|
|
102
|
+
readonly ambientRecall: boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Catch-up: at session start, ingest conversation transcripts that have not
|
|
105
|
+
* been archived yet (the host's own machine only). Text is stored
|
|
106
|
+
* immediately; vectorization is deferred to recall/rebuild so start stays
|
|
107
|
+
* fast. Off → no automatic ingest; the archive only grows when explicitly
|
|
108
|
+
* rebuilt.
|
|
109
|
+
*/
|
|
110
|
+
readonly archive: boolean;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* One environment label plus the signal that selects it. Rules are evaluated
|
|
114
|
+
* in order; the first match wins. Generalizes the operator's home/work
|
|
115
|
+
* `Test-Path` pattern into a portable, declarative form.
|
|
116
|
+
*/
|
|
117
|
+
interface EnvironmentRule {
|
|
118
|
+
readonly label: string;
|
|
119
|
+
/** Match when this absolute path exists on the machine. */
|
|
120
|
+
readonly pathExists?: string;
|
|
121
|
+
/** Match when the OS hostname equals this (case-insensitive). */
|
|
122
|
+
readonly hostname?: string;
|
|
123
|
+
/**
|
|
124
|
+
* Match when an environment variable is set. A bare string matches on
|
|
125
|
+
* presence; the object form additionally requires a specific value.
|
|
126
|
+
*/
|
|
127
|
+
readonly envVar?: string | {
|
|
128
|
+
readonly name: string;
|
|
129
|
+
readonly equals?: string;
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
interface VortexConfig {
|
|
133
|
+
readonly autoRecord: AutoRecordConfig;
|
|
134
|
+
readonly environments: readonly EnvironmentRule[];
|
|
135
|
+
}
|
|
136
|
+
/** Path of the instance config file: `<agentDir>/vortex.json`. */
|
|
137
|
+
declare function vortexConfigPath(ctx: ModuleContext): string;
|
|
138
|
+
/**
|
|
139
|
+
* Load the instance config, merged over defaults. A missing, unreadable, or
|
|
140
|
+
* invalid file yields defaults (everything on, no environments) rather than
|
|
141
|
+
* throwing — config is opt-in tuning, never a prerequisite.
|
|
142
|
+
*/
|
|
143
|
+
declare function loadVortexConfig(ctx: ModuleContext): VortexConfig;
|
|
144
|
+
/**
|
|
145
|
+
* Resolve the active environment label from the config rules (first match
|
|
146
|
+
* wins), or null when none match. Pure — the caller injects the signals
|
|
147
|
+
* (hostname, env vars, a path-existence probe) so this stays testable and
|
|
148
|
+
* free of direct OS access.
|
|
149
|
+
*/
|
|
150
|
+
declare function resolveEnvironment(config: VortexConfig, signals: {
|
|
151
|
+
readonly hostname?: string;
|
|
152
|
+
readonly env?: Record<string, string | undefined>;
|
|
153
|
+
readonly pathExists?: (p: string) => boolean;
|
|
154
|
+
}): string | null;
|
|
155
|
+
|
|
156
|
+
//# sourceMappingURL=index.d.ts.map
|
|
157
|
+
|
|
158
|
+
type index_d$d_AutoRecordConfig = AutoRecordConfig;
|
|
159
|
+
type index_d$d_EnvironmentRule = EnvironmentRule;
|
|
160
|
+
type index_d$d_FrontmatterDoc<T = Record<string, unknown>> = FrontmatterDoc<T>;
|
|
161
|
+
type index_d$d_ModuleContext = ModuleContext;
|
|
162
|
+
type index_d$d_Privacy = Privacy;
|
|
163
|
+
type index_d$d_VortexConfig = VortexConfig;
|
|
164
|
+
declare const index_d$d_isVisibleAt: typeof isVisibleAt;
|
|
165
|
+
declare const index_d$d_loadVortexConfig: typeof loadVortexConfig;
|
|
166
|
+
declare const index_d$d_makeContext: typeof makeContext;
|
|
167
|
+
declare const index_d$d_maxPrivacy: typeof maxPrivacy;
|
|
168
|
+
declare const index_d$d_moduleDir: typeof moduleDir;
|
|
169
|
+
declare const index_d$d_normalizePrivacy: typeof normalizePrivacy;
|
|
170
|
+
declare const index_d$d_parseFrontmatter: typeof parseFrontmatter;
|
|
171
|
+
declare const index_d$d_resolveEnvironment: typeof resolveEnvironment;
|
|
172
|
+
declare const index_d$d_serializeFrontmatter: typeof serializeFrontmatter;
|
|
173
|
+
declare const index_d$d_vortexConfigPath: typeof vortexConfigPath;
|
|
174
|
+
declare namespace index_d$d {
|
|
175
|
+
export { type index_d$d_AutoRecordConfig as AutoRecordConfig, type index_d$d_EnvironmentRule as EnvironmentRule, type index_d$d_FrontmatterDoc as FrontmatterDoc, type index_d$d_ModuleContext as ModuleContext, type index_d$d_Privacy as Privacy, type index_d$d_VortexConfig as VortexConfig, index_d$d_isVisibleAt as isVisibleAt, index_d$d_loadVortexConfig as loadVortexConfig, index_d$d_makeContext as makeContext, index_d$d_maxPrivacy as maxPrivacy, index_d$d_moduleDir as moduleDir, index_d$d_normalizePrivacy as normalizePrivacy, index_d$d_parseFrontmatter as parseFrontmatter, index_d$d_resolveEnvironment as resolveEnvironment, index_d$d_serializeFrontmatter as serializeFrontmatter, index_d$d_vortexConfigPath as vortexConfigPath };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Declaration of a single argument expected by a command.
|
|
180
|
+
*
|
|
181
|
+
* Argument parsing in Phase 2 is positional: arguments are read from the
|
|
182
|
+
* tokens following the command name, in declaration order. Named flags
|
|
183
|
+
* (e.g. `--foo bar`) are not handled at this layer — hosts that need them
|
|
184
|
+
* can pre-process input before calling `runSlash`.
|
|
185
|
+
*/
|
|
186
|
+
interface CommandArg {
|
|
187
|
+
readonly name: string;
|
|
188
|
+
readonly description: string;
|
|
189
|
+
readonly required?: boolean;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Value passed to a command's handler.
|
|
193
|
+
*
|
|
194
|
+
* - `raw` — the full input string with any leading `/` removed.
|
|
195
|
+
* - `args` — positional arguments matched against the command's declared
|
|
196
|
+
* `args` schema, keyed by argument name.
|
|
197
|
+
* - `rest` — the unparsed trailing portion of the input (everything after
|
|
198
|
+
* the command name), provided as-is for commands that prefer to handle
|
|
199
|
+
* their own parsing.
|
|
200
|
+
* - `context` — resolved repository paths from `@vortex-os/core.makeContext`.
|
|
201
|
+
*/
|
|
202
|
+
interface CommandInput {
|
|
203
|
+
readonly raw: string;
|
|
204
|
+
readonly args: Readonly<Record<string, string>>;
|
|
205
|
+
readonly rest: string;
|
|
206
|
+
readonly context: ModuleContext;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* A registrable, callable command.
|
|
210
|
+
*/
|
|
211
|
+
interface Command<Result = unknown> {
|
|
212
|
+
readonly name: string;
|
|
213
|
+
readonly description: string;
|
|
214
|
+
readonly args?: readonly CommandArg[];
|
|
215
|
+
readonly handler: (input: CommandInput) => Result | Promise<Result>;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Holds registered commands and looks them up by name.
|
|
220
|
+
*
|
|
221
|
+
* Names are matched exactly. Registering two commands with the same name
|
|
222
|
+
* is an error — the second call throws. Callers that want to override an
|
|
223
|
+
* existing command must `unregister` first.
|
|
224
|
+
*/
|
|
225
|
+
declare class CommandRegistry {
|
|
226
|
+
private readonly commands;
|
|
227
|
+
register(command: Command): void;
|
|
228
|
+
unregister(name: string): boolean;
|
|
229
|
+
has(name: string): boolean;
|
|
230
|
+
get(name: string): Command | undefined;
|
|
231
|
+
list(): readonly Command[];
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
interface RunOptions {
|
|
235
|
+
readonly registry: CommandRegistry;
|
|
236
|
+
readonly context: ModuleContext;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Thrown by `runSlash` when the requested command name does not exist
|
|
240
|
+
* in the registry. The unknown name is exposed for caller diagnostics.
|
|
241
|
+
*/
|
|
242
|
+
declare class CommandNotFoundError extends Error {
|
|
243
|
+
readonly commandName: string;
|
|
244
|
+
constructor(commandName: string);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Parse an input string and dispatch the matching command.
|
|
248
|
+
*
|
|
249
|
+
* Accepted forms (leading slash optional):
|
|
250
|
+
* "name"
|
|
251
|
+
* "/name"
|
|
252
|
+
* "name arg1 arg2 ..."
|
|
253
|
+
*
|
|
254
|
+
* Returns whatever the command's handler returns (awaited if it is async).
|
|
255
|
+
*/
|
|
256
|
+
declare function runSlash(input: string, { registry, context }: RunOptions): Promise<unknown>;
|
|
257
|
+
|
|
258
|
+
//# sourceMappingURL=index.d.ts.map
|
|
259
|
+
|
|
260
|
+
type index_d$c_Command<Result = unknown> = Command<Result>;
|
|
261
|
+
type index_d$c_CommandArg = CommandArg;
|
|
262
|
+
type index_d$c_CommandInput = CommandInput;
|
|
263
|
+
type index_d$c_CommandNotFoundError = CommandNotFoundError;
|
|
264
|
+
declare const index_d$c_CommandNotFoundError: typeof CommandNotFoundError;
|
|
265
|
+
type index_d$c_CommandRegistry = CommandRegistry;
|
|
266
|
+
declare const index_d$c_CommandRegistry: typeof CommandRegistry;
|
|
267
|
+
type index_d$c_RunOptions = RunOptions;
|
|
268
|
+
declare const index_d$c_runSlash: typeof runSlash;
|
|
269
|
+
declare namespace index_d$c {
|
|
270
|
+
export { type index_d$c_Command as Command, type index_d$c_CommandArg as CommandArg, type index_d$c_CommandInput as CommandInput, index_d$c_CommandNotFoundError as CommandNotFoundError, index_d$c_CommandRegistry as CommandRegistry, type index_d$c_RunOptions as RunOptions, index_d$c_runSlash as runSlash };
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Canonical memory categories.
|
|
275
|
+
*
|
|
276
|
+
* - `user` — facts about the operator (role, preferences, working style).
|
|
277
|
+
* - `feedback` — corrections and validated approaches from the operator.
|
|
278
|
+
* - `project` — ongoing work context (goals, deadlines, stakeholders).
|
|
279
|
+
* - `reference` — pointers to external systems (dashboards, repos, channels).
|
|
280
|
+
*
|
|
281
|
+
* Hosts may extend the set, but stability of these four is preserved.
|
|
282
|
+
*/
|
|
283
|
+
declare const MemoryType: {
|
|
284
|
+
readonly User: "user";
|
|
285
|
+
readonly Feedback: "feedback";
|
|
286
|
+
readonly Project: "project";
|
|
287
|
+
readonly Reference: "reference";
|
|
288
|
+
};
|
|
289
|
+
type MemoryType = (typeof MemoryType)[keyof typeof MemoryType];
|
|
290
|
+
/**
|
|
291
|
+
* Frontmatter required on every memory file.
|
|
292
|
+
*
|
|
293
|
+
* `name` should match the file id (filename without `.md`). `description`
|
|
294
|
+
* is a single-line summary used in the generated index. `type` places the
|
|
295
|
+
* memory in one of the canonical categories. Additional keys (e.g.
|
|
296
|
+
* `originSessionId`, `created`, custom tags) are tolerated and preserved
|
|
297
|
+
* on round-trip but are not required.
|
|
298
|
+
*/
|
|
299
|
+
interface MemoryFrontmatter {
|
|
300
|
+
name: string;
|
|
301
|
+
description: string;
|
|
302
|
+
type: MemoryType;
|
|
303
|
+
[key: string]: unknown;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* A parsed memory document, ready to be written back or rendered.
|
|
307
|
+
*
|
|
308
|
+
* `id` is the filename stem (no `.md`); it is the address by which the
|
|
309
|
+
* store retrieves and overwrites the memory.
|
|
310
|
+
*/
|
|
311
|
+
interface Memory {
|
|
312
|
+
id: string;
|
|
313
|
+
frontmatter: MemoryFrontmatter;
|
|
314
|
+
body: string;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* A directory-backed memory store.
|
|
319
|
+
*
|
|
320
|
+
* Each memory lives in a single `.md` file. The `MEMORY.md` (generated index)
|
|
321
|
+
* and `_INDEX.md` (Obsidian-friendly index) files are excluded — they are
|
|
322
|
+
* derived views, not memories themselves.
|
|
323
|
+
*/
|
|
324
|
+
declare class MemoryStore {
|
|
325
|
+
readonly dir: string;
|
|
326
|
+
constructor(dir: string);
|
|
327
|
+
/** Ensure the backing directory exists. Safe to call repeatedly. */
|
|
328
|
+
ensure(): Promise<void>;
|
|
329
|
+
/** List memory ids (filename stems), sorted lexicographically. */
|
|
330
|
+
list(): Promise<readonly string[]>;
|
|
331
|
+
/** Read a memory by id. Throws if the file does not exist. */
|
|
332
|
+
read(id: string): Promise<Memory>;
|
|
333
|
+
/** Write (or overwrite) a memory. Ensures the directory exists first. */
|
|
334
|
+
write(memory: Memory): Promise<void>;
|
|
335
|
+
/** Delete a memory. Returns false if it did not exist. */
|
|
336
|
+
delete(id: string): Promise<boolean>;
|
|
337
|
+
/** Test whether a memory exists by id. */
|
|
338
|
+
has(id: string): Promise<boolean>;
|
|
339
|
+
/** Absolute path of a memory file (file may not exist). */
|
|
340
|
+
pathFor(id: string): string;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
interface WriteMemoryIndexOptions {
|
|
344
|
+
/** Top-level heading. Defaults to "Memory Index". */
|
|
345
|
+
title?: string;
|
|
346
|
+
/** Optional text placed above the heading (e.g. an HTML comment). */
|
|
347
|
+
preamble?: string;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Render a `MEMORY.md` index from the entries currently in `store` and
|
|
351
|
+
* write it to `<store.dir>/MEMORY.md`. Existing `MEMORY.md` is overwritten.
|
|
352
|
+
*
|
|
353
|
+
* The index is a flat bullet list: one line per memory, linking to the
|
|
354
|
+
* memory file and including the memory's `description`.
|
|
355
|
+
*/
|
|
356
|
+
declare function writeMemoryIndex(store: MemoryStore, options?: WriteMemoryIndexOptions): Promise<void>;
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Difference between two memory stores. All three lists may be empty,
|
|
360
|
+
* which means the stores are in sync.
|
|
361
|
+
*/
|
|
362
|
+
interface SyncDiff {
|
|
363
|
+
/** Ids present in `a` but not in `b`. */
|
|
364
|
+
onlyInA: readonly string[];
|
|
365
|
+
/** Ids present in `b` but not in `a`. */
|
|
366
|
+
onlyInB: readonly string[];
|
|
367
|
+
/** Ids present in both but whose raw file contents differ. */
|
|
368
|
+
changed: readonly string[];
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Compute the diff between two memory stores. Neither store is modified.
|
|
372
|
+
*
|
|
373
|
+
* `changed` is determined by exact byte comparison of the underlying
|
|
374
|
+
* `.md` files. Frontmatter ordering or whitespace differences therefore
|
|
375
|
+
* count as a change — callers that want semantic equality should
|
|
376
|
+
* re-serialize through `parseFrontmatter` / `serializeFrontmatter` before
|
|
377
|
+
* comparing.
|
|
378
|
+
*/
|
|
379
|
+
declare function diffStores(a: MemoryStore, b: MemoryStore): Promise<SyncDiff>;
|
|
380
|
+
|
|
381
|
+
//# sourceMappingURL=index.d.ts.map
|
|
382
|
+
|
|
383
|
+
type index_d$b_Memory = Memory;
|
|
384
|
+
type index_d$b_MemoryFrontmatter = MemoryFrontmatter;
|
|
385
|
+
type index_d$b_MemoryStore = MemoryStore;
|
|
386
|
+
declare const index_d$b_MemoryStore: typeof MemoryStore;
|
|
387
|
+
type index_d$b_MemoryType = MemoryType;
|
|
388
|
+
type index_d$b_SyncDiff = SyncDiff;
|
|
389
|
+
type index_d$b_WriteMemoryIndexOptions = WriteMemoryIndexOptions;
|
|
390
|
+
declare const index_d$b_diffStores: typeof diffStores;
|
|
391
|
+
declare const index_d$b_writeMemoryIndex: typeof writeMemoryIndex;
|
|
392
|
+
declare namespace index_d$b {
|
|
393
|
+
export { type index_d$b_Memory as Memory, type index_d$b_MemoryFrontmatter as MemoryFrontmatter, index_d$b_MemoryStore as MemoryStore, type index_d$b_MemoryType as MemoryType, type index_d$b_SyncDiff as SyncDiff, type index_d$b_WriteMemoryIndexOptions as WriteMemoryIndexOptions, index_d$b_diffStores as diffStores, index_d$b_writeMemoryIndex as writeMemoryIndex };
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
type Severity = "error" | "warning" | "info";
|
|
397
|
+
/**
|
|
398
|
+
* A single problem found by a rule.
|
|
399
|
+
*/
|
|
400
|
+
interface LintFinding {
|
|
401
|
+
readonly rule: string;
|
|
402
|
+
readonly severity: Severity;
|
|
403
|
+
readonly file: string;
|
|
404
|
+
readonly line?: number;
|
|
405
|
+
readonly message: string;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Input passed to a rule's `check` function.
|
|
409
|
+
*/
|
|
410
|
+
interface LintInput {
|
|
411
|
+
readonly file: string;
|
|
412
|
+
readonly content: string;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* A registrable lint rule.
|
|
416
|
+
*
|
|
417
|
+
* Rules are pure: same input produces the same findings, no side effects.
|
|
418
|
+
* `check` may be async — useful for rules that need to consult other
|
|
419
|
+
* files (e.g. resolving wiki links).
|
|
420
|
+
*/
|
|
421
|
+
interface LintRule {
|
|
422
|
+
readonly id: string;
|
|
423
|
+
readonly description: string;
|
|
424
|
+
readonly check: (input: LintInput) => readonly LintFinding[] | Promise<readonly LintFinding[]>;
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Aggregated result of a lint run.
|
|
428
|
+
*/
|
|
429
|
+
interface LintReport {
|
|
430
|
+
readonly findings: readonly LintFinding[];
|
|
431
|
+
readonly filesScanned: number;
|
|
432
|
+
readonly rulesRun: number;
|
|
433
|
+
readonly durationMs: number;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
interface LintOptions {
|
|
437
|
+
/** Directory to scan recursively. */
|
|
438
|
+
readonly dir: string;
|
|
439
|
+
/** Rules to apply to every file. */
|
|
440
|
+
readonly rules: readonly LintRule[];
|
|
441
|
+
/** File extensions to include. Defaults to `[".md"]`. */
|
|
442
|
+
readonly extensions?: readonly string[];
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Recursively scan `dir` for files with the configured extensions and run
|
|
446
|
+
* every rule against each file. Findings from all rules are aggregated into
|
|
447
|
+
* a single `LintReport`. Order of findings within the report is not
|
|
448
|
+
* guaranteed beyond "file by file, rule by rule".
|
|
449
|
+
*/
|
|
450
|
+
declare function lintDirectory(options: LintOptions): Promise<LintReport>;
|
|
451
|
+
|
|
452
|
+
interface RequireFrontmatterOptions {
|
|
453
|
+
/** Frontmatter keys that must be present and non-empty. */
|
|
454
|
+
readonly required: readonly string[];
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Rule that ensures the listed frontmatter keys are present and non-empty.
|
|
458
|
+
* Empty string, null, and undefined values all fail the check; `0`, `false`,
|
|
459
|
+
* and structured values (arrays, objects) pass as long as they exist.
|
|
460
|
+
*/
|
|
461
|
+
declare function requireFrontmatter(options: RequireFrontmatterOptions): LintRule;
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Rule that ensures, if a `privacy` frontmatter field is present, its value
|
|
465
|
+
* is one of the canonical three: `public`, `internal`, `personal`.
|
|
466
|
+
* Documents without any `privacy` field pass.
|
|
467
|
+
*/
|
|
468
|
+
declare function privacyValid(): LintRule;
|
|
469
|
+
|
|
470
|
+
interface WikiLinkResolvesOptions {
|
|
471
|
+
/** Directory under which valid link targets live. Searched recursively. */
|
|
472
|
+
readonly searchRoot: string;
|
|
473
|
+
/** Target file extensions. Defaults to `[".md"]`. */
|
|
474
|
+
readonly extensions?: readonly string[];
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Rule that checks wiki-style links `[[target]]` resolve to an existing
|
|
478
|
+
* file under `searchRoot` (by basename match, recursive). Aliases
|
|
479
|
+
* (`[[target|alias]]`) and anchors (`[[target#section]]`) are stripped
|
|
480
|
+
* before lookup.
|
|
481
|
+
*
|
|
482
|
+
* The target index is built lazily on the first invocation and cached for
|
|
483
|
+
* the lifetime of the rule instance.
|
|
484
|
+
*/
|
|
485
|
+
declare function wikiLinkResolves(options: WikiLinkResolvesOptions): LintRule;
|
|
486
|
+
|
|
487
|
+
//# sourceMappingURL=index.d.ts.map
|
|
488
|
+
|
|
489
|
+
type index_d$a_LintFinding = LintFinding;
|
|
490
|
+
type index_d$a_LintInput = LintInput;
|
|
491
|
+
type index_d$a_LintOptions = LintOptions;
|
|
492
|
+
type index_d$a_LintReport = LintReport;
|
|
493
|
+
type index_d$a_LintRule = LintRule;
|
|
494
|
+
type index_d$a_RequireFrontmatterOptions = RequireFrontmatterOptions;
|
|
495
|
+
type index_d$a_Severity = Severity;
|
|
496
|
+
type index_d$a_WikiLinkResolvesOptions = WikiLinkResolvesOptions;
|
|
497
|
+
declare const index_d$a_lintDirectory: typeof lintDirectory;
|
|
498
|
+
declare const index_d$a_privacyValid: typeof privacyValid;
|
|
499
|
+
declare const index_d$a_requireFrontmatter: typeof requireFrontmatter;
|
|
500
|
+
declare const index_d$a_wikiLinkResolves: typeof wikiLinkResolves;
|
|
501
|
+
declare namespace index_d$a {
|
|
502
|
+
export { type index_d$a_LintFinding as LintFinding, type index_d$a_LintInput as LintInput, type index_d$a_LintOptions as LintOptions, type index_d$a_LintReport as LintReport, type index_d$a_LintRule as LintRule, type index_d$a_RequireFrontmatterOptions as RequireFrontmatterOptions, type index_d$a_Severity as Severity, type index_d$a_WikiLinkResolvesOptions as WikiLinkResolvesOptions, index_d$a_lintDirectory as lintDirectory, index_d$a_privacyValid as privacyValid, index_d$a_requireFrontmatter as requireFrontmatter, index_d$a_wikiLinkResolves as wikiLinkResolves };
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
type PitfallSeverity = "info" | "warning" | "error";
|
|
506
|
+
/**
|
|
507
|
+
* A single AI coding pitfall.
|
|
508
|
+
*
|
|
509
|
+
* Pitfalls describe failure modes that recur across AI coding work, along
|
|
510
|
+
* with how to recognize them and what to do instead. They are catalog
|
|
511
|
+
* entries, not active detectors.
|
|
512
|
+
*/
|
|
513
|
+
interface Pitfall {
|
|
514
|
+
readonly id: string;
|
|
515
|
+
readonly title: string;
|
|
516
|
+
readonly category: string;
|
|
517
|
+
readonly severity: PitfallSeverity;
|
|
518
|
+
readonly signal: string;
|
|
519
|
+
readonly cause: string;
|
|
520
|
+
readonly mitigation: string;
|
|
521
|
+
/** Free-form trailing markdown (examples, notes); empty string if none. */
|
|
522
|
+
readonly body: string;
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Frontmatter shape expected on a pitfall `.md` file.
|
|
526
|
+
*
|
|
527
|
+
* `id` is optional in the source — if omitted, the filename stem is used.
|
|
528
|
+
*/
|
|
529
|
+
interface PitfallFrontmatter {
|
|
530
|
+
id?: string;
|
|
531
|
+
title: string;
|
|
532
|
+
category: string;
|
|
533
|
+
severity: PitfallSeverity;
|
|
534
|
+
signal: string;
|
|
535
|
+
cause: string;
|
|
536
|
+
mitigation: string;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Directory-backed pitfall catalog. One `.md` file per pitfall.
|
|
541
|
+
*
|
|
542
|
+
* The catalog reads all `.md` files in `dir` on each query (no caching).
|
|
543
|
+
* Callers that need cached behavior should wrap or call `list()` once and
|
|
544
|
+
* reuse the result.
|
|
545
|
+
*/
|
|
546
|
+
declare class PitfallCatalog {
|
|
547
|
+
readonly dir: string;
|
|
548
|
+
constructor(dir: string);
|
|
549
|
+
/** Load every pitfall in the directory, sorted by id. */
|
|
550
|
+
list(): Promise<readonly Pitfall[]>;
|
|
551
|
+
/** Load a single pitfall by id. Returns `undefined` if not found. */
|
|
552
|
+
get(id: string): Promise<Pitfall | undefined>;
|
|
553
|
+
/** Return only pitfalls matching the given category. */
|
|
554
|
+
filterByCategory(category: string): Promise<readonly Pitfall[]>;
|
|
555
|
+
private entries;
|
|
556
|
+
private loadFile;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
//# sourceMappingURL=index.d.ts.map
|
|
560
|
+
|
|
561
|
+
type index_d$9_Pitfall = Pitfall;
|
|
562
|
+
type index_d$9_PitfallCatalog = PitfallCatalog;
|
|
563
|
+
declare const index_d$9_PitfallCatalog: typeof PitfallCatalog;
|
|
564
|
+
type index_d$9_PitfallFrontmatter = PitfallFrontmatter;
|
|
565
|
+
type index_d$9_PitfallSeverity = PitfallSeverity;
|
|
566
|
+
declare namespace index_d$9 {
|
|
567
|
+
export { type index_d$9_Pitfall as Pitfall, index_d$9_PitfallCatalog as PitfallCatalog, type index_d$9_PitfallFrontmatter as PitfallFrontmatter, type index_d$9_PitfallSeverity as PitfallSeverity };
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
type ToolRuleSeverity = "advisory" | "strict" | "absolute";
|
|
571
|
+
/**
|
|
572
|
+
* A single tool-usage rule.
|
|
573
|
+
*
|
|
574
|
+
* Tool rules express constraints the operator wants agents to obey when
|
|
575
|
+
* invoking specific tools. They are catalog entries, not active enforcers.
|
|
576
|
+
*/
|
|
577
|
+
interface ToolRule {
|
|
578
|
+
readonly id: string;
|
|
579
|
+
readonly title: string;
|
|
580
|
+
readonly scope: string;
|
|
581
|
+
readonly severity: ToolRuleSeverity;
|
|
582
|
+
readonly condition: string;
|
|
583
|
+
readonly action: string;
|
|
584
|
+
/** Free-form trailing markdown (examples, notes); empty string if none. */
|
|
585
|
+
readonly body: string;
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Frontmatter shape expected on a tool-rule `.md` file.
|
|
589
|
+
*
|
|
590
|
+
* `id` is optional in the source — if omitted, the filename stem is used.
|
|
591
|
+
*/
|
|
592
|
+
interface ToolRuleFrontmatter {
|
|
593
|
+
id?: string;
|
|
594
|
+
title: string;
|
|
595
|
+
scope: string;
|
|
596
|
+
severity: ToolRuleSeverity;
|
|
597
|
+
condition: string;
|
|
598
|
+
action: string;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Directory-backed tool-rule catalog. One `.md` file per rule.
|
|
603
|
+
*
|
|
604
|
+
* The catalog reads all `.md` files in `dir` on each query (no caching).
|
|
605
|
+
*/
|
|
606
|
+
declare class ToolRuleCatalog {
|
|
607
|
+
readonly dir: string;
|
|
608
|
+
constructor(dir: string);
|
|
609
|
+
/** Load every rule in the directory, sorted by id. */
|
|
610
|
+
list(): Promise<readonly ToolRule[]>;
|
|
611
|
+
/** Load a single rule by id. Returns `undefined` if not found. */
|
|
612
|
+
get(id: string): Promise<ToolRule | undefined>;
|
|
613
|
+
/** Return only rules whose `scope` matches exactly. */
|
|
614
|
+
filterByScope(scope: string): Promise<readonly ToolRule[]>;
|
|
615
|
+
/** Return only rules whose `severity` matches. */
|
|
616
|
+
filterBySeverity(severity: ToolRuleSeverity): Promise<readonly ToolRule[]>;
|
|
617
|
+
private entries;
|
|
618
|
+
private loadFile;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
//# sourceMappingURL=index.d.ts.map
|
|
622
|
+
|
|
623
|
+
type index_d$8_ToolRule = ToolRule;
|
|
624
|
+
type index_d$8_ToolRuleCatalog = ToolRuleCatalog;
|
|
625
|
+
declare const index_d$8_ToolRuleCatalog: typeof ToolRuleCatalog;
|
|
626
|
+
type index_d$8_ToolRuleFrontmatter = ToolRuleFrontmatter;
|
|
627
|
+
type index_d$8_ToolRuleSeverity = ToolRuleSeverity;
|
|
628
|
+
declare namespace index_d$8 {
|
|
629
|
+
export { type index_d$8_ToolRule as ToolRule, index_d$8_ToolRuleCatalog as ToolRuleCatalog, type index_d$8_ToolRuleFrontmatter as ToolRuleFrontmatter, type index_d$8_ToolRuleSeverity as ToolRuleSeverity };
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
interface RenderOptions {
|
|
633
|
+
/** Target viewer privacy level. Content above this is stripped. */
|
|
634
|
+
readonly targetPrivacy: Privacy;
|
|
635
|
+
/**
|
|
636
|
+
* Optional HTML template. The placeholders `{{title}}` and `{{content}}`
|
|
637
|
+
* are replaced. If omitted, a minimal default template is used.
|
|
638
|
+
*/
|
|
639
|
+
readonly template?: string;
|
|
640
|
+
/** Optional title for the `{{title}}` placeholder. */
|
|
641
|
+
readonly title?: string;
|
|
642
|
+
}
|
|
643
|
+
type WarningKind = "section-stripped" | "document-not-visible";
|
|
644
|
+
interface RenderWarning {
|
|
645
|
+
readonly kind: WarningKind;
|
|
646
|
+
readonly reason: string;
|
|
647
|
+
}
|
|
648
|
+
interface RenderResult {
|
|
649
|
+
/** Rendered HTML. Empty string if the document is not visible at target. */
|
|
650
|
+
readonly html: string;
|
|
651
|
+
/** Effective document privacy (frontmatter value or default `internal`). */
|
|
652
|
+
readonly documentPrivacy: Privacy;
|
|
653
|
+
/** Whether the document was visible at the requested target privacy. */
|
|
654
|
+
readonly visible: boolean;
|
|
655
|
+
/** Warnings collected during render (stripped sections, skipped docs). */
|
|
656
|
+
readonly warnings: readonly RenderWarning[];
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Render a markdown source to HTML, applying document-level and
|
|
661
|
+
* section-level privacy filtering before conversion.
|
|
662
|
+
*
|
|
663
|
+
* If the document's own privacy exceeds the target, an empty result is
|
|
664
|
+
* returned with a `document-not-visible` warning and no body conversion
|
|
665
|
+
* is performed.
|
|
666
|
+
*/
|
|
667
|
+
declare function renderHtml(source: string, options: RenderOptions): Promise<RenderResult>;
|
|
668
|
+
|
|
669
|
+
interface StripResult {
|
|
670
|
+
readonly content: string;
|
|
671
|
+
readonly warnings: readonly RenderWarning[];
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Remove section blocks whose declared privacy exceeds the target.
|
|
675
|
+
*
|
|
676
|
+
* Each section is delimited by `<!-- vortex:privacy LEVEL -->` and
|
|
677
|
+
* `<!-- /vortex:privacy -->`. Sections at or below target privacy keep
|
|
678
|
+
* their body (markers themselves are removed). Sections above target are
|
|
679
|
+
* stripped entirely and a `section-stripped` warning is reported.
|
|
680
|
+
*
|
|
681
|
+
* Sections do not nest; the parser does not support nesting.
|
|
682
|
+
*/
|
|
683
|
+
declare function stripPrivateSections(content: string, targetPrivacy: Privacy): StripResult;
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Minimal default template. Hosts that want styling, navigation, or
|
|
687
|
+
* additional metadata should pass a custom `template` to `renderHtml`.
|
|
688
|
+
*/
|
|
689
|
+
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";
|
|
690
|
+
/**
|
|
691
|
+
* Replace `{{name}}` placeholders in a template string with values from
|
|
692
|
+
* `vars`. Missing keys are replaced with the empty string.
|
|
693
|
+
*/
|
|
694
|
+
declare function applyTemplate(template: string, vars: Readonly<Record<string, string>>): string;
|
|
695
|
+
|
|
696
|
+
//# sourceMappingURL=index.d.ts.map
|
|
697
|
+
|
|
698
|
+
declare const index_d$7_DEFAULT_TEMPLATE: typeof DEFAULT_TEMPLATE;
|
|
699
|
+
type index_d$7_RenderOptions = RenderOptions;
|
|
700
|
+
type index_d$7_RenderResult = RenderResult;
|
|
701
|
+
type index_d$7_RenderWarning = RenderWarning;
|
|
702
|
+
type index_d$7_StripResult = StripResult;
|
|
703
|
+
type index_d$7_WarningKind = WarningKind;
|
|
704
|
+
declare const index_d$7_applyTemplate: typeof applyTemplate;
|
|
705
|
+
declare const index_d$7_renderHtml: typeof renderHtml;
|
|
706
|
+
declare const index_d$7_stripPrivateSections: typeof stripPrivateSections;
|
|
707
|
+
declare namespace index_d$7 {
|
|
708
|
+
export { index_d$7_DEFAULT_TEMPLATE as DEFAULT_TEMPLATE, type index_d$7_RenderOptions as RenderOptions, type index_d$7_RenderResult as RenderResult, type index_d$7_RenderWarning as RenderWarning, type index_d$7_StripResult as StripResult, type index_d$7_WarningKind as WarningKind, index_d$7_applyTemplate as applyTemplate, index_d$7_renderHtml as renderHtml, index_d$7_stripPrivateSections as stripPrivateSections };
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Frontmatter expected on a worklog file. All fields besides `type` are
|
|
713
|
+
* conventional — the store tolerates absence and surfaces what is present.
|
|
714
|
+
*/
|
|
715
|
+
interface WorklogFrontmatter {
|
|
716
|
+
type: "worklog";
|
|
717
|
+
status?: string;
|
|
718
|
+
privacy?: string;
|
|
719
|
+
created?: string;
|
|
720
|
+
updated?: string;
|
|
721
|
+
tags?: readonly string[];
|
|
722
|
+
related?: readonly string[];
|
|
723
|
+
[key: string]: unknown;
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* A parsed worklog entry.
|
|
727
|
+
*
|
|
728
|
+
* `date` is the ISO date portion of the filename (`YYYY-MM-DD`).
|
|
729
|
+
* `keyword` is the trailing slug portion of the filename without `.md`.
|
|
730
|
+
* `path` is the absolute path of the file on disk.
|
|
731
|
+
*/
|
|
732
|
+
interface WorklogEntry {
|
|
733
|
+
readonly date: string;
|
|
734
|
+
readonly keyword: string;
|
|
735
|
+
readonly path: string;
|
|
736
|
+
readonly frontmatter: WorklogFrontmatter;
|
|
737
|
+
readonly body: string;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* Directory-backed worklog store. Expected layout: `<rootDir>/YYYY/MM/YYYY-MM-DD-keyword.md`.
|
|
742
|
+
*
|
|
743
|
+
* The store treats missing subdirectories as empty, never as errors —
|
|
744
|
+
* a brand-new month with no entries returns an empty list, not a throw.
|
|
745
|
+
*/
|
|
746
|
+
declare class WorklogStore {
|
|
747
|
+
readonly rootDir: string;
|
|
748
|
+
constructor(rootDir: string);
|
|
749
|
+
/** All entries across all years and months, sorted by date ascending. */
|
|
750
|
+
list(): Promise<readonly WorklogEntry[]>;
|
|
751
|
+
/** Entries within one calendar month. */
|
|
752
|
+
listByMonth(year: number, month: number): Promise<readonly WorklogEntry[]>;
|
|
753
|
+
/**
|
|
754
|
+
* The first entry matching `date` (`YYYY-MM-DD`). If multiple files exist
|
|
755
|
+
* for that date with different keywords, the lexicographically-first one
|
|
756
|
+
* is returned. Use `list()` when all are needed.
|
|
757
|
+
*/
|
|
758
|
+
get(date: string): Promise<WorklogEntry | undefined>;
|
|
759
|
+
/** Most recent entry by date (descending), then keyword (descending). */
|
|
760
|
+
getLatest(): Promise<WorklogEntry | undefined>;
|
|
761
|
+
/** Resolve the file path for a given (date, keyword), without creating it. */
|
|
762
|
+
pathFor(date: string, keyword: string): string;
|
|
763
|
+
private listSubdirs;
|
|
764
|
+
private entriesIn;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Append a new section to the end of an existing worklog entry's file.
|
|
769
|
+
*
|
|
770
|
+
* The resulting markdown adds two leading blank lines, then `## <title>`,
|
|
771
|
+
* then a blank line, then the body. The entry's frontmatter is not touched.
|
|
772
|
+
*
|
|
773
|
+
* Returns the updated raw markdown that was written.
|
|
774
|
+
*/
|
|
775
|
+
declare function appendSection(entry: WorklogEntry, title: string, body: string): Promise<string>;
|
|
776
|
+
|
|
777
|
+
//# sourceMappingURL=index.d.ts.map
|
|
778
|
+
|
|
779
|
+
type index_d$6_WorklogEntry = WorklogEntry;
|
|
780
|
+
type index_d$6_WorklogFrontmatter = WorklogFrontmatter;
|
|
781
|
+
type index_d$6_WorklogStore = WorklogStore;
|
|
782
|
+
declare const index_d$6_WorklogStore: typeof WorklogStore;
|
|
783
|
+
declare const index_d$6_appendSection: typeof appendSection;
|
|
784
|
+
declare namespace index_d$6 {
|
|
785
|
+
export { type index_d$6_WorklogEntry as WorklogEntry, type index_d$6_WorklogFrontmatter as WorklogFrontmatter, index_d$6_WorklogStore as WorklogStore, index_d$6_appendSection as appendSection };
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/**
|
|
789
|
+
* Frontmatter expected on a Decision-Log entry. `type` is the only required
|
|
790
|
+
* field — the store tolerates absence of the rest and surfaces what is present.
|
|
791
|
+
*
|
|
792
|
+
* `privacy` defaults to `personal` by convention; callers should not rely on
|
|
793
|
+
* the store to enforce it.
|
|
794
|
+
*/
|
|
795
|
+
interface DecisionLogFrontmatter {
|
|
796
|
+
type: "decision-log";
|
|
797
|
+
status?: "active" | "template" | "archived" | string;
|
|
798
|
+
privacy?: "personal" | "internal" | "public" | string;
|
|
799
|
+
created?: string;
|
|
800
|
+
updated?: string;
|
|
801
|
+
tags?: readonly string[];
|
|
802
|
+
related?: readonly string[];
|
|
803
|
+
[key: string]: unknown;
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* A parsed Decision-Log entry.
|
|
807
|
+
*
|
|
808
|
+
* `date` is the ISO date portion of the filename (`YYYY-MM-DD`).
|
|
809
|
+
* `slug` is the trailing portion of the filename without `.md`.
|
|
810
|
+
* `path` is the absolute path of the file on disk.
|
|
811
|
+
*/
|
|
812
|
+
interface DecisionEntry {
|
|
813
|
+
readonly date: string;
|
|
814
|
+
readonly slug: string;
|
|
815
|
+
readonly path: string;
|
|
816
|
+
readonly frontmatter: DecisionLogFrontmatter;
|
|
817
|
+
readonly body: string;
|
|
818
|
+
}
|
|
819
|
+
/** Filter criteria for {@link DecisionStore.filter}. Empty filter matches all. */
|
|
820
|
+
interface DecisionFilter {
|
|
821
|
+
/** Match entries with `frontmatter.status` equal to this value. */
|
|
822
|
+
status?: string;
|
|
823
|
+
/** Match entries that contain this tag (case-sensitive). */
|
|
824
|
+
tag?: string;
|
|
825
|
+
/** Match entries with date >= this value (`YYYY-MM-DD`). */
|
|
826
|
+
fromDate?: string;
|
|
827
|
+
/** Match entries with date <= this value (`YYYY-MM-DD`). */
|
|
828
|
+
toDate?: string;
|
|
829
|
+
}
|
|
830
|
+
/** Input for {@link renderTemplate}. */
|
|
831
|
+
interface DecisionTemplateInput {
|
|
832
|
+
/** ISO date (`YYYY-MM-DD`). Also written into the body header. */
|
|
833
|
+
date: string;
|
|
834
|
+
/** Short kebab-style identifier used in the filename. */
|
|
835
|
+
slug: string;
|
|
836
|
+
/** One-line decision title shown as the H1. */
|
|
837
|
+
title: string;
|
|
838
|
+
/** Free-form area label (e.g. `work`, `personal`, `home-lab`). */
|
|
839
|
+
area?: string;
|
|
840
|
+
/** Extra tags appended after the default `decision-log` tag. */
|
|
841
|
+
tags?: readonly string[];
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
/**
|
|
845
|
+
* Directory-backed Decision-Log store. Expected layout is flat —
|
|
846
|
+
* `<rootDir>/YYYY-MM-DD-<slug>.md`, no year/month subdirectories.
|
|
847
|
+
*
|
|
848
|
+
* Non-entry files at the root (README, _TEMPLATE, anything not matching
|
|
849
|
+
* the date-prefix pattern) are silently ignored.
|
|
850
|
+
*
|
|
851
|
+
* A missing root directory returns an empty list rather than throwing,
|
|
852
|
+
* so a brand-new template clone with no entries is a normal state.
|
|
853
|
+
*/
|
|
854
|
+
declare class DecisionStore {
|
|
855
|
+
readonly rootDir: string;
|
|
856
|
+
constructor(rootDir: string);
|
|
857
|
+
/** All entries, sorted by date ascending, then slug ascending. */
|
|
858
|
+
list(): Promise<readonly DecisionEntry[]>;
|
|
859
|
+
/**
|
|
860
|
+
* Entries whose filename starts with `date` (`YYYY-MM-DD`). Multiple
|
|
861
|
+
* decisions on the same day are returned in slug-ascending order.
|
|
862
|
+
*/
|
|
863
|
+
getByDate(date: string): Promise<readonly DecisionEntry[]>;
|
|
864
|
+
/**
|
|
865
|
+
* The first entry matching `date` and (optionally) `slug`. When no slug is
|
|
866
|
+
* provided and multiple entries share the date, the lexicographically-first
|
|
867
|
+
* one is returned.
|
|
868
|
+
*/
|
|
869
|
+
get(date: string, slug?: string): Promise<DecisionEntry | undefined>;
|
|
870
|
+
/** Most recent entry by date (descending), then slug (descending). */
|
|
871
|
+
getLatest(): Promise<DecisionEntry | undefined>;
|
|
872
|
+
/**
|
|
873
|
+
* Subset of entries matching the given criteria. Empty/undefined fields
|
|
874
|
+
* are ignored. Returns entries in the same order as {@link list}.
|
|
875
|
+
*/
|
|
876
|
+
filter(criteria: DecisionFilter): Promise<readonly DecisionEntry[]>;
|
|
877
|
+
/** Resolve the file path for a given (date, slug), without creating it. */
|
|
878
|
+
pathFor(date: string, slug: string): string;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
/**
|
|
882
|
+
* Render a new Decision-Log entry body using an obsidian-style template
|
|
883
|
+
* convention. Caller is responsible for writing the result to disk via
|
|
884
|
+
* {@link DecisionStore.pathFor}.
|
|
885
|
+
*
|
|
886
|
+
* The output deliberately mirrors a human-authored template so the
|
|
887
|
+
* shape stays consistent whether the entry was created by hand or by
|
|
888
|
+
* this helper.
|
|
889
|
+
*/
|
|
890
|
+
declare function renderTemplate(input: DecisionTemplateInput): string;
|
|
891
|
+
|
|
892
|
+
//# sourceMappingURL=index.d.ts.map
|
|
893
|
+
|
|
894
|
+
type index_d$5_DecisionEntry = DecisionEntry;
|
|
895
|
+
type index_d$5_DecisionFilter = DecisionFilter;
|
|
896
|
+
type index_d$5_DecisionLogFrontmatter = DecisionLogFrontmatter;
|
|
897
|
+
type index_d$5_DecisionStore = DecisionStore;
|
|
898
|
+
declare const index_d$5_DecisionStore: typeof DecisionStore;
|
|
899
|
+
type index_d$5_DecisionTemplateInput = DecisionTemplateInput;
|
|
900
|
+
declare const index_d$5_renderTemplate: typeof renderTemplate;
|
|
901
|
+
declare namespace index_d$5 {
|
|
902
|
+
export { type index_d$5_DecisionEntry as DecisionEntry, type index_d$5_DecisionFilter as DecisionFilter, type index_d$5_DecisionLogFrontmatter as DecisionLogFrontmatter, index_d$5_DecisionStore as DecisionStore, type index_d$5_DecisionTemplateInput as DecisionTemplateInput, index_d$5_renderTemplate as renderTemplate };
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* One entry surfaced in a generated `_INDEX.md`.
|
|
907
|
+
*/
|
|
908
|
+
interface IndexEntry {
|
|
909
|
+
/** Path relative to the directory being indexed (forward slashes). */
|
|
910
|
+
readonly relPath: string;
|
|
911
|
+
/** Filename without extension. */
|
|
912
|
+
readonly name: string;
|
|
913
|
+
/** Title — `# H1` from the body, or filename fallback. */
|
|
914
|
+
readonly title: string;
|
|
915
|
+
/** Short description — frontmatter `description`, or first body paragraph fallback. */
|
|
916
|
+
readonly description?: string;
|
|
917
|
+
/** Frontmatter `type` value, if present (e.g. `worklog`, `decision-log`, `memory`). */
|
|
918
|
+
readonly type?: string;
|
|
919
|
+
/** Frontmatter `updated` or `created` value, ISO `YYYY-MM-DD` when parseable. */
|
|
920
|
+
readonly updated?: string;
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* Options controlling {@link scanDirectory}.
|
|
924
|
+
*/
|
|
925
|
+
interface ScanOptions {
|
|
926
|
+
/**
|
|
927
|
+
* Recurse into subdirectories. Default: false (flat scan).
|
|
928
|
+
*
|
|
929
|
+
* When true, the scanner descends into all subdirectories whose name does
|
|
930
|
+
* not start with `.` or `_`. The reserved files `README.md` and
|
|
931
|
+
* `_INDEX.md` are always skipped at every depth.
|
|
932
|
+
*/
|
|
933
|
+
recursive?: boolean;
|
|
934
|
+
/**
|
|
935
|
+
* Filenames to skip in addition to the always-skipped reserved files
|
|
936
|
+
* (`README.md`, `_INDEX.md`). Comparison is case-sensitive on the basename.
|
|
937
|
+
*/
|
|
938
|
+
skipFilenames?: readonly string[];
|
|
939
|
+
/**
|
|
940
|
+
* Filename prefixes to skip (e.g. `["_TEMPLATE"]`). Comparison is
|
|
941
|
+
* case-sensitive against the basename without extension.
|
|
942
|
+
*/
|
|
943
|
+
skipPrefixes?: readonly string[];
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* Input for {@link renderIndex}.
|
|
947
|
+
*/
|
|
948
|
+
interface RenderIndexInput {
|
|
949
|
+
/** Page H1 — typically the directory's human name (e.g. "Memory", "Worklog"). */
|
|
950
|
+
title: string;
|
|
951
|
+
/**
|
|
952
|
+
* One-line blockquote shown beneath the H1. Pass an empty string to omit
|
|
953
|
+
* the blockquote.
|
|
954
|
+
*/
|
|
955
|
+
description?: string;
|
|
956
|
+
/** Entries to list. Order is preserved as given. */
|
|
957
|
+
entries: readonly IndexEntry[];
|
|
958
|
+
/** Frontmatter `updated` field. Default: today's date in `YYYY-MM-DD`. */
|
|
959
|
+
updated?: string;
|
|
960
|
+
/** Frontmatter `privacy` field. Default: `internal`. */
|
|
961
|
+
privacy?: "public" | "internal" | "personal" | string;
|
|
962
|
+
/** Extra frontmatter tags besides the default `[index]`. */
|
|
963
|
+
extraTags?: readonly string[];
|
|
964
|
+
/** Optional "관련" links rendered after the entry list. */
|
|
965
|
+
related?: readonly string[];
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
/**
|
|
969
|
+
* Scan a directory of markdown notes and produce one {@link IndexEntry}
|
|
970
|
+
* per file, sorted by `relPath` ascending.
|
|
971
|
+
*
|
|
972
|
+
* - Files whose names are `README.md` or `_INDEX.md` are always skipped.
|
|
973
|
+
* - Hidden entries (name starting with `.` or `_`, except `_TEMPLATE` which
|
|
974
|
+
* is still surfaced but can be excluded via `skipPrefixes: ["_TEMPLATE"]`)
|
|
975
|
+
* are not descended into when `recursive: true`.
|
|
976
|
+
* - A missing directory returns an empty list rather than throwing.
|
|
977
|
+
*/
|
|
978
|
+
declare function scanDirectory(rootDir: string, opts?: ScanOptions): Promise<readonly IndexEntry[]>;
|
|
979
|
+
|
|
980
|
+
/**
|
|
981
|
+
* Render an `_INDEX.md` body from a {@link RenderIndexInput}.
|
|
982
|
+
*
|
|
983
|
+
* Output shape:
|
|
984
|
+
*
|
|
985
|
+
* ---
|
|
986
|
+
* type: index
|
|
987
|
+
* status: active
|
|
988
|
+
* privacy: <privacy>
|
|
989
|
+
* updated: <updated>
|
|
990
|
+
* tags: [index, <extraTags...>]
|
|
991
|
+
* ---
|
|
992
|
+
*
|
|
993
|
+
* # <title>
|
|
994
|
+
*
|
|
995
|
+
* > <description>
|
|
996
|
+
*
|
|
997
|
+
* ## 항목 (<count>)
|
|
998
|
+
*
|
|
999
|
+
* | 파일 | 설명 | 갱신 |
|
|
1000
|
+
* |---|---|---|
|
|
1001
|
+
* | [[<name>]] | <description or title> | <updated> |
|
|
1002
|
+
* ...
|
|
1003
|
+
*
|
|
1004
|
+
* ## 관련 (only if `related` is non-empty)
|
|
1005
|
+
*
|
|
1006
|
+
* - [[<related[0]>]]
|
|
1007
|
+
* ...
|
|
1008
|
+
*
|
|
1009
|
+
* Caller is responsible for writing this body to disk. The renderer never
|
|
1010
|
+
* touches the filesystem.
|
|
1011
|
+
*/
|
|
1012
|
+
declare function renderIndex(input: RenderIndexInput): string;
|
|
1013
|
+
|
|
1014
|
+
/**
|
|
1015
|
+
* Walk a directory tree and return every subdirectory that contains at
|
|
1016
|
+
* least `minEntries` markdown files at its top level. The root directory
|
|
1017
|
+
* itself is included if it qualifies.
|
|
1018
|
+
*
|
|
1019
|
+
* "At its top level" means `.md` files **directly inside** the directory
|
|
1020
|
+
* (not in its subdirectories) — this is what an `_INDEX.md` in that
|
|
1021
|
+
* directory would index.
|
|
1022
|
+
*
|
|
1023
|
+
* `README.md` and `_INDEX.md` files are not counted (they are not
|
|
1024
|
+
* indexable entries). `.md` files starting with prefixes in `skipPrefixes`
|
|
1025
|
+
* are also not counted.
|
|
1026
|
+
*
|
|
1027
|
+
* Hidden directories (`.foo`) are not descended into. `_foo` directories
|
|
1028
|
+
* are descended into — they may legitimately contain content
|
|
1029
|
+
* (`_HUB-*.md`, `_INDEX.md` of subdirectories).
|
|
1030
|
+
*
|
|
1031
|
+
* A missing root directory returns an empty list rather than throwing.
|
|
1032
|
+
*
|
|
1033
|
+
* Use case — splitting a giant flat `_INDEX.md` into per-folder
|
|
1034
|
+
* indexes: scan a tree, find the meaningful directories, write an
|
|
1035
|
+
* `_INDEX.md` in each.
|
|
1036
|
+
*/
|
|
1037
|
+
declare function findIndexableDirs(rootDir: string, options?: {
|
|
1038
|
+
minEntries?: number;
|
|
1039
|
+
skipPrefixes?: readonly string[];
|
|
1040
|
+
}): Promise<readonly string[]>;
|
|
1041
|
+
|
|
1042
|
+
//# sourceMappingURL=index.d.ts.map
|
|
1043
|
+
|
|
1044
|
+
type index_d$4_IndexEntry = IndexEntry;
|
|
1045
|
+
type index_d$4_RenderIndexInput = RenderIndexInput;
|
|
1046
|
+
type index_d$4_ScanOptions = ScanOptions;
|
|
1047
|
+
declare const index_d$4_findIndexableDirs: typeof findIndexableDirs;
|
|
1048
|
+
declare const index_d$4_renderIndex: typeof renderIndex;
|
|
1049
|
+
declare const index_d$4_scanDirectory: typeof scanDirectory;
|
|
1050
|
+
declare namespace index_d$4 {
|
|
1051
|
+
export { type index_d$4_IndexEntry as IndexEntry, type index_d$4_RenderIndexInput as RenderIndexInput, type index_d$4_ScanOptions as ScanOptions, index_d$4_findIndexableDirs as findIndexableDirs, index_d$4_renderIndex as renderIndex, index_d$4_scanDirectory as scanDirectory };
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
/**
|
|
1055
|
+
* Frontmatter expected on a Runbook entry. `type` is the only required
|
|
1056
|
+
* field; the store tolerates absence of the rest and surfaces what is present.
|
|
1057
|
+
*/
|
|
1058
|
+
interface RunbookFrontmatter {
|
|
1059
|
+
type: "runbook";
|
|
1060
|
+
status?: "active" | "draft" | "archived" | string;
|
|
1061
|
+
privacy?: "public" | "internal" | "personal" | string;
|
|
1062
|
+
/** ISO date (`YYYY-MM-DD`) when this runbook was last verified end-to-end. */
|
|
1063
|
+
last_tested?: string;
|
|
1064
|
+
/** Free-form incident category (e.g. `network-outage`, `mail-outage`). */
|
|
1065
|
+
"incident-type"?: string;
|
|
1066
|
+
created?: string;
|
|
1067
|
+
updated?: string;
|
|
1068
|
+
tags?: readonly string[];
|
|
1069
|
+
related?: readonly string[] | string;
|
|
1070
|
+
[key: string]: unknown;
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* A parsed runbook entry.
|
|
1074
|
+
*
|
|
1075
|
+
* `slug` is the filename without the `.md` extension. Runbooks live in a
|
|
1076
|
+
* flat directory — no date-prefix convention, since the name is typically
|
|
1077
|
+
* descriptive (`service-restart-procedure`, `database-restore`).
|
|
1078
|
+
*/
|
|
1079
|
+
interface RunbookEntry {
|
|
1080
|
+
readonly slug: string;
|
|
1081
|
+
readonly path: string;
|
|
1082
|
+
readonly frontmatter: RunbookFrontmatter;
|
|
1083
|
+
readonly body: string;
|
|
1084
|
+
}
|
|
1085
|
+
/** Filter criteria for {@link RunbookStore.filter}. */
|
|
1086
|
+
interface RunbookFilter {
|
|
1087
|
+
/** Match entries with `frontmatter.status` equal to this value. */
|
|
1088
|
+
status?: string;
|
|
1089
|
+
/** Match entries that contain this tag (case-sensitive). */
|
|
1090
|
+
tag?: string;
|
|
1091
|
+
/** Match entries with `frontmatter['incident-type']` equal to this value. */
|
|
1092
|
+
incidentType?: string;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
/**
|
|
1096
|
+
* Directory-backed runbook store. Expected layout is flat —
|
|
1097
|
+
* `<rootDir>/<slug>.md`, no subdirectories.
|
|
1098
|
+
*
|
|
1099
|
+
* Non-entry files at the root (README, _INDEX, anything not ending in `.md`)
|
|
1100
|
+
* are silently ignored. A missing root directory returns an empty list
|
|
1101
|
+
* rather than throwing.
|
|
1102
|
+
*/
|
|
1103
|
+
declare class RunbookStore {
|
|
1104
|
+
readonly rootDir: string;
|
|
1105
|
+
constructor(rootDir: string);
|
|
1106
|
+
/** All entries, sorted by slug ascending. */
|
|
1107
|
+
list(): Promise<readonly RunbookEntry[]>;
|
|
1108
|
+
/** A single entry by slug, or undefined if not found. */
|
|
1109
|
+
get(slug: string): Promise<RunbookEntry | undefined>;
|
|
1110
|
+
/**
|
|
1111
|
+
* Subset of entries matching the given criteria. Empty/undefined fields
|
|
1112
|
+
* are ignored. Returns entries in the same order as {@link list}.
|
|
1113
|
+
*/
|
|
1114
|
+
filter(criteria: RunbookFilter): Promise<readonly RunbookEntry[]>;
|
|
1115
|
+
/**
|
|
1116
|
+
* Entries whose `last_tested` is older than `staleAfterDays` from the
|
|
1117
|
+
* given reference date (default: today). Entries without a `last_tested`
|
|
1118
|
+
* field are treated as "never tested" and are always returned.
|
|
1119
|
+
*
|
|
1120
|
+
* This is the practical reason runbooks are a module rather than plain
|
|
1121
|
+
* data — periodic reverification is a real operational need.
|
|
1122
|
+
*/
|
|
1123
|
+
getStaleByLastTested(staleAfterDays: number, referenceDate?: Date): Promise<readonly RunbookEntry[]>;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
//# sourceMappingURL=index.d.ts.map
|
|
1127
|
+
|
|
1128
|
+
type index_d$3_RunbookEntry = RunbookEntry;
|
|
1129
|
+
type index_d$3_RunbookFilter = RunbookFilter;
|
|
1130
|
+
type index_d$3_RunbookFrontmatter = RunbookFrontmatter;
|
|
1131
|
+
type index_d$3_RunbookStore = RunbookStore;
|
|
1132
|
+
declare const index_d$3_RunbookStore: typeof RunbookStore;
|
|
1133
|
+
declare namespace index_d$3 {
|
|
1134
|
+
export { type index_d$3_RunbookEntry as RunbookEntry, type index_d$3_RunbookFilter as RunbookFilter, type index_d$3_RunbookFrontmatter as RunbookFrontmatter, index_d$3_RunbookStore as RunbookStore };
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
/**
|
|
1138
|
+
* A wiki link extracted from a markdown body.
|
|
1139
|
+
*
|
|
1140
|
+
* Examples (input → parsed shape):
|
|
1141
|
+
* `[[Foo]]` → { name: "Foo" }
|
|
1142
|
+
* `[[Foo|bar]]` → { name: "Foo", alias: "bar" }
|
|
1143
|
+
* `[[Foo#Section]]` → { name: "Foo", anchor: "Section" }
|
|
1144
|
+
* `[[Foo#Sec|bar]]` → { name: "Foo", anchor: "Sec", alias: "bar" }
|
|
1145
|
+
*/
|
|
1146
|
+
interface WikiLink {
|
|
1147
|
+
/** Target page name as written, without the `.md` extension. */
|
|
1148
|
+
readonly name: string;
|
|
1149
|
+
/** Section anchor after `#`, if present. */
|
|
1150
|
+
readonly anchor?: string;
|
|
1151
|
+
/** Display alias after `|`, if present. */
|
|
1152
|
+
readonly alias?: string;
|
|
1153
|
+
/** Original raw text including `[[...]]` brackets. */
|
|
1154
|
+
readonly raw: string;
|
|
1155
|
+
}
|
|
1156
|
+
/**
|
|
1157
|
+
* A wiki link that did not resolve against the filesystem index.
|
|
1158
|
+
*
|
|
1159
|
+
* `sourcePath` is the absolute path of the file that contained the link.
|
|
1160
|
+
* `link` is the parsed link itself. Reason is a short string identifying
|
|
1161
|
+
* why resolution failed (e.g. `not-found`).
|
|
1162
|
+
*/
|
|
1163
|
+
interface BrokenLink {
|
|
1164
|
+
readonly sourcePath: string;
|
|
1165
|
+
readonly link: WikiLink;
|
|
1166
|
+
readonly reason: "not-found" | "ambiguous";
|
|
1167
|
+
/** When `ambiguous`, the candidate paths that matched the name. */
|
|
1168
|
+
readonly candidates?: readonly string[];
|
|
1169
|
+
}
|
|
1170
|
+
/**
|
|
1171
|
+
* Aggregate result of {@link checkDirectory}.
|
|
1172
|
+
*/
|
|
1173
|
+
interface LinkCheckResult {
|
|
1174
|
+
/** Number of `.md` files scanned. */
|
|
1175
|
+
readonly filesScanned: number;
|
|
1176
|
+
/** Total wiki links encountered across all files. */
|
|
1177
|
+
readonly totalLinks: number;
|
|
1178
|
+
/** Links that resolved to a unique target. */
|
|
1179
|
+
readonly resolved: number;
|
|
1180
|
+
/** Detail of unresolved links. */
|
|
1181
|
+
readonly broken: readonly BrokenLink[];
|
|
1182
|
+
/** Detail of ambiguous links (name matched multiple files). */
|
|
1183
|
+
readonly ambiguous: readonly BrokenLink[];
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
/**
|
|
1187
|
+
* Extract every wiki link from a markdown body. Returns links in
|
|
1188
|
+
* document order; duplicates are preserved (callers can dedupe if they
|
|
1189
|
+
* want, but a broken link in two places is still two repairs).
|
|
1190
|
+
*
|
|
1191
|
+
* Code fences and inline code spans are not stripped — this module
|
|
1192
|
+
* treats markdown as text. Hosts that need to ignore links inside
|
|
1193
|
+
* code blocks should pre-filter the body.
|
|
1194
|
+
*/
|
|
1195
|
+
declare function extractWikiLinks(body: string): readonly WikiLink[];
|
|
1196
|
+
|
|
1197
|
+
/**
|
|
1198
|
+
* Filesystem index of every `.md` file under a root.
|
|
1199
|
+
*
|
|
1200
|
+
* Provides two lookup paths:
|
|
1201
|
+
*
|
|
1202
|
+
* - `byBasename` — `name` (no `.md`) → list of absolute paths. Used for
|
|
1203
|
+
* bare wiki links like `[[Foo]]`, which Obsidian resolves by filename
|
|
1204
|
+
* anywhere in the vault.
|
|
1205
|
+
* - `byRelPath` — forward-slash relative path (no `.md`) → absolute path.
|
|
1206
|
+
* Used for path-aware wiki links like `[[Projects/Home/Foo]]` or
|
|
1207
|
+
* `[[../Foo]]`, where the operator wrote a path on purpose to
|
|
1208
|
+
* disambiguate.
|
|
1209
|
+
*
|
|
1210
|
+
* `rootDir` is retained so resolvers can interpret root-relative paths.
|
|
1211
|
+
*/
|
|
1212
|
+
interface FileIndex {
|
|
1213
|
+
readonly byBasename: ReadonlyMap<string, readonly string[]>;
|
|
1214
|
+
readonly byRelPath: ReadonlyMap<string, string>;
|
|
1215
|
+
/**
|
|
1216
|
+
* Optional lowercase rel-path → absolute-path map for case-insensitive
|
|
1217
|
+
* fallback. Present only when {@link buildFileIndex} was called with
|
|
1218
|
+
* `caseInsensitive: true`. If two rel-paths collide after lowercasing,
|
|
1219
|
+
* the first walker-visited path wins; the conflict is silent (rare in
|
|
1220
|
+
* a well-organized tree).
|
|
1221
|
+
*/
|
|
1222
|
+
readonly byRelPathLower?: ReadonlyMap<string, string>;
|
|
1223
|
+
readonly rootDir: string;
|
|
1224
|
+
}
|
|
1225
|
+
/**
|
|
1226
|
+
* Options for {@link buildFileIndex}.
|
|
1227
|
+
*/
|
|
1228
|
+
interface BuildIndexOptions {
|
|
1229
|
+
/**
|
|
1230
|
+
* Build an additional lowercase `byRelPathLower` map so {@link resolveLink}
|
|
1231
|
+
* can fall back to case-insensitive matching when the exact-case path
|
|
1232
|
+
* lookup fails. Useful when the operator's wiki-link convention uses
|
|
1233
|
+
* different casing than the on-disk layout (a frequent situation when
|
|
1234
|
+
* content is migrated from one vault into another with renamed roots,
|
|
1235
|
+
* e.g. `[[Projects/Home/foo]]` vs `data/projects/home/foo.md`).
|
|
1236
|
+
*
|
|
1237
|
+
* Default: false. Bare-name lookup is unaffected — Obsidian historically
|
|
1238
|
+
* treats bare names case-sensitively, and we keep that.
|
|
1239
|
+
*/
|
|
1240
|
+
caseInsensitive?: boolean;
|
|
1241
|
+
/**
|
|
1242
|
+
* Extra file extensions (besides `.md`) to include in the index. Each
|
|
1243
|
+
* extension must include the leading dot, e.g. `[".hwp", ".docx", ".pdf"]`.
|
|
1244
|
+
*
|
|
1245
|
+
* `.md` files are always indexed with the extension stripped from their
|
|
1246
|
+
* key — `[[Foo]]` matches `Foo.md`. Files with one of the additional
|
|
1247
|
+
* extensions are indexed with the extension *kept*, so they only match
|
|
1248
|
+
* when the operator writes the full filename — `[[Foo.hwp]]` matches
|
|
1249
|
+
* `Foo.hwp`. This avoids surprise collisions where `[[Foo]]` would
|
|
1250
|
+
* suddenly match a non-markdown file.
|
|
1251
|
+
*
|
|
1252
|
+
* Default: `[]` (only `.md` is indexed; preserves v1 behavior).
|
|
1253
|
+
*
|
|
1254
|
+
* Note: only `.md` files are scanned for wiki links by
|
|
1255
|
+
* {@link import("./checker.js").checkDirectory} and rewritten by
|
|
1256
|
+
* {@link import("./rewrite.js").rewriteDirectory}. Additional extensions
|
|
1257
|
+
* affect *resolution targets* (what a wiki link can point at), not
|
|
1258
|
+
* *scan sources* (what a wiki link can appear in).
|
|
1259
|
+
*/
|
|
1260
|
+
additionalExtensions?: readonly string[];
|
|
1261
|
+
}
|
|
1262
|
+
/**
|
|
1263
|
+
* Walk `rootDir` recursively and build a {@link FileIndex} of every `.md`
|
|
1264
|
+
* file (plus any `additionalExtensions` requested).
|
|
1265
|
+
*
|
|
1266
|
+
* Hidden directories (`.foo`) are skipped. `_foo` directories ARE indexed —
|
|
1267
|
+
* Obsidian wiki links can target any markdown file regardless of underscore
|
|
1268
|
+
* prefix, so we mirror that. A missing root returns an empty index.
|
|
1269
|
+
*/
|
|
1270
|
+
declare function buildFileIndex(rootDir: string, options?: BuildIndexOptions): Promise<FileIndex>;
|
|
1271
|
+
/**
|
|
1272
|
+
* Resolution outcome for a single wiki link.
|
|
1273
|
+
*
|
|
1274
|
+
* - `unique`: one and only one file matched.
|
|
1275
|
+
* - `not-found`: no file matched.
|
|
1276
|
+
* - `ambiguous`: multiple files share the basename (only possible for
|
|
1277
|
+
* bare-name links; path-aware links always resolve uniquely or fail).
|
|
1278
|
+
*/
|
|
1279
|
+
type ResolveOutcome = {
|
|
1280
|
+
kind: "unique";
|
|
1281
|
+
path: string;
|
|
1282
|
+
} | {
|
|
1283
|
+
kind: "not-found";
|
|
1284
|
+
} | {
|
|
1285
|
+
kind: "ambiguous";
|
|
1286
|
+
candidates: readonly string[];
|
|
1287
|
+
};
|
|
1288
|
+
/**
|
|
1289
|
+
* Optional hints that turn on path-aware resolution.
|
|
1290
|
+
*
|
|
1291
|
+
* - `sourcePath` — absolute path of the file the link was found in.
|
|
1292
|
+
* Required to resolve `../foo`-style relative links.
|
|
1293
|
+
*
|
|
1294
|
+
* When neither hint is set, behavior collapses to bare-name lookup
|
|
1295
|
+
* (basename only), matching the original v1 semantics.
|
|
1296
|
+
*/
|
|
1297
|
+
interface ResolveOpts {
|
|
1298
|
+
sourcePath?: string;
|
|
1299
|
+
}
|
|
1300
|
+
/**
|
|
1301
|
+
* Look up a wiki link in the index. Three cases:
|
|
1302
|
+
*
|
|
1303
|
+
* 1. **Bare name** (`[[Foo]]`) — basename lookup only. Returns `unique`
|
|
1304
|
+
* if exactly one `Foo.md` exists, `ambiguous` if multiple, `not-found`
|
|
1305
|
+
* otherwise.
|
|
1306
|
+
* 2. **Root-relative path** (`[[Projects/Foo]]`) — exact rel-path lookup
|
|
1307
|
+
* against the index. Always `unique` or `not-found`.
|
|
1308
|
+
* 3. **Source-relative path** (`[[../Foo]]`, `[[./Foo]]`) — resolved
|
|
1309
|
+
* against `dirname(sourcePath)` first, then looked up by rel-path.
|
|
1310
|
+
* Requires `opts.sourcePath`; without it, returns `not-found`.
|
|
1311
|
+
*
|
|
1312
|
+
* Trailing `.md` in the link name is stripped before matching.
|
|
1313
|
+
*/
|
|
1314
|
+
declare function resolveLink(name: string, index: FileIndex, opts?: ResolveOpts): ResolveOutcome;
|
|
1315
|
+
/**
|
|
1316
|
+
* Reduce an absolute path to one relative to `rootDir`, using forward
|
|
1317
|
+
* slashes. Useful for reporting.
|
|
1318
|
+
*/
|
|
1319
|
+
declare function toRel(path: string, rootDir: string): string;
|
|
1320
|
+
|
|
1321
|
+
/**
|
|
1322
|
+
* Options for {@link checkDirectory}.
|
|
1323
|
+
*/
|
|
1324
|
+
interface CheckDirectoryOptions extends BuildIndexOptions {
|
|
1325
|
+
}
|
|
1326
|
+
/**
|
|
1327
|
+
* Scan every `.md` file under `rootDir`, extract wiki links, and
|
|
1328
|
+
* report which ones cannot be resolved (or resolve to multiple files).
|
|
1329
|
+
*
|
|
1330
|
+
* This is read-only — it does not modify any file. The function returns
|
|
1331
|
+
* a structured result so hosts can decide whether to log, fail a build,
|
|
1332
|
+
* propose rewrites, etc.
|
|
1333
|
+
*
|
|
1334
|
+
* Pass `caseInsensitive: true` when wiki-link casing may differ from
|
|
1335
|
+
* the on-disk path (e.g. content migrated from a vault with different
|
|
1336
|
+
* directory naming conventions).
|
|
1337
|
+
*/
|
|
1338
|
+
declare function checkDirectory(rootDir: string, options?: CheckDirectoryOptions): Promise<LinkCheckResult>;
|
|
1339
|
+
/**
|
|
1340
|
+
* Group broken links by target name and return counts in descending order.
|
|
1341
|
+
* Useful for quickly identifying the most-cited missing pages.
|
|
1342
|
+
*/
|
|
1343
|
+
declare function topBrokenTargets(broken: readonly BrokenLink[], limit?: number): readonly {
|
|
1344
|
+
readonly name: string;
|
|
1345
|
+
readonly count: number;
|
|
1346
|
+
}[];
|
|
1347
|
+
|
|
1348
|
+
/**
|
|
1349
|
+
* Map of wiki-link names to replace.
|
|
1350
|
+
*
|
|
1351
|
+
* Both keys and values are the `name` portion of a wiki link — what
|
|
1352
|
+
* appears between `[[` and the optional `#anchor` / `|alias`. Anchors
|
|
1353
|
+
* and aliases on the original link are preserved automatically.
|
|
1354
|
+
*
|
|
1355
|
+
* Examples:
|
|
1356
|
+
* { "API-Tokens": "secrets/api-tokens" }
|
|
1357
|
+
* [[API-Tokens]] → [[secrets/api-tokens]]
|
|
1358
|
+
* [[API-Tokens|토큰]] → [[secrets/api-tokens|토큰]]
|
|
1359
|
+
* [[API-Tokens#A|토큰]] → [[secrets/api-tokens#A|토큰]]
|
|
1360
|
+
*
|
|
1361
|
+
* Use the exact name string the operator wrote — no normalization is
|
|
1362
|
+
* applied. If the same broken target appears with different spellings
|
|
1363
|
+
* (e.g. case differences), provide one entry per spelling.
|
|
1364
|
+
*/
|
|
1365
|
+
type RedirectionMap = ReadonlyMap<string, string>;
|
|
1366
|
+
/**
|
|
1367
|
+
* Options for {@link rewriteDirectory}.
|
|
1368
|
+
*/
|
|
1369
|
+
interface RewriteOptions {
|
|
1370
|
+
/**
|
|
1371
|
+
* The redirection map driving the rewrite. Links whose name is not
|
|
1372
|
+
* a key in this map are left untouched.
|
|
1373
|
+
*/
|
|
1374
|
+
redirections: RedirectionMap;
|
|
1375
|
+
/**
|
|
1376
|
+
* When true, do not write any files. The result still describes the
|
|
1377
|
+
* rewrites that would happen — useful for showing the operator what
|
|
1378
|
+
* a redirection map will do before it does it.
|
|
1379
|
+
*/
|
|
1380
|
+
dryRun?: boolean;
|
|
1381
|
+
}
|
|
1382
|
+
/**
|
|
1383
|
+
* Per-file detail of a rewrite operation.
|
|
1384
|
+
*/
|
|
1385
|
+
interface FileRewrite {
|
|
1386
|
+
readonly sourcePath: string;
|
|
1387
|
+
readonly rewrites: readonly {
|
|
1388
|
+
readonly from: string;
|
|
1389
|
+
readonly to: string;
|
|
1390
|
+
}[];
|
|
1391
|
+
}
|
|
1392
|
+
/**
|
|
1393
|
+
* Aggregate result of {@link rewriteDirectory}.
|
|
1394
|
+
*/
|
|
1395
|
+
interface RewriteResult {
|
|
1396
|
+
readonly filesScanned: number;
|
|
1397
|
+
/** Files whose body was changed (or would be changed under dry-run). */
|
|
1398
|
+
readonly filesChanged: number;
|
|
1399
|
+
/** Total number of link replacements (may exceed `filesChanged`). */
|
|
1400
|
+
readonly rewritesApplied: number;
|
|
1401
|
+
/** Links matching a redirection key but ultimately not replaced — currently always 0; reserved for future skip reasons. */
|
|
1402
|
+
readonly skipped: number;
|
|
1403
|
+
readonly details: readonly FileRewrite[];
|
|
1404
|
+
readonly dryRun: boolean;
|
|
1405
|
+
}
|
|
1406
|
+
/**
|
|
1407
|
+
* Walk every `.md` file under `rootDir`, replace wiki links whose name
|
|
1408
|
+
* is a key in `redirections`, and write the changed files back to disk
|
|
1409
|
+
* (or describe what would change when `dryRun: true`).
|
|
1410
|
+
*
|
|
1411
|
+
* Only the link `name` is replaced. Anchors (`#Section`) and aliases
|
|
1412
|
+
* (`|display`) carry over verbatim onto the replacement link. The
|
|
1413
|
+
* surrounding markdown body is untouched.
|
|
1414
|
+
*
|
|
1415
|
+
* Rewriting is deterministic and order-independent — within a file,
|
|
1416
|
+
* every occurrence of every mapped key is replaced exactly once per
|
|
1417
|
+
* occurrence, with no chaining (the replacement is not re-scanned for
|
|
1418
|
+
* further matches).
|
|
1419
|
+
*/
|
|
1420
|
+
declare function rewriteDirectory(rootDir: string, opts: RewriteOptions): Promise<RewriteResult>;
|
|
1421
|
+
/**
|
|
1422
|
+
* Pure transformation: take a markdown body, return the body with all
|
|
1423
|
+
* `[[…]]` links whose name appears in `redirections` rewritten. Exported
|
|
1424
|
+
* for testing and for callers that need to rewrite an in-memory string.
|
|
1425
|
+
*
|
|
1426
|
+
* The transformation does not touch markdown outside `[[…]]` patterns.
|
|
1427
|
+
*/
|
|
1428
|
+
declare function rewriteBody(body: string, redirections: RedirectionMap): {
|
|
1429
|
+
newBody: string;
|
|
1430
|
+
fileRewrites: {
|
|
1431
|
+
from: string;
|
|
1432
|
+
to: string;
|
|
1433
|
+
}[];
|
|
1434
|
+
};
|
|
1435
|
+
|
|
1436
|
+
//# sourceMappingURL=index.d.ts.map
|
|
1437
|
+
|
|
1438
|
+
type index_d$2_BrokenLink = BrokenLink;
|
|
1439
|
+
type index_d$2_BuildIndexOptions = BuildIndexOptions;
|
|
1440
|
+
type index_d$2_CheckDirectoryOptions = CheckDirectoryOptions;
|
|
1441
|
+
type index_d$2_FileIndex = FileIndex;
|
|
1442
|
+
type index_d$2_FileRewrite = FileRewrite;
|
|
1443
|
+
type index_d$2_LinkCheckResult = LinkCheckResult;
|
|
1444
|
+
type index_d$2_RedirectionMap = RedirectionMap;
|
|
1445
|
+
type index_d$2_ResolveOpts = ResolveOpts;
|
|
1446
|
+
type index_d$2_ResolveOutcome = ResolveOutcome;
|
|
1447
|
+
type index_d$2_RewriteOptions = RewriteOptions;
|
|
1448
|
+
type index_d$2_RewriteResult = RewriteResult;
|
|
1449
|
+
type index_d$2_WikiLink = WikiLink;
|
|
1450
|
+
declare const index_d$2_buildFileIndex: typeof buildFileIndex;
|
|
1451
|
+
declare const index_d$2_checkDirectory: typeof checkDirectory;
|
|
1452
|
+
declare const index_d$2_extractWikiLinks: typeof extractWikiLinks;
|
|
1453
|
+
declare const index_d$2_resolveLink: typeof resolveLink;
|
|
1454
|
+
declare const index_d$2_rewriteBody: typeof rewriteBody;
|
|
1455
|
+
declare const index_d$2_rewriteDirectory: typeof rewriteDirectory;
|
|
1456
|
+
declare const index_d$2_toRel: typeof toRel;
|
|
1457
|
+
declare const index_d$2_topBrokenTargets: typeof topBrokenTargets;
|
|
1458
|
+
declare namespace index_d$2 {
|
|
1459
|
+
export { type index_d$2_BrokenLink as BrokenLink, type index_d$2_BuildIndexOptions as BuildIndexOptions, type index_d$2_CheckDirectoryOptions as CheckDirectoryOptions, type index_d$2_FileIndex as FileIndex, type index_d$2_FileRewrite as FileRewrite, type index_d$2_LinkCheckResult as LinkCheckResult, type index_d$2_RedirectionMap as RedirectionMap, type index_d$2_ResolveOpts as ResolveOpts, type index_d$2_ResolveOutcome as ResolveOutcome, type index_d$2_RewriteOptions as RewriteOptions, type index_d$2_RewriteResult as RewriteResult, type index_d$2_WikiLink as WikiLink, index_d$2_buildFileIndex as buildFileIndex, index_d$2_checkDirectory as checkDirectory, index_d$2_extractWikiLinks as extractWikiLinks, index_d$2_resolveLink as resolveLink, index_d$2_rewriteBody as rewriteBody, index_d$2_rewriteDirectory as rewriteDirectory, index_d$2_toRel as toRel, index_d$2_topBrokenTargets as topBrokenTargets };
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
/**
|
|
1463
|
+
* Host-supplied LLM adapter. The proposer asks structured questions
|
|
1464
|
+
* (a prompt plus a JSON-shaped expected answer); the host runs the question
|
|
1465
|
+
* against whatever LLM facility it has — a sub-agent tool call (Claude Code),
|
|
1466
|
+
* an inline completion (Codex), an MCP call (Gemini), or a Claude Desktop
|
|
1467
|
+
* surface. The proposer does not care which.
|
|
1468
|
+
*
|
|
1469
|
+
* The interface is intentionally narrow: prompt in, structured answer out.
|
|
1470
|
+
* No streaming, no tool registration, no token budget knobs. Each
|
|
1471
|
+
* `LLMJudge.ask()` call is a single-shot decision query.
|
|
1472
|
+
*
|
|
1473
|
+
* This mirrors the `TranscriptAdapter` pattern in `@vortex-os/memory-extended`
|
|
1474
|
+
* — host-specific work is isolated to one adapter per host; the consumer
|
|
1475
|
+
* (`InsightProposer`, `HubProposer`) is host-agnostic.
|
|
1476
|
+
*/
|
|
1477
|
+
interface LLMJudge {
|
|
1478
|
+
/**
|
|
1479
|
+
* Identifier of the host this adapter speaks to. Used for diagnostics and
|
|
1480
|
+
* for proposals to record which judge approved them (`accepted.log`).
|
|
1481
|
+
* Open-ended string so third-party hosts can register their own identifier.
|
|
1482
|
+
*/
|
|
1483
|
+
readonly host: string;
|
|
1484
|
+
/**
|
|
1485
|
+
* Run a single-shot decision query against the host LLM.
|
|
1486
|
+
*
|
|
1487
|
+
* Implementations must:
|
|
1488
|
+
* - Pass `prompt` to the underlying LLM with whatever system instructions
|
|
1489
|
+
* the host normally uses (no special framing required from the caller).
|
|
1490
|
+
* - Constrain the response to match `expected.shape` — either by JSON-
|
|
1491
|
+
* mode generation, by structured output, or by a retry loop that
|
|
1492
|
+
* reformats the response. The proposer assumes the returned value
|
|
1493
|
+
* conforms to `expected.shape`.
|
|
1494
|
+
* - Throw on persistent format failure rather than returning malformed
|
|
1495
|
+
* data. Callers handle the rejection rather than the host masking it.
|
|
1496
|
+
*
|
|
1497
|
+
* The return type is `unknown` because the caller knows the shape it
|
|
1498
|
+
* expects (it supplied `expected.shape`) and runtime-validates after the
|
|
1499
|
+
* call. Keeping the static return loose avoids coupling the interface to
|
|
1500
|
+
* a particular validation library.
|
|
1501
|
+
*/
|
|
1502
|
+
ask(prompt: string, expected: ExpectedShape): Promise<unknown>;
|
|
1503
|
+
}
|
|
1504
|
+
/**
|
|
1505
|
+
* Shape descriptor for the expected LLM response. Kept minimal so any
|
|
1506
|
+
* validation library (zod, valibot, hand-rolled) can produce one.
|
|
1507
|
+
*
|
|
1508
|
+
* - `shape: "string"` — a single free-form string answer (e.g. a yes/no,
|
|
1509
|
+
* a slug, a summary).
|
|
1510
|
+
* - `shape: "json"` — a JSON value matching the supplied JSON-Schema-like
|
|
1511
|
+
* descriptor. Implementations may pass the descriptor to a structured-
|
|
1512
|
+
* output mode if the underlying LLM supports it; otherwise they must
|
|
1513
|
+
* validate after generation.
|
|
1514
|
+
*/
|
|
1515
|
+
type ExpectedShape = {
|
|
1516
|
+
readonly shape: "string";
|
|
1517
|
+
} | {
|
|
1518
|
+
readonly shape: "json";
|
|
1519
|
+
/**
|
|
1520
|
+
* Free-form schema descriptor — passed through to the host's structured
|
|
1521
|
+
* output mechanism if any, otherwise informational only. The proposer
|
|
1522
|
+
* still runs its own runtime check on the returned value, so this
|
|
1523
|
+
* field's contract is best-effort.
|
|
1524
|
+
*/
|
|
1525
|
+
readonly schema: unknown;
|
|
1526
|
+
};
|
|
1527
|
+
|
|
1528
|
+
/**
|
|
1529
|
+
* The single contract that both proposer surfaces (insight capture, hub
|
|
1530
|
+
* auto-curation) implement. Generic over the input shape so each surface can
|
|
1531
|
+
* declare its own evaluation input — a recent-turns buffer for the insight
|
|
1532
|
+
* surface, a filesystem snapshot for the hub surface.
|
|
1533
|
+
*
|
|
1534
|
+
* `evaluate()` is intentionally pure: it inspects its input, optionally
|
|
1535
|
+
* consults the LLM, and returns either a {@link Proposal} or `null`. Side
|
|
1536
|
+
* effects (writing the captured insight, recording the decline) are
|
|
1537
|
+
* captured as thunks inside the returned Proposal and only run after the
|
|
1538
|
+
* user decides.
|
|
1539
|
+
*
|
|
1540
|
+
* A `null` return means "no proposal at this time" — the proposer's
|
|
1541
|
+
* thresholds were not met, the LLM declined, the input fingerprint was
|
|
1542
|
+
* already on the decline list, or nothing meaningful changed since the last
|
|
1543
|
+
* evaluation. The caller must not treat `null` as an error.
|
|
1544
|
+
*/
|
|
1545
|
+
interface Proposer<Input, P extends Proposal = Proposal> {
|
|
1546
|
+
readonly kind: string;
|
|
1547
|
+
evaluate(input: Input, ctx: ProposerContext): Promise<P | null>;
|
|
1548
|
+
}
|
|
1549
|
+
/**
|
|
1550
|
+
* Shared evaluation context handed to every proposer call.
|
|
1551
|
+
*
|
|
1552
|
+
* - `cwd` is the instance's repository root — proposers resolve `data/`
|
|
1553
|
+
* paths relative to it. Absolute paths never leak into proposals (the
|
|
1554
|
+
* proposal's action carries data-relative paths).
|
|
1555
|
+
* - `declinedFingerprints` is pre-loaded by the orchestrator so the
|
|
1556
|
+
* proposer can do its decline check without touching the filesystem
|
|
1557
|
+
* during evaluation.
|
|
1558
|
+
* - `llm` is the host-supplied judge. Injected so the proposer stays
|
|
1559
|
+
* host-agnostic.
|
|
1560
|
+
* - `now` is injected (rather than `new Date()` inside the proposer) so
|
|
1561
|
+
* verify scenarios can pin time for deterministic fingerprints.
|
|
1562
|
+
*/
|
|
1563
|
+
interface ProposerContext {
|
|
1564
|
+
readonly cwd: string;
|
|
1565
|
+
readonly declinedFingerprints: ReadonlySet<string>;
|
|
1566
|
+
readonly llm: LLMJudge;
|
|
1567
|
+
readonly now: Date;
|
|
1568
|
+
}
|
|
1569
|
+
/**
|
|
1570
|
+
* A single proposal handed to the host for the user to accept or decline.
|
|
1571
|
+
*
|
|
1572
|
+
* The proposal carries enough preview content that the user can decide
|
|
1573
|
+
* without further round-trips. `onAccept` / `onDecline` are thunks — the
|
|
1574
|
+
* side-effect logic was captured at evaluation time but does not run until
|
|
1575
|
+
* the user decides. This keeps `Proposer.evaluate()` pure.
|
|
1576
|
+
*
|
|
1577
|
+
* `fingerprint` identifies the proposal for decline-tracking. It must
|
|
1578
|
+
* include the chosen `action.kind` and target path so the same topic can
|
|
1579
|
+
* re-surface with a different placement decision if the LLM's call shifts
|
|
1580
|
+
* (e.g. user declined an `append-section` to file X, but a later evaluation
|
|
1581
|
+
* proposes `create-file` in a sibling folder — different fingerprint,
|
|
1582
|
+
* eligible to surface).
|
|
1583
|
+
*/
|
|
1584
|
+
interface Proposal {
|
|
1585
|
+
readonly kind: string;
|
|
1586
|
+
readonly fingerprint: string;
|
|
1587
|
+
readonly action: ProposalAction;
|
|
1588
|
+
readonly preview: string;
|
|
1589
|
+
readonly rationale: string;
|
|
1590
|
+
readonly sourceRefs: readonly string[];
|
|
1591
|
+
readonly onAccept: () => Promise<AcceptResult>;
|
|
1592
|
+
readonly onDecline: () => Promise<void>;
|
|
1593
|
+
}
|
|
1594
|
+
/**
|
|
1595
|
+
* Placement action chosen by the proposer. Four kinds cover the full
|
|
1596
|
+
* lifecycle of topic-aware capture; the proposer biases toward the *least*
|
|
1597
|
+
* structural change consistent with the captured content.
|
|
1598
|
+
*
|
|
1599
|
+
* Preference order (extend before create):
|
|
1600
|
+
* `append-section` > `create-file` > `create-folder` > `update-file`
|
|
1601
|
+
*
|
|
1602
|
+
* - `create-folder` — topic is new; create the folder and seed the first
|
|
1603
|
+
* file inside it.
|
|
1604
|
+
* - `create-file` — topic folder exists; create a new sibling file. The
|
|
1605
|
+
* proposer chose this because the content does not belong in any
|
|
1606
|
+
* existing file in the folder.
|
|
1607
|
+
* - `append-section` — an existing file is the right home; append a new
|
|
1608
|
+
* `## <sectionHeader>` section to it. Use this for an ongoing topic
|
|
1609
|
+
* where the new content is an addition, not a rewrite.
|
|
1610
|
+
* - `update-file` — an existing file needs in-place revision (status
|
|
1611
|
+
* update, factual correction, summary refresh). Rare; prefer
|
|
1612
|
+
* `append-section` when the new content is additive.
|
|
1613
|
+
*
|
|
1614
|
+
* All paths are relative to `data/` so proposals never embed absolute paths
|
|
1615
|
+
* (proposals can be serialized into `_proactive-curator/` and re-evaluated
|
|
1616
|
+
* later without being tied to a particular workspace location).
|
|
1617
|
+
*/
|
|
1618
|
+
type ProposalAction = {
|
|
1619
|
+
readonly kind: "create-folder";
|
|
1620
|
+
readonly folderPath: string;
|
|
1621
|
+
readonly filename: string;
|
|
1622
|
+
readonly body: string;
|
|
1623
|
+
} | {
|
|
1624
|
+
readonly kind: "create-file";
|
|
1625
|
+
readonly folderPath: string;
|
|
1626
|
+
readonly filename: string;
|
|
1627
|
+
readonly body: string;
|
|
1628
|
+
} | {
|
|
1629
|
+
readonly kind: "append-section";
|
|
1630
|
+
readonly filePath: string;
|
|
1631
|
+
readonly sectionHeader: string;
|
|
1632
|
+
readonly body: string;
|
|
1633
|
+
} | {
|
|
1634
|
+
readonly kind: "update-file";
|
|
1635
|
+
readonly filePath: string;
|
|
1636
|
+
readonly body: string;
|
|
1637
|
+
readonly reason: string;
|
|
1638
|
+
};
|
|
1639
|
+
/**
|
|
1640
|
+
* Result returned by {@link Proposal.onAccept}. The host uses this to
|
|
1641
|
+
* confirm the write succeeded and to surface the next-action hint to the
|
|
1642
|
+
* user in plain language.
|
|
1643
|
+
*/
|
|
1644
|
+
interface AcceptResult {
|
|
1645
|
+
readonly writtenPath: string;
|
|
1646
|
+
readonly actionApplied: ProposalAction["kind"];
|
|
1647
|
+
readonly nextActionHint?: string;
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
/**
|
|
1651
|
+
* Input to {@link computeFingerprint}. Two shapes — one per surface — share
|
|
1652
|
+
* a single function so the decline store can carry both kinds of
|
|
1653
|
+
* fingerprints in the same lookup set.
|
|
1654
|
+
*
|
|
1655
|
+
* The action-aware fingerprint is the load-bearing design choice: declining
|
|
1656
|
+
* an `append-section` proposal for topic X does *not* prevent a later
|
|
1657
|
+
* `create-file` proposal for the same topic from surfacing. The LLM's
|
|
1658
|
+
* placement decision is part of the fingerprint, so a shifted decision is
|
|
1659
|
+
* a new proposal.
|
|
1660
|
+
*/
|
|
1661
|
+
type FingerprintInput = {
|
|
1662
|
+
readonly kind: "capture-insight";
|
|
1663
|
+
readonly turnIds: readonly string[];
|
|
1664
|
+
readonly topic: string;
|
|
1665
|
+
readonly actionKind: ProposalAction["kind"];
|
|
1666
|
+
readonly targetPath: string;
|
|
1667
|
+
} | {
|
|
1668
|
+
readonly kind: "create-hub";
|
|
1669
|
+
readonly topic: string;
|
|
1670
|
+
readonly sourceDocs: readonly string[];
|
|
1671
|
+
readonly actionKind: ProposalAction["kind"];
|
|
1672
|
+
readonly targetPath: string;
|
|
1673
|
+
};
|
|
1674
|
+
/**
|
|
1675
|
+
* Compute a stable 16-hex-char fingerprint for a proposal. Stable means:
|
|
1676
|
+
* identical logical input — regardless of source ordering of array fields or
|
|
1677
|
+
* path separator style — produces an identical fingerprint, so the decline
|
|
1678
|
+
* lookup is reliable across machines (work / home) and across path-separator
|
|
1679
|
+
* regimes (Windows backslash vs POSIX slash).
|
|
1680
|
+
*
|
|
1681
|
+
* SHA-256 truncated to 16 hex chars (64 bits) is enough collision resistance
|
|
1682
|
+
* for a per-instance decline set; the full hash adds storage with no
|
|
1683
|
+
* practical benefit at this scale.
|
|
1684
|
+
*/
|
|
1685
|
+
declare function computeFingerprint(input: FingerprintInput): string;
|
|
1686
|
+
|
|
1687
|
+
type ProposalKind = "capture-insight" | "create-hub";
|
|
1688
|
+
interface DeclinedEntry {
|
|
1689
|
+
/** ISO-8601 timestamp of when the user declined. */
|
|
1690
|
+
readonly declinedAt: string;
|
|
1691
|
+
/** Topic slug at decline time (for the audit trail; not part of the fingerprint). */
|
|
1692
|
+
readonly topic: string;
|
|
1693
|
+
/** ISO-8601 timestamp after which this entry is eligible for re-evaluation. */
|
|
1694
|
+
readonly expiresAt: string;
|
|
1695
|
+
/** The action the user declined — `create-file`, `append-section`, etc. */
|
|
1696
|
+
readonly actionKind: ProposalAction["kind"];
|
|
1697
|
+
/** Target path the declined action would have written/touched (data-relative). */
|
|
1698
|
+
readonly targetPath: string;
|
|
1699
|
+
/** Hub proposals only — the source-doc cluster that triggered this proposal. */
|
|
1700
|
+
readonly sourceDocs?: readonly string[];
|
|
1701
|
+
}
|
|
1702
|
+
/**
|
|
1703
|
+
* Load the active (un-expired) declined fingerprints. The returned set is
|
|
1704
|
+
* what {@link ProposerContext.declinedFingerprints} carries during
|
|
1705
|
+
* `evaluate()` so the proposer can do its decline check without filesystem
|
|
1706
|
+
* access at evaluation time.
|
|
1707
|
+
*
|
|
1708
|
+
* Missing or corrupt store files return an empty set rather than throwing —
|
|
1709
|
+
* a first-run instance simply has nothing declined.
|
|
1710
|
+
*/
|
|
1711
|
+
declare function loadDeclinedFingerprints(cwd: string, now: Date): Promise<ReadonlySet<string>>;
|
|
1712
|
+
/**
|
|
1713
|
+
* Persist a decline. Purges expired entries from disk in the same write so
|
|
1714
|
+
* the store does not grow unbounded.
|
|
1715
|
+
*/
|
|
1716
|
+
declare function recordDecline(cwd: string, args: {
|
|
1717
|
+
readonly kind: ProposalKind;
|
|
1718
|
+
readonly fingerprint: string;
|
|
1719
|
+
readonly topic: string;
|
|
1720
|
+
readonly actionKind: ProposalAction["kind"];
|
|
1721
|
+
readonly targetPath: string;
|
|
1722
|
+
readonly sourceDocs?: readonly string[];
|
|
1723
|
+
readonly now: Date;
|
|
1724
|
+
readonly expiryDays?: number;
|
|
1725
|
+
}): Promise<void>;
|
|
1726
|
+
/**
|
|
1727
|
+
* Append an acceptance record to the audit trail. Newline-delimited JSON so
|
|
1728
|
+
* the file is grep-friendly and tail-friendly without a parser.
|
|
1729
|
+
*/
|
|
1730
|
+
declare function recordAcceptance(cwd: string, args: {
|
|
1731
|
+
readonly kind: ProposalKind;
|
|
1732
|
+
readonly fingerprint: string;
|
|
1733
|
+
readonly topic: string;
|
|
1734
|
+
readonly actionKind: ProposalAction["kind"];
|
|
1735
|
+
readonly writtenPath: string;
|
|
1736
|
+
readonly now: Date;
|
|
1737
|
+
}): Promise<void>;
|
|
1738
|
+
/**
|
|
1739
|
+
* Clear declined entries. Optional `kind` argument scopes the reset to
|
|
1740
|
+
* just one surface. Called by `/curate --reset-declined` (sub-phase c).
|
|
1741
|
+
* Missing store file is a no-op — nothing to reset.
|
|
1742
|
+
*/
|
|
1743
|
+
declare function resetDeclined(cwd: string, kind?: ProposalKind): Promise<void>;
|
|
1744
|
+
|
|
1745
|
+
interface InsightProposerOptions {
|
|
1746
|
+
/** Below this token count the proposer never asks the LLM. */
|
|
1747
|
+
readonly minTokensAccumulated: number;
|
|
1748
|
+
/** Below this turn count the proposer never asks the LLM. */
|
|
1749
|
+
readonly minTurnsBeforeFirstCheck: number;
|
|
1750
|
+
/**
|
|
1751
|
+
* Cap on how many topic folders to surface to the placement LLM call.
|
|
1752
|
+
* Large instance trees will exceed any practical LLM context budget;
|
|
1753
|
+
* truncation keeps the call tractable. Default 100.
|
|
1754
|
+
*/
|
|
1755
|
+
readonly maxTreeEntries?: number;
|
|
1756
|
+
/** Days after which a decline becomes eligible for re-evaluation. */
|
|
1757
|
+
readonly declineExpiryDays?: number;
|
|
1758
|
+
}
|
|
1759
|
+
interface TurnRecord {
|
|
1760
|
+
readonly turnId: string;
|
|
1761
|
+
readonly role: "user" | "assistant" | "system";
|
|
1762
|
+
readonly content: string;
|
|
1763
|
+
}
|
|
1764
|
+
interface InsightInput {
|
|
1765
|
+
readonly recentTurns: readonly TurnRecord[];
|
|
1766
|
+
readonly accumulatedTokens: number;
|
|
1767
|
+
}
|
|
1768
|
+
interface InsightProposal extends Proposal {
|
|
1769
|
+
readonly kind: "capture-insight";
|
|
1770
|
+
}
|
|
1771
|
+
interface TopicFile {
|
|
1772
|
+
readonly path: string;
|
|
1773
|
+
readonly filename: string;
|
|
1774
|
+
readonly frontmatterTopic?: string;
|
|
1775
|
+
readonly tags?: readonly string[];
|
|
1776
|
+
}
|
|
1777
|
+
interface TopicFolderSnapshot {
|
|
1778
|
+
readonly path: string;
|
|
1779
|
+
readonly files: readonly TopicFile[];
|
|
1780
|
+
}
|
|
1781
|
+
interface TopicTreeSnapshot {
|
|
1782
|
+
readonly folders: readonly TopicFolderSnapshot[];
|
|
1783
|
+
/** True when the scan was truncated by `maxTreeEntries`. */
|
|
1784
|
+
readonly truncated: boolean;
|
|
1785
|
+
}
|
|
1786
|
+
declare class InsightProposer implements Proposer<InsightInput, InsightProposal> {
|
|
1787
|
+
private readonly options;
|
|
1788
|
+
readonly kind = "capture-insight";
|
|
1789
|
+
constructor(options: InsightProposerOptions);
|
|
1790
|
+
evaluate(input: InsightInput, ctx: ProposerContext): Promise<InsightProposal | null>;
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
interface HubProposerOptions {
|
|
1794
|
+
/** Threshold for triggering propose-veto LLM gate. Below this, no proposal. Default 3. */
|
|
1795
|
+
readonly weakSignalAt: number;
|
|
1796
|
+
/** Threshold for switching to suppress-veto LLM gate. Default 5. */
|
|
1797
|
+
readonly strongSignalAt: number;
|
|
1798
|
+
/**
|
|
1799
|
+
* Content categories (data-relative) to scan for topic clusters. Default
|
|
1800
|
+
* `worklog`, `decision-log`, `runbooks`. Hub itself, `_memory/`, and the
|
|
1801
|
+
* curator's own `_proactive-curator/` are never scanned (a hub-of-hubs
|
|
1802
|
+
* is out of scope; memory is not topical content).
|
|
1803
|
+
*/
|
|
1804
|
+
readonly scanCategories?: readonly string[];
|
|
1805
|
+
/** Decline expiry in days. Default 30. */
|
|
1806
|
+
readonly declineExpiryDays?: number;
|
|
1807
|
+
}
|
|
1808
|
+
interface HubInput {
|
|
1809
|
+
/**
|
|
1810
|
+
* Hub evaluation has no per-call input beyond context — the filesystem is
|
|
1811
|
+
* the input. This shape is kept for future extension (e.g. a hint to scan
|
|
1812
|
+
* only a specific category) without breaking the `Proposer<Input, P>`
|
|
1813
|
+
* contract.
|
|
1814
|
+
*/
|
|
1815
|
+
readonly hint?: {
|
|
1816
|
+
readonly onlyCategories?: readonly string[];
|
|
1817
|
+
};
|
|
1818
|
+
}
|
|
1819
|
+
interface HubProposal extends Proposal {
|
|
1820
|
+
readonly kind: "create-hub";
|
|
1821
|
+
}
|
|
1822
|
+
declare class HubProposer implements Proposer<HubInput, HubProposal> {
|
|
1823
|
+
private readonly options;
|
|
1824
|
+
readonly kind = "create-hub";
|
|
1825
|
+
constructor(options: HubProposerOptions);
|
|
1826
|
+
evaluate(input: HubInput, ctx: ProposerContext): Promise<HubProposal | null>;
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
/**
|
|
1830
|
+
* Sliding buffer of recent conversation turns. The host pushes each turn as
|
|
1831
|
+
* it occurs; the buffer caps at `maxTurns` and discards the oldest entries
|
|
1832
|
+
* past the cap. Token count is estimated cheaply so the host can poll
|
|
1833
|
+
* `tokenCount()` to decide when InsightProposer's threshold has been met.
|
|
1834
|
+
*
|
|
1835
|
+
* Default estimator is `chars / 4` — a rough baseline that overshoots for
|
|
1836
|
+
* CJK content and undershoots for ASCII code. Hosts that have a real
|
|
1837
|
+
* tokenizer can inject one via the `estimator` option.
|
|
1838
|
+
*
|
|
1839
|
+
* The buffer is process-local and not persisted — a new session starts
|
|
1840
|
+
* with an empty buffer, which is the intended UX (proactive proposals are
|
|
1841
|
+
* about *this conversation*, not a re-ingestion of past sessions; that is
|
|
1842
|
+
* what `memory-extended/consolidate` is for).
|
|
1843
|
+
*/
|
|
1844
|
+
declare class TurnBuffer {
|
|
1845
|
+
private readonly turns;
|
|
1846
|
+
private readonly maxTurns;
|
|
1847
|
+
private readonly estimator;
|
|
1848
|
+
constructor(options?: {
|
|
1849
|
+
readonly maxTurns?: number;
|
|
1850
|
+
readonly estimator?: (turn: TurnRecord) => number;
|
|
1851
|
+
});
|
|
1852
|
+
/** Append a turn, evicting the oldest entry if the buffer is full. */
|
|
1853
|
+
add(turn: TurnRecord): void;
|
|
1854
|
+
/** Return the most recent `n` turns (or fewer if the buffer has fewer). */
|
|
1855
|
+
recent(n: number): readonly TurnRecord[];
|
|
1856
|
+
/** Number of turns currently buffered. */
|
|
1857
|
+
get length(): number;
|
|
1858
|
+
/** Estimated total token count over the entire buffer. */
|
|
1859
|
+
tokenCount(): number;
|
|
1860
|
+
/** Reset the buffer — typically called at session-end. */
|
|
1861
|
+
clear(): void;
|
|
1862
|
+
}
|
|
1863
|
+
/**
|
|
1864
|
+
* Backpressure controller for ambient mid-session triggers. When the user
|
|
1865
|
+
* declines several proposals in a row, the controller flips into
|
|
1866
|
+
* `active=true` and the host should pause ambient evaluations for the
|
|
1867
|
+
* remainder of the session. Manual `/curate` invocations are still
|
|
1868
|
+
* allowed — the controller exists only to suppress unsolicited prompts.
|
|
1869
|
+
*
|
|
1870
|
+
* Reset semantics:
|
|
1871
|
+
* - `recordAccept()` — any acceptance clears the streak.
|
|
1872
|
+
* - `recordIgnored()` — proposals the host surfaced but the user did not
|
|
1873
|
+
* explicitly accept/decline do not count toward the streak.
|
|
1874
|
+
* - `reset()` — explicit reset, used by `/curate` (the user re-engaging
|
|
1875
|
+
* after backpressure kicked in).
|
|
1876
|
+
*/
|
|
1877
|
+
declare class AmbientBackpressure {
|
|
1878
|
+
private declineStreak;
|
|
1879
|
+
private readonly maxStreak;
|
|
1880
|
+
constructor(options?: {
|
|
1881
|
+
readonly maxStreak?: number;
|
|
1882
|
+
});
|
|
1883
|
+
/** Record a user decline. Counts toward backpressure. */
|
|
1884
|
+
recordDecline(): void;
|
|
1885
|
+
/** Record a user acceptance. Clears the streak. */
|
|
1886
|
+
recordAccept(): void;
|
|
1887
|
+
/** Explicit reset (e.g. user runs `/curate` after backpressure activated). */
|
|
1888
|
+
reset(): void;
|
|
1889
|
+
/** True when the streak has reached the maximum and ambient should pause. */
|
|
1890
|
+
isActive(): boolean;
|
|
1891
|
+
/** Current decline streak — exposed for diagnostics. */
|
|
1892
|
+
get streak(): number;
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
/**
|
|
1896
|
+
* Minimal shape of a recall hit the ambient recaller consumes.
|
|
1897
|
+
*
|
|
1898
|
+
* Defined locally — `proactive-curator` does not depend on
|
|
1899
|
+
* `@vortex-os/memory-extended`. The host injects a {@link RecallFn} whose
|
|
1900
|
+
* result structurally satisfies this shape (memory-extended's `RecallHit`
|
|
1901
|
+
* carries all of these fields plus a few extra, so the wiring is
|
|
1902
|
+
* zero-friction). This mirrors how `LLMJudge` keeps the host's LLM facility
|
|
1903
|
+
* behind an injected adapter: the recall *engine* lives in another package;
|
|
1904
|
+
* the *decision of when to surface a hit in conversation* lives here.
|
|
1905
|
+
*/
|
|
1906
|
+
interface AmbientRecallHit {
|
|
1907
|
+
readonly id: string;
|
|
1908
|
+
/** Cosine similarity to the query (1 = identical direction). */
|
|
1909
|
+
readonly score: number;
|
|
1910
|
+
readonly name: string;
|
|
1911
|
+
/** Short body excerpt for the host to weave into prose. */
|
|
1912
|
+
readonly excerpt: string;
|
|
1913
|
+
/** Corpus the hit came from (e.g. "memory", "session-archive"). */
|
|
1914
|
+
readonly source: string;
|
|
1915
|
+
readonly type: string;
|
|
1916
|
+
readonly updated: string | null;
|
|
1917
|
+
readonly tags: readonly string[];
|
|
1918
|
+
}
|
|
1919
|
+
/**
|
|
1920
|
+
* Host-injected recall function. The host wires its `memory-extended` recall
|
|
1921
|
+
* engine (sqlite + vector + embedder + session chunks) behind this single
|
|
1922
|
+
* call so the recaller stays engine-agnostic and `proactive-curator` stays
|
|
1923
|
+
* free of any `memory-extended` dependency.
|
|
1924
|
+
*/
|
|
1925
|
+
interface RecallFn {
|
|
1926
|
+
(query: string, opts?: {
|
|
1927
|
+
readonly k?: number;
|
|
1928
|
+
}): Promise<{
|
|
1929
|
+
readonly hits: readonly AmbientRecallHit[];
|
|
1930
|
+
}>;
|
|
1931
|
+
}
|
|
1932
|
+
/** One surfaced suggestion — a recall hit that passed the ambient gate. */
|
|
1933
|
+
interface RecallSuggestion {
|
|
1934
|
+
readonly hit: AmbientRecallHit;
|
|
1935
|
+
/** Convenience copy of `hit.score` (the gate's ranking key). */
|
|
1936
|
+
readonly score: number;
|
|
1937
|
+
}
|
|
1938
|
+
/**
|
|
1939
|
+
* Result of one {@link AmbientRecaller.consider} call. Carries the surviving
|
|
1940
|
+
* suggestion(s) plus diagnostics (how many hits the engine returned, how many
|
|
1941
|
+
* each gate dropped) so an instance can tune `minScore` against real
|
|
1942
|
+
* conversations rather than guessing.
|
|
1943
|
+
*/
|
|
1944
|
+
interface AmbientRecallResult {
|
|
1945
|
+
/** Hits that passed every gate, best-first, capped at `maxSuggestions`. */
|
|
1946
|
+
readonly suggestions: readonly RecallSuggestion[];
|
|
1947
|
+
/** True when backpressure is active — the recaller stayed silent. */
|
|
1948
|
+
readonly suppressed: boolean;
|
|
1949
|
+
/** The query actually used (derived or explicit); null if none/empty. */
|
|
1950
|
+
readonly query: string | null;
|
|
1951
|
+
/** Hits returned by the engine before filtering (transparency for tuning). */
|
|
1952
|
+
readonly considered: number;
|
|
1953
|
+
/** Hits dropped for scoring below `minScore`. */
|
|
1954
|
+
readonly belowThreshold: number;
|
|
1955
|
+
/** Hits dropped as already surfaced earlier this session. */
|
|
1956
|
+
readonly deduped: number;
|
|
1957
|
+
}
|
|
1958
|
+
interface AmbientRecallerOptions {
|
|
1959
|
+
readonly recall: RecallFn;
|
|
1960
|
+
/**
|
|
1961
|
+
* Minimum cosine score for a hit to be worth surfacing unprompted. The
|
|
1962
|
+
* single most important tuning knob — too low surfaces noise (naggy), too
|
|
1963
|
+
* high never fires. The right value depends on the embedder; calibrate per
|
|
1964
|
+
* instance against real conversations (the result diagnostics help). The
|
|
1965
|
+
* default 0.5 is a conservative starting point for the bundled e5-small
|
|
1966
|
+
* embedder.
|
|
1967
|
+
*/
|
|
1968
|
+
readonly minScore?: number;
|
|
1969
|
+
/** Max suggestions per `consider()`. Default 1 — ambient is one nudge, not a list. */
|
|
1970
|
+
readonly maxSuggestions?: number;
|
|
1971
|
+
/** Below this query length, do not even call the engine. Default 12. */
|
|
1972
|
+
readonly minQueryChars?: number;
|
|
1973
|
+
/**
|
|
1974
|
+
* How many candidates to ask the engine for. Defaults to
|
|
1975
|
+
* `maxSuggestions + 4` so dedup/threshold filtering has headroom.
|
|
1976
|
+
*/
|
|
1977
|
+
readonly candidateK?: number;
|
|
1978
|
+
/** Shared backpressure controller. Omit to use a fresh one. */
|
|
1979
|
+
readonly backpressure?: AmbientBackpressure;
|
|
1980
|
+
}
|
|
1981
|
+
/**
|
|
1982
|
+
* Decides *whether* and *which* past memory to surface in the flow of a live
|
|
1983
|
+
* conversation — the ambient counterpart to the explicit `/recall` command
|
|
1984
|
+
* (memory-extended-design.md deferred this "notice and offer" reliability to
|
|
1985
|
+
* a proactive-curator-connected follow-up; this is it).
|
|
1986
|
+
*
|
|
1987
|
+
* It does not embed, search, or format anything itself. It takes the recent
|
|
1988
|
+
* conversation, derives a query, asks the injected recall engine, and applies
|
|
1989
|
+
* three gates so the surface stays useful and non-naggy:
|
|
1990
|
+
*
|
|
1991
|
+
* 1. **Backpressure** — after N consecutive declines (see
|
|
1992
|
+
* {@link AmbientBackpressure}) it goes silent for the rest of the session.
|
|
1993
|
+
* 2. **Score threshold** — only confident hits surface.
|
|
1994
|
+
* 3. **Session dedup** — a hit already offered this session is not re-offered.
|
|
1995
|
+
*
|
|
1996
|
+
* Stateful by design (the dedup set + backpressure streak live across turns),
|
|
1997
|
+
* so a host keeps ONE instance alive for the session — a long-lived runtime
|
|
1998
|
+
* or the opt-in embedder daemon. A stateless per-call host (a plain slash
|
|
1999
|
+
* command) cannot carry the gate state; that is exactly why the default
|
|
2000
|
+
* Claude Code surface is agent-guidance, not a command (see the design docs).
|
|
2001
|
+
*/
|
|
2002
|
+
declare class AmbientRecaller {
|
|
2003
|
+
private readonly recall;
|
|
2004
|
+
private readonly minScore;
|
|
2005
|
+
private readonly maxSuggestions;
|
|
2006
|
+
private readonly minQueryChars;
|
|
2007
|
+
private readonly candidateK;
|
|
2008
|
+
private readonly backpressure;
|
|
2009
|
+
private readonly surfaced;
|
|
2010
|
+
constructor(options: AmbientRecallerOptions);
|
|
2011
|
+
/**
|
|
2012
|
+
* Consider surfacing a memory given the current conversation. Pass an
|
|
2013
|
+
* explicit `query` (the host knows what the user is referencing) or recent
|
|
2014
|
+
* `turns` to derive one from. Returns the gated suggestions plus diagnostics.
|
|
2015
|
+
*
|
|
2016
|
+
* Does not catch errors from the injected engine — a failing embedder
|
|
2017
|
+
* should surface to the host (which decides whether to swallow it for the
|
|
2018
|
+
* turn), not be masked here.
|
|
2019
|
+
*/
|
|
2020
|
+
consider(input: {
|
|
2021
|
+
readonly query?: string;
|
|
2022
|
+
readonly turns?: readonly TurnRecord[];
|
|
2023
|
+
}): Promise<AmbientRecallResult>;
|
|
2024
|
+
/** The user engaged with a surfaced suggestion — clears the decline streak. */
|
|
2025
|
+
recordAccept(): void;
|
|
2026
|
+
/** The user dismissed a surfaced suggestion — counts toward backpressure. */
|
|
2027
|
+
recordDecline(): void;
|
|
2028
|
+
/** True when backpressure has silenced ambient surfacing for the session. */
|
|
2029
|
+
get suppressed(): boolean;
|
|
2030
|
+
/**
|
|
2031
|
+
* Re-engage after backpressure (the user explicitly asks for suggestions
|
|
2032
|
+
* again, e.g. via `/curate`). Clears the decline streak AND the dedup set
|
|
2033
|
+
* so previously surfaced hits can be offered again.
|
|
2034
|
+
*/
|
|
2035
|
+
reset(): void;
|
|
2036
|
+
}
|
|
2037
|
+
/**
|
|
2038
|
+
* Build a recall query from recent turns. Uses the most recent *user* turn —
|
|
2039
|
+
* in ambient use the trigger is the user's latest utterance ("didn't I do
|
|
2040
|
+
* this before?"), and that utterance is the query. Falls back to the most
|
|
2041
|
+
* recent turn of any role if the window has no user turn.
|
|
2042
|
+
*/
|
|
2043
|
+
declare function deriveQueryFromTurns(turns: readonly TurnRecord[]): string;
|
|
2044
|
+
|
|
2045
|
+
/**
|
|
2046
|
+
* Shared building blocks for host `LLMJudge` adapters that work by injecting a
|
|
2047
|
+
* single-shot "prompt in, string out" call.
|
|
2048
|
+
*
|
|
2049
|
+
* Every first-party host (Claude Code, Codex, Gemini, Claude Desktop) reaches
|
|
2050
|
+
* its LLM differently — a sub-agent tool call, an inline completion, an MCP
|
|
2051
|
+
* call, a desktop surface — but that difference is entirely in the *raw
|
|
2052
|
+
* invoker* the host injects. The work *around* the call is identical: frame
|
|
2053
|
+
* the proposer's prompt so the model returns only the requested shape, then
|
|
2054
|
+
* parse the raw response tolerantly. That shared work lives here so each host
|
|
2055
|
+
* adapter is a thin shell over one injected function (the design's
|
|
2056
|
+
* "subsequent hosts inherit the pattern").
|
|
2057
|
+
*/
|
|
2058
|
+
/** A host's single-shot LLM call: a prompt in, a raw string out. */
|
|
2059
|
+
interface InjectedInvoker {
|
|
2060
|
+
(input: {
|
|
2061
|
+
readonly prompt: string;
|
|
2062
|
+
}): Promise<string>;
|
|
2063
|
+
}
|
|
2064
|
+
/**
|
|
2065
|
+
* Base error for injected-host LLMJudge adapters. Each host subclass narrows
|
|
2066
|
+
* the `name` (e.g. `ClaudeCodeLLMJudgeError`) so callers can distinguish the
|
|
2067
|
+
* source host while still catching the family with `instanceof LLMJudgeError`.
|
|
2068
|
+
*/
|
|
2069
|
+
declare class LLMJudgeError extends Error {
|
|
2070
|
+
readonly raw?: string | undefined;
|
|
2071
|
+
constructor(message: string, raw?: string | undefined);
|
|
2072
|
+
}
|
|
2073
|
+
/**
|
|
2074
|
+
* Frame a proposer prompt for a single-shot host LLM call. Host-agnostic —
|
|
2075
|
+
* the instruction constrains the response to the expected shape and names no
|
|
2076
|
+
* host facility, so every adapter shares it verbatim.
|
|
2077
|
+
*/
|
|
2078
|
+
declare function frameForJudge(prompt: string, expected: ExpectedShape): string;
|
|
2079
|
+
/**
|
|
2080
|
+
* Parse a raw host response into the expected shape. Strings pass through
|
|
2081
|
+
* trimmed; JSON answers are extracted tolerantly (a leading/trailing ```json
|
|
2082
|
+
* fence, or a sentence wrapped around the object) and `JSON.parse`'d.
|
|
2083
|
+
* Persistent format failure throws via the injected `makeError` factory so
|
|
2084
|
+
* each adapter raises its own typed error rather than the base masking it.
|
|
2085
|
+
*/
|
|
2086
|
+
declare function parseJudgeResponse(raw: string, expected: ExpectedShape, makeError: (message: string, raw?: string) => Error): unknown;
|
|
2087
|
+
/**
|
|
2088
|
+
* Shared base for host adapters built on an injected invoker. The base owns
|
|
2089
|
+
* framing + parsing; a subclass declares only the host id and (optionally)
|
|
2090
|
+
* overrides {@link makeError} to raise a host-named error type.
|
|
2091
|
+
*/
|
|
2092
|
+
declare abstract class InjectedLLMJudge implements LLMJudge {
|
|
2093
|
+
protected readonly invoker: InjectedInvoker;
|
|
2094
|
+
abstract readonly host: string;
|
|
2095
|
+
constructor(invoker: InjectedInvoker);
|
|
2096
|
+
/** Host adapters override to raise a host-named error subclass. */
|
|
2097
|
+
protected makeError(message: string, raw?: string): Error;
|
|
2098
|
+
ask(prompt: string, expected: ExpectedShape): Promise<unknown>;
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
/**
|
|
2102
|
+
* Claude Code host adapter for `LLMJudge`.
|
|
2103
|
+
*
|
|
2104
|
+
* Claude Code's natural surface for a single-shot decision query is a
|
|
2105
|
+
* **sub-agent tool call** — a separate, ephemeral agent invoked by the outer
|
|
2106
|
+
* session with a focused prompt, returning its single answer. The adapter
|
|
2107
|
+
* does not know how to invoke a sub-agent itself (that is Claude Code runtime
|
|
2108
|
+
* territory); the host injects an invoker callback at construction time, and
|
|
2109
|
+
* the shared {@link InjectedLLMJudge} base handles prompt framing + tolerant
|
|
2110
|
+
* response parsing on top of it.
|
|
2111
|
+
*
|
|
2112
|
+
* The invoker callback is intentionally minimal — a single async function
|
|
2113
|
+
* that takes a string and returns a string. Hosts that want to thread
|
|
2114
|
+
* additional metadata (session id, tool budget) can capture them in the
|
|
2115
|
+
* closure when they create the invoker.
|
|
2116
|
+
*/
|
|
2117
|
+
/** Claude Code's sub-agent invoker — a `prompt in, string out` call. */
|
|
2118
|
+
type ClaudeCodeSubAgentInvoker = InjectedInvoker;
|
|
2119
|
+
declare class ClaudeCodeLLMJudgeError extends LLMJudgeError {
|
|
2120
|
+
constructor(message: string, raw?: string);
|
|
2121
|
+
}
|
|
2122
|
+
declare class ClaudeCodeLLMJudge extends InjectedLLMJudge {
|
|
2123
|
+
readonly host = "claude-code";
|
|
2124
|
+
protected makeError(message: string, raw?: string): Error;
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2127
|
+
/**
|
|
2128
|
+
* Codex CLI host adapter for `LLMJudge`.
|
|
2129
|
+
*
|
|
2130
|
+
* Codex's natural surface for a single-shot decision query is an **inline
|
|
2131
|
+
* completion** — the host runs the framed prompt as a one-off completion and
|
|
2132
|
+
* returns the text. As with every adapter, the host injects that call; the
|
|
2133
|
+
* shared base supplies framing + parsing. The only host-specific surface here
|
|
2134
|
+
* is the `host` identifier (`"codex"`, matching the sessionArchive adapter
|
|
2135
|
+
* convention) and the typed error.
|
|
2136
|
+
*/
|
|
2137
|
+
/** Codex's inline-completion invoker — a `prompt in, string out` call. */
|
|
2138
|
+
type CodexCompletionInvoker = InjectedInvoker;
|
|
2139
|
+
declare class CodexLLMJudgeError extends LLMJudgeError {
|
|
2140
|
+
constructor(message: string, raw?: string);
|
|
2141
|
+
}
|
|
2142
|
+
declare class CodexLLMJudge extends InjectedLLMJudge {
|
|
2143
|
+
readonly host = "codex";
|
|
2144
|
+
protected makeError(message: string, raw?: string): Error;
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
/**
|
|
2148
|
+
* Gemini CLI host adapter for `LLMJudge`.
|
|
2149
|
+
*
|
|
2150
|
+
* Gemini's natural surface for a single-shot decision query is an **MCP call**
|
|
2151
|
+
* — the host routes the framed prompt through its model-call tool and returns
|
|
2152
|
+
* the text. The host injects that call; the shared base supplies framing +
|
|
2153
|
+
* parsing. Host-specific surface is the `host` identifier (`"gemini"`,
|
|
2154
|
+
* matching the sessionArchive adapter convention) and the typed error.
|
|
2155
|
+
*/
|
|
2156
|
+
/** Gemini's MCP-call invoker — a `prompt in, string out` call. */
|
|
2157
|
+
type GeminiMcpInvoker = InjectedInvoker;
|
|
2158
|
+
declare class GeminiLLMJudgeError extends LLMJudgeError {
|
|
2159
|
+
constructor(message: string, raw?: string);
|
|
2160
|
+
}
|
|
2161
|
+
declare class GeminiLLMJudge extends InjectedLLMJudge {
|
|
2162
|
+
readonly host = "gemini";
|
|
2163
|
+
protected makeError(message: string, raw?: string): Error;
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
/**
|
|
2167
|
+
* Claude Desktop host adapter for `LLMJudge`.
|
|
2168
|
+
*
|
|
2169
|
+
* Claude Desktop's natural surface for a single-shot decision query is a
|
|
2170
|
+
* **response on its own conversation surface** — the host poses the framed
|
|
2171
|
+
* prompt and returns the model's reply. The host injects that call; the
|
|
2172
|
+
* shared base supplies framing + parsing. Host-specific surface is the `host`
|
|
2173
|
+
* identifier (`"claude-desktop"`, matching the sessionArchive adapter
|
|
2174
|
+
* convention) and the typed error.
|
|
2175
|
+
*/
|
|
2176
|
+
/** Claude Desktop's response invoker — a `prompt in, string out` call. */
|
|
2177
|
+
type ClaudeDesktopInvoker = InjectedInvoker;
|
|
2178
|
+
declare class ClaudeDesktopLLMJudgeError extends LLMJudgeError {
|
|
2179
|
+
constructor(message: string, raw?: string);
|
|
2180
|
+
}
|
|
2181
|
+
declare class ClaudeDesktopLLMJudge extends InjectedLLMJudge {
|
|
2182
|
+
readonly host = "claude-desktop";
|
|
2183
|
+
protected makeError(message: string, raw?: string): Error;
|
|
2184
|
+
}
|
|
2185
|
+
|
|
2186
|
+
//# sourceMappingURL=index.d.ts.map
|
|
2187
|
+
|
|
2188
|
+
type index_d$1_AcceptResult = AcceptResult;
|
|
2189
|
+
type index_d$1_AmbientBackpressure = AmbientBackpressure;
|
|
2190
|
+
declare const index_d$1_AmbientBackpressure: typeof AmbientBackpressure;
|
|
2191
|
+
type index_d$1_AmbientRecallHit = AmbientRecallHit;
|
|
2192
|
+
type index_d$1_AmbientRecallResult = AmbientRecallResult;
|
|
2193
|
+
type index_d$1_AmbientRecaller = AmbientRecaller;
|
|
2194
|
+
declare const index_d$1_AmbientRecaller: typeof AmbientRecaller;
|
|
2195
|
+
type index_d$1_AmbientRecallerOptions = AmbientRecallerOptions;
|
|
2196
|
+
type index_d$1_ClaudeCodeLLMJudge = ClaudeCodeLLMJudge;
|
|
2197
|
+
declare const index_d$1_ClaudeCodeLLMJudge: typeof ClaudeCodeLLMJudge;
|
|
2198
|
+
type index_d$1_ClaudeCodeLLMJudgeError = ClaudeCodeLLMJudgeError;
|
|
2199
|
+
declare const index_d$1_ClaudeCodeLLMJudgeError: typeof ClaudeCodeLLMJudgeError;
|
|
2200
|
+
type index_d$1_ClaudeCodeSubAgentInvoker = ClaudeCodeSubAgentInvoker;
|
|
2201
|
+
type index_d$1_ClaudeDesktopInvoker = ClaudeDesktopInvoker;
|
|
2202
|
+
type index_d$1_ClaudeDesktopLLMJudge = ClaudeDesktopLLMJudge;
|
|
2203
|
+
declare const index_d$1_ClaudeDesktopLLMJudge: typeof ClaudeDesktopLLMJudge;
|
|
2204
|
+
type index_d$1_ClaudeDesktopLLMJudgeError = ClaudeDesktopLLMJudgeError;
|
|
2205
|
+
declare const index_d$1_ClaudeDesktopLLMJudgeError: typeof ClaudeDesktopLLMJudgeError;
|
|
2206
|
+
type index_d$1_CodexCompletionInvoker = CodexCompletionInvoker;
|
|
2207
|
+
type index_d$1_CodexLLMJudge = CodexLLMJudge;
|
|
2208
|
+
declare const index_d$1_CodexLLMJudge: typeof CodexLLMJudge;
|
|
2209
|
+
type index_d$1_CodexLLMJudgeError = CodexLLMJudgeError;
|
|
2210
|
+
declare const index_d$1_CodexLLMJudgeError: typeof CodexLLMJudgeError;
|
|
2211
|
+
type index_d$1_DeclinedEntry = DeclinedEntry;
|
|
2212
|
+
type index_d$1_ExpectedShape = ExpectedShape;
|
|
2213
|
+
type index_d$1_FingerprintInput = FingerprintInput;
|
|
2214
|
+
type index_d$1_GeminiLLMJudge = GeminiLLMJudge;
|
|
2215
|
+
declare const index_d$1_GeminiLLMJudge: typeof GeminiLLMJudge;
|
|
2216
|
+
type index_d$1_GeminiLLMJudgeError = GeminiLLMJudgeError;
|
|
2217
|
+
declare const index_d$1_GeminiLLMJudgeError: typeof GeminiLLMJudgeError;
|
|
2218
|
+
type index_d$1_GeminiMcpInvoker = GeminiMcpInvoker;
|
|
2219
|
+
type index_d$1_HubInput = HubInput;
|
|
2220
|
+
type index_d$1_HubProposal = HubProposal;
|
|
2221
|
+
type index_d$1_HubProposer = HubProposer;
|
|
2222
|
+
declare const index_d$1_HubProposer: typeof HubProposer;
|
|
2223
|
+
type index_d$1_HubProposerOptions = HubProposerOptions;
|
|
2224
|
+
type index_d$1_InjectedInvoker = InjectedInvoker;
|
|
2225
|
+
type index_d$1_InjectedLLMJudge = InjectedLLMJudge;
|
|
2226
|
+
declare const index_d$1_InjectedLLMJudge: typeof InjectedLLMJudge;
|
|
2227
|
+
type index_d$1_InsightInput = InsightInput;
|
|
2228
|
+
type index_d$1_InsightProposal = InsightProposal;
|
|
2229
|
+
type index_d$1_InsightProposer = InsightProposer;
|
|
2230
|
+
declare const index_d$1_InsightProposer: typeof InsightProposer;
|
|
2231
|
+
type index_d$1_InsightProposerOptions = InsightProposerOptions;
|
|
2232
|
+
type index_d$1_LLMJudge = LLMJudge;
|
|
2233
|
+
type index_d$1_LLMJudgeError = LLMJudgeError;
|
|
2234
|
+
declare const index_d$1_LLMJudgeError: typeof LLMJudgeError;
|
|
2235
|
+
type index_d$1_Proposal = Proposal;
|
|
2236
|
+
type index_d$1_ProposalAction = ProposalAction;
|
|
2237
|
+
type index_d$1_ProposalKind = ProposalKind;
|
|
2238
|
+
type index_d$1_Proposer<Input, P extends Proposal = Proposal> = Proposer<Input, P>;
|
|
2239
|
+
type index_d$1_ProposerContext = ProposerContext;
|
|
2240
|
+
type index_d$1_RecallFn = RecallFn;
|
|
2241
|
+
type index_d$1_RecallSuggestion = RecallSuggestion;
|
|
2242
|
+
type index_d$1_TopicTreeSnapshot = TopicTreeSnapshot;
|
|
2243
|
+
type index_d$1_TurnBuffer = TurnBuffer;
|
|
2244
|
+
declare const index_d$1_TurnBuffer: typeof TurnBuffer;
|
|
2245
|
+
type index_d$1_TurnRecord = TurnRecord;
|
|
2246
|
+
declare const index_d$1_computeFingerprint: typeof computeFingerprint;
|
|
2247
|
+
declare const index_d$1_deriveQueryFromTurns: typeof deriveQueryFromTurns;
|
|
2248
|
+
declare const index_d$1_frameForJudge: typeof frameForJudge;
|
|
2249
|
+
declare const index_d$1_loadDeclinedFingerprints: typeof loadDeclinedFingerprints;
|
|
2250
|
+
declare const index_d$1_parseJudgeResponse: typeof parseJudgeResponse;
|
|
2251
|
+
declare const index_d$1_recordAcceptance: typeof recordAcceptance;
|
|
2252
|
+
declare const index_d$1_recordDecline: typeof recordDecline;
|
|
2253
|
+
declare const index_d$1_resetDeclined: typeof resetDeclined;
|
|
2254
|
+
declare namespace index_d$1 {
|
|
2255
|
+
export { type index_d$1_AcceptResult as AcceptResult, index_d$1_AmbientBackpressure as AmbientBackpressure, type index_d$1_AmbientRecallHit as AmbientRecallHit, type index_d$1_AmbientRecallResult as AmbientRecallResult, index_d$1_AmbientRecaller as AmbientRecaller, type index_d$1_AmbientRecallerOptions as AmbientRecallerOptions, index_d$1_ClaudeCodeLLMJudge as ClaudeCodeLLMJudge, index_d$1_ClaudeCodeLLMJudgeError as ClaudeCodeLLMJudgeError, type index_d$1_ClaudeCodeSubAgentInvoker as ClaudeCodeSubAgentInvoker, type index_d$1_ClaudeDesktopInvoker as ClaudeDesktopInvoker, index_d$1_ClaudeDesktopLLMJudge as ClaudeDesktopLLMJudge, index_d$1_ClaudeDesktopLLMJudgeError as ClaudeDesktopLLMJudgeError, type index_d$1_CodexCompletionInvoker as CodexCompletionInvoker, index_d$1_CodexLLMJudge as CodexLLMJudge, index_d$1_CodexLLMJudgeError as CodexLLMJudgeError, type index_d$1_DeclinedEntry as DeclinedEntry, type index_d$1_ExpectedShape as ExpectedShape, type index_d$1_FingerprintInput as FingerprintInput, index_d$1_GeminiLLMJudge as GeminiLLMJudge, index_d$1_GeminiLLMJudgeError as GeminiLLMJudgeError, type index_d$1_GeminiMcpInvoker as GeminiMcpInvoker, type index_d$1_HubInput as HubInput, type index_d$1_HubProposal as HubProposal, index_d$1_HubProposer as HubProposer, type index_d$1_HubProposerOptions as HubProposerOptions, type index_d$1_InjectedInvoker as InjectedInvoker, index_d$1_InjectedLLMJudge as InjectedLLMJudge, type index_d$1_InsightInput as InsightInput, type index_d$1_InsightProposal as InsightProposal, index_d$1_InsightProposer as InsightProposer, type index_d$1_InsightProposerOptions as InsightProposerOptions, type index_d$1_LLMJudge as LLMJudge, index_d$1_LLMJudgeError as LLMJudgeError, type index_d$1_Proposal as Proposal, type index_d$1_ProposalAction as ProposalAction, type index_d$1_ProposalKind as ProposalKind, type index_d$1_Proposer as Proposer, type index_d$1_ProposerContext as ProposerContext, type index_d$1_RecallFn as RecallFn, type index_d$1_RecallSuggestion as RecallSuggestion, type index_d$1_TopicTreeSnapshot as TopicTreeSnapshot, index_d$1_TurnBuffer as TurnBuffer, type index_d$1_TurnRecord as TurnRecord, index_d$1_computeFingerprint as computeFingerprint, index_d$1_deriveQueryFromTurns as deriveQueryFromTurns, index_d$1_frameForJudge as frameForJudge, index_d$1_loadDeclinedFingerprints as loadDeclinedFingerprints, index_d$1_parseJudgeResponse as parseJudgeResponse, index_d$1_recordAcceptance as recordAcceptance, index_d$1_recordDecline as recordDecline, index_d$1_resetDeclined as resetDeclined };
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2258
|
+
/**
|
|
2259
|
+
* `/curate` — surface accumulated proposals from the proactive-curator
|
|
2260
|
+
* module. Two surfaces share one command:
|
|
2261
|
+
*
|
|
2262
|
+
* - `/curate` — run both proposers; surface any results.
|
|
2263
|
+
* - `/curate --insight` — InsightProposer only.
|
|
2264
|
+
* - `/curate --hub` — HubProposer only.
|
|
2265
|
+
* - `/curate --reset-declined` — clear the decline list (escape hatch).
|
|
2266
|
+
*
|
|
2267
|
+
* Host integration:
|
|
2268
|
+
* 1. Construct an `LLMJudge` adapter for the host (Claude Code / Codex /
|
|
2269
|
+
* Gemini / Claude Desktop) — see `@vortex-os/proactive-curator`.
|
|
2270
|
+
* 2. Optionally provide an `insightInputProvider` callback that returns
|
|
2271
|
+
* the current `InsightInput` (recent turns + accumulated tokens) when
|
|
2272
|
+
* the host wants the in-session insight surface. Without this provider
|
|
2273
|
+
* the insight proposer is skipped.
|
|
2274
|
+
* 3. Pass both to `createRitualRegistry({ llm, insightInputProvider })`.
|
|
2275
|
+
* The `/curate` command is registered only when an LLMJudge is
|
|
2276
|
+
* supplied — instances that have not wired up a host LLM get the rest
|
|
2277
|
+
* of the rituals without a half-broken curate command.
|
|
2278
|
+
*
|
|
2279
|
+
* Result shape carries the full `Proposal` objects (with `onAccept` and
|
|
2280
|
+
* `onDecline` thunks). Hosts render the previews, ask the user to decide,
|
|
2281
|
+
* then call the thunks. This is the one command in `session-rituals`
|
|
2282
|
+
* whose result is intentionally non-serializable — the thunks are the
|
|
2283
|
+
* point.
|
|
2284
|
+
*/
|
|
2285
|
+
interface CurateOptions {
|
|
2286
|
+
readonly llm: LLMJudge;
|
|
2287
|
+
/**
|
|
2288
|
+
* Returns the current InsightInput when the host wants the in-session
|
|
2289
|
+
* surface to run. Absence is a feature: hosts that only want hub
|
|
2290
|
+
* curation can omit it and the insight proposer is skipped without
|
|
2291
|
+
* error.
|
|
2292
|
+
*/
|
|
2293
|
+
readonly insightInputProvider?: () => InsightInput | null;
|
|
2294
|
+
readonly insightProposer?: InsightProposer;
|
|
2295
|
+
readonly hubProposer?: HubProposer;
|
|
2296
|
+
}
|
|
2297
|
+
type CurateAnyProposal = InsightProposal | HubProposal;
|
|
2298
|
+
interface CurateResult {
|
|
2299
|
+
readonly subcommand: "curate";
|
|
2300
|
+
readonly status: "ok" | "reset-declined";
|
|
2301
|
+
readonly proposals: readonly CurateAnyProposal[];
|
|
2302
|
+
readonly skipped: {
|
|
2303
|
+
readonly insight: boolean;
|
|
2304
|
+
readonly hub: boolean;
|
|
2305
|
+
};
|
|
2306
|
+
readonly nextActions: readonly string[];
|
|
2307
|
+
}
|
|
2308
|
+
/**
|
|
2309
|
+
* Build the `/curate` command bound to a particular LLMJudge and optional
|
|
2310
|
+
* input provider. Returned as a factory so the registry can decide at
|
|
2311
|
+
* registration time whether to install the command at all.
|
|
2312
|
+
*/
|
|
2313
|
+
declare function curateCommand(options: CurateOptions): Command<CurateResult>;
|
|
2314
|
+
|
|
2315
|
+
/**
|
|
2316
|
+
* `/recall <query>` — hybrid semantic search over memories, defined in the
|
|
2317
|
+
* plugin over the `@vortex-os/memory-extended` engine (mirrors how
|
|
2318
|
+
* `/curate` is defined here over `proactive-curator`). Keeping the command
|
|
2319
|
+
* in the plugin lets the module stay free of any slash-commands dependency.
|
|
2320
|
+
*
|
|
2321
|
+
* Host integration:
|
|
2322
|
+
* 1. Supply an embedder. `vector.createLocalEmbedder()` is the bundled
|
|
2323
|
+
* default (local MiniLM, model downloads on first use); pass an
|
|
2324
|
+
* OpenAI/Voyage adapter to use an API instead.
|
|
2325
|
+
* 2. Pass it to `createRitualRegistry({ recall: { embed } })`. The command
|
|
2326
|
+
* is registered only when an embedder is supplied — instances that have
|
|
2327
|
+
* not wired one up get the rest of the rituals without a half-broken
|
|
2328
|
+
* recall command (same graceful-degradation rule as `/curate`).
|
|
2329
|
+
*
|
|
2330
|
+
* The handler returns the structured `RecallResult` (data, not a report —
|
|
2331
|
+
* operator decision 5 / 2026-05-29). The host renders a list with
|
|
2332
|
+
* `vector`/`recall` render helpers for an explicit search, or reads the
|
|
2333
|
+
* hits and phrases one in conversation for ambient use.
|
|
2334
|
+
*/
|
|
2335
|
+
interface RecallOptions {
|
|
2336
|
+
/** Embedding function. `vector.createLocalEmbedder()` for the default. */
|
|
2337
|
+
readonly embed: vector.EmbedFn;
|
|
2338
|
+
/** Override the DB path. Default `<dataDir>/_indexes/memory.sqlite`. */
|
|
2339
|
+
readonly dbPath?: (ctx: ModuleContext) => string;
|
|
2340
|
+
/** Default hit count when `--k` is absent. Default 5. */
|
|
2341
|
+
readonly defaultK?: number;
|
|
2342
|
+
}
|
|
2343
|
+
declare function recallCommand(options: RecallOptions): Command<recall.RecallResult>;
|
|
2344
|
+
|
|
2345
|
+
/**
|
|
2346
|
+
* Options accepted by {@link createRitualRegistry}. All fields are optional;
|
|
2347
|
+
* each one unlocks an additional command surface when supplied:
|
|
2348
|
+
*
|
|
2349
|
+
* - `curate` — when an `LLMJudge` is provided, the `/curate` command from
|
|
2350
|
+
* `@vortex-os/proactive-curator` is registered. Without it the rest of
|
|
2351
|
+
* the rituals work as before and `/curate` is simply absent (graceful
|
|
2352
|
+
* degradation rather than a half-broken command).
|
|
2353
|
+
* - `recall` — when an embedder is provided, the `/recall` command over
|
|
2354
|
+
* `@vortex-os/memory-extended` is registered. Same graceful-degradation
|
|
2355
|
+
* rule: absent the embedder, semantic recall would not work, so the
|
|
2356
|
+
* command is simply not installed.
|
|
2357
|
+
*/
|
|
2358
|
+
interface RitualRegistryOptions {
|
|
2359
|
+
readonly curate?: CurateOptions;
|
|
2360
|
+
readonly recall?: RecallOptions;
|
|
2361
|
+
}
|
|
2362
|
+
/**
|
|
2363
|
+
* Build a {@link CommandRegistry} with all ritual commands registered.
|
|
2364
|
+
*
|
|
2365
|
+
* Hosts that want a subset can register the individual exports instead.
|
|
2366
|
+
* This factory exists for the common case — "give me everything" — plus
|
|
2367
|
+
* opt-in surfaces that depend on host-supplied adapters (currently
|
|
2368
|
+
* `/curate`, which needs an `LLMJudge`).
|
|
2369
|
+
*/
|
|
2370
|
+
declare function createRitualRegistry(options?: RitualRegistryOptions): CommandRegistry;
|
|
2371
|
+
|
|
2372
|
+
/**
|
|
2373
|
+
* Bridge the `@vortex-os/memory-extended` recall engine into a
|
|
2374
|
+
* `@vortex-os/proactive-curator` {@link AmbientRecaller} — defined in the
|
|
2375
|
+
* plugin, exactly where `/recall` and `/curate` are defined over their
|
|
2376
|
+
* respective engines. This keeps both modules free of a dependency on each
|
|
2377
|
+
* other; the plugin is the only place that knows about both.
|
|
2378
|
+
*
|
|
2379
|
+
* This is deliberately **not** a slash command. Ambient recall is stateful
|
|
2380
|
+
* across turns (its dedup set + backpressure streak), so it belongs to a
|
|
2381
|
+
* long-lived host — the opt-in embedder daemon / `UserPromptSubmit` hook, or
|
|
2382
|
+
* any host runtime that keeps one instance alive for the session. The default
|
|
2383
|
+
* Claude Code surface is agent-guidance (see `docs/proactive-curator-design.md`);
|
|
2384
|
+
* this factory is for hosts that opt into the *automatic* surface.
|
|
2385
|
+
*
|
|
2386
|
+
* Construct **once per session** and reuse the returned recaller so its gate
|
|
2387
|
+
* state persists. The injected `RecallFn` opens DB handles lazily per call
|
|
2388
|
+
* and closes them in a `finally`, so a long-lived process never holds a file
|
|
2389
|
+
* lock between turns. The embedder (the expensive, warm-able part) is
|
|
2390
|
+
* supplied by the host so it can keep the model resident across calls.
|
|
2391
|
+
*/
|
|
2392
|
+
interface AmbientRecallFactoryOptions {
|
|
2393
|
+
/** Embedding function. The host keeps this warm (daemon) to avoid per-call model loads. */
|
|
2394
|
+
readonly embed: vector.EmbedFn;
|
|
2395
|
+
/** Override the DB path. Default `<dataDir>/_indexes/memory.sqlite`. */
|
|
2396
|
+
readonly dbPath?: (ctx: ModuleContext) => string;
|
|
2397
|
+
/** Restrict recall to one corpus. Omit to search all. */
|
|
2398
|
+
readonly source?: vector.VectorSource;
|
|
2399
|
+
/** Forwarded to AmbientRecaller — minimum cosine score to surface. Default 0.5. */
|
|
2400
|
+
readonly minScore?: number;
|
|
2401
|
+
/** Forwarded to AmbientRecaller — max suggestions per consider(). Default 1. */
|
|
2402
|
+
readonly maxSuggestions?: number;
|
|
2403
|
+
/** Forwarded to AmbientRecaller — skip the engine below this query length. Default 12. */
|
|
2404
|
+
readonly minQueryChars?: number;
|
|
2405
|
+
}
|
|
2406
|
+
/**
|
|
2407
|
+
* Build a session-scoped {@link AmbientRecaller} wired to the recall engine.
|
|
2408
|
+
* Returns `undefined`-free — the caller owns the lifecycle.
|
|
2409
|
+
*/
|
|
2410
|
+
declare function createAmbientRecaller(ctx: ModuleContext, options: AmbientRecallFactoryOptions): AmbientRecaller;
|
|
2411
|
+
|
|
2412
|
+
/**
|
|
2413
|
+
* Output of {@link sessionStartCommand}'s handler. Pure data — the host
|
|
2414
|
+
* decides how to display it. Returning structured output rather than
|
|
2415
|
+
* printing keeps the command usable from non-CLI hosts (tests, web UIs).
|
|
2416
|
+
*/
|
|
2417
|
+
interface SessionStartReport {
|
|
2418
|
+
readonly time: string;
|
|
2419
|
+
readonly repoRoot: string;
|
|
2420
|
+
readonly dataDir: string;
|
|
2421
|
+
readonly counts: Readonly<Record<string, number>>;
|
|
2422
|
+
readonly missing: readonly string[];
|
|
2423
|
+
}
|
|
2424
|
+
/**
|
|
2425
|
+
* `/session-start` — Emit a small report that anchors a new session.
|
|
2426
|
+
* No side effects: reads filesystem counts only.
|
|
2427
|
+
*
|
|
2428
|
+
* The host (e.g. Claude Code session loop) is expected to display the
|
|
2429
|
+
* report and decide what to do next. This command's job is to surface
|
|
2430
|
+
* the facts, not to take action.
|
|
2431
|
+
*/
|
|
2432
|
+
declare const sessionStartCommand: Command<SessionStartReport>;
|
|
2433
|
+
|
|
2434
|
+
interface RecentWorklog {
|
|
2435
|
+
/** Path relative to the data directory (e.g. `worklog/2026/05/2026-05-30-foo.md`). */
|
|
2436
|
+
readonly path: string;
|
|
2437
|
+
/** First `# ` heading, else the filename without extension. */
|
|
2438
|
+
readonly title: string;
|
|
2439
|
+
}
|
|
2440
|
+
/** Outcome of the optional `git pull` the hook runs before reporting. */
|
|
2441
|
+
interface GitPullResult {
|
|
2442
|
+
readonly ran: boolean;
|
|
2443
|
+
readonly summary: string;
|
|
2444
|
+
/** True when the pull could not fast-forward (divergence / dirty tree). Never auto-resolved. */
|
|
2445
|
+
readonly conflict: boolean;
|
|
2446
|
+
}
|
|
2447
|
+
interface SessionStartHookReport {
|
|
2448
|
+
readonly time: string;
|
|
2449
|
+
readonly repoRoot: string;
|
|
2450
|
+
readonly dataDir: string;
|
|
2451
|
+
readonly counts: Readonly<Record<string, number>>;
|
|
2452
|
+
readonly missing: readonly string[];
|
|
2453
|
+
readonly recentWorklog: RecentWorklog | null;
|
|
2454
|
+
/** Worklog dates (`YYYY-MM-DD`) present within the gap window — for backfill detection. */
|
|
2455
|
+
readonly recentWorklogDates: readonly string[];
|
|
2456
|
+
/** Resolved environment label (e.g. home/work), or null when none is configured. */
|
|
2457
|
+
readonly environment: string | null;
|
|
2458
|
+
}
|
|
2459
|
+
/**
|
|
2460
|
+
* Gather the read-only facts for a start-of-session report: data-dir counts,
|
|
2461
|
+
* the most recent worklog, recent worklog dates, and an optional environment
|
|
2462
|
+
* label. Mirrors the `/session-start` command's counting.
|
|
2463
|
+
*/
|
|
2464
|
+
declare function collectSessionStartReport(ctx: ModuleContext, opts?: {
|
|
2465
|
+
readonly now?: Date;
|
|
2466
|
+
readonly environment?: string | null;
|
|
2467
|
+
readonly gapWindowDays?: number;
|
|
2468
|
+
}): Promise<SessionStartHookReport>;
|
|
2469
|
+
/**
|
|
2470
|
+
* Days that have commits but no worklog — backfill candidates. Pure set
|
|
2471
|
+
* difference (`commitDays` − `presentDates`), de-duplicated and sorted. The
|
|
2472
|
+
* hook supplies `commitDays` from git; the report supplies the present dates.
|
|
2473
|
+
*/
|
|
2474
|
+
declare function detectWorklogGaps(commitDays: readonly string[], presentDates: readonly string[]): string[];
|
|
2475
|
+
/**
|
|
2476
|
+
* Render a session-start report as a compact markdown block for a host hook
|
|
2477
|
+
* to inject as session context. A pull conflict and any worklog gaps are
|
|
2478
|
+
* surfaced as warnings (the agent acts on the gaps — see AGENT.md).
|
|
2479
|
+
*/
|
|
2480
|
+
declare function renderSessionStartReport(report: SessionStartHookReport, extras?: {
|
|
2481
|
+
readonly git?: GitPullResult | null;
|
|
2482
|
+
readonly missingWorklogDays?: readonly string[];
|
|
2483
|
+
readonly catchUp?: {
|
|
2484
|
+
readonly ingestedLocal: number;
|
|
2485
|
+
readonly indexedPulled: number;
|
|
2486
|
+
readonly errors: number;
|
|
2487
|
+
};
|
|
2488
|
+
}): string;
|
|
2489
|
+
|
|
2490
|
+
/**
|
|
2491
|
+
* Ensure a dated worklog entry exists — the host-side **create** primitive
|
|
2492
|
+
* the worklog module deliberately leaves out (`WorklogStore` reads; `/log`
|
|
2493
|
+
* only appends and errors when today's entry is missing). Auto-worklog
|
|
2494
|
+
* (the agent at wind-down, or the SessionEnd net) needs *creation*, so it
|
|
2495
|
+
* lives here, where instance frontmatter conventions belong.
|
|
2496
|
+
*
|
|
2497
|
+
* Idempotent: if a worklog already exists for the date (with any keyword), it
|
|
2498
|
+
* is returned untouched (`created: false`) — never overwritten. Pair with
|
|
2499
|
+
* `appendSection` from `@vortex-os/worklog` to add the session's content.
|
|
2500
|
+
*/
|
|
2501
|
+
interface EnsureWorklogResult {
|
|
2502
|
+
readonly path: string;
|
|
2503
|
+
readonly date: string;
|
|
2504
|
+
readonly keyword: string;
|
|
2505
|
+
/** True when this call created the file; false when one already existed. */
|
|
2506
|
+
readonly created: boolean;
|
|
2507
|
+
}
|
|
2508
|
+
declare function ensureWorklogEntry(ctx: ModuleContext, opts?: {
|
|
2509
|
+
readonly now?: Date;
|
|
2510
|
+
readonly keyword?: string;
|
|
2511
|
+
readonly title?: string;
|
|
2512
|
+
readonly body?: string;
|
|
2513
|
+
}): Promise<EnsureWorklogResult>;
|
|
2514
|
+
|
|
2515
|
+
/**
|
|
2516
|
+
* Start-of-session "catch-up": fold conversation transcripts into the local
|
|
2517
|
+
* search archive without the user ever having to wrap up a session.
|
|
2518
|
+
*
|
|
2519
|
+
* Two sources, one pass:
|
|
2520
|
+
* - **local (a)** — this machine's own transcripts that are not archived yet,
|
|
2521
|
+
* read from the agent's transcript store and scoped to the current project.
|
|
2522
|
+
* - **pulled (b)** — transcripts created on another machine that arrived as
|
|
2523
|
+
* normalized text via git sync. Their text is present but this machine's
|
|
2524
|
+
* DB (local, derived, gitignored) has never indexed them.
|
|
2525
|
+
*
|
|
2526
|
+
* Text only — vectorization is deferred to recall/rebuild so session start
|
|
2527
|
+
* stays fast. The whole step is gated by `autoRecord.archive` at the call site
|
|
2528
|
+
* and is best-effort: callers should treat a thrown archive backend (e.g. the
|
|
2529
|
+
* native sqlite module not built) as "skip", never as a fatal start error.
|
|
2530
|
+
*/
|
|
2531
|
+
interface CatchUpResult {
|
|
2532
|
+
/** Local transcripts newly archived this run (source a). */
|
|
2533
|
+
readonly ingestedLocal: number;
|
|
2534
|
+
/** Normalized transcripts from another machine newly indexed (source b). */
|
|
2535
|
+
readonly indexedPulled: number;
|
|
2536
|
+
/** Per-session ingest errors (source a). */
|
|
2537
|
+
readonly errors: number;
|
|
2538
|
+
}
|
|
2539
|
+
interface CatchUpOptions {
|
|
2540
|
+
/** Restrict local ingest to one project's transcripts. Default: `ctx.repoRoot`. */
|
|
2541
|
+
readonly cwd?: string;
|
|
2542
|
+
/**
|
|
2543
|
+
* Transcript adapters for local ingest. Default: Claude Code only. Other
|
|
2544
|
+
* hosts (Codex, Gemini) can be added by a caller; tests inject fakes so the
|
|
2545
|
+
* scan never touches the real home directory.
|
|
2546
|
+
*/
|
|
2547
|
+
readonly adapters?: sessionArchive.IngestParams["adapters"];
|
|
2548
|
+
/** Adapter environment override (e.g. a sandbox HOME). Tests use this. */
|
|
2549
|
+
readonly env?: sessionArchive.IngestParams["env"];
|
|
2550
|
+
}
|
|
2551
|
+
declare function catchUpSessions(ctx: ModuleContext, opts?: CatchUpOptions): Promise<CatchUpResult>;
|
|
2552
|
+
|
|
2553
|
+
/**
|
|
2554
|
+
* Hook wiring for `/vortex init`: make sure the instance's
|
|
2555
|
+
* `.claude/settings.json` registers the VortEX SessionStart / SessionEnd hooks,
|
|
2556
|
+
* so the boot report + worklog-net fire automatically without the user knowing
|
|
2557
|
+
* any command. NON-DESTRUCTIVE — like the MCP install merge, this preserves
|
|
2558
|
+
* every other hook and top-level field and only adds our two entries if absent.
|
|
2559
|
+
*
|
|
2560
|
+
* Pure functions here (parse / merge / detect); the command does the actual
|
|
2561
|
+
* file read/write around them. Keeping them pure makes the merge unit-testable
|
|
2562
|
+
* and the "writes only what's missing" guarantee verifiable.
|
|
2563
|
+
*/
|
|
2564
|
+
declare const SESSION_START_COMMAND = "node plugins/session-rituals/scripts/session-start-hook.mjs";
|
|
2565
|
+
declare const SESSION_END_COMMAND = "node plugins/session-rituals/scripts/session-end-hook.mjs";
|
|
2566
|
+
interface HookCommand {
|
|
2567
|
+
readonly type: "command";
|
|
2568
|
+
readonly command: string;
|
|
2569
|
+
}
|
|
2570
|
+
interface HookGroup {
|
|
2571
|
+
readonly hooks: readonly HookCommand[];
|
|
2572
|
+
readonly matcher?: string;
|
|
2573
|
+
}
|
|
2574
|
+
interface ClaudeSettings {
|
|
2575
|
+
hooks?: {
|
|
2576
|
+
SessionStart?: HookGroup[];
|
|
2577
|
+
SessionEnd?: HookGroup[];
|
|
2578
|
+
[event: string]: HookGroup[] | undefined;
|
|
2579
|
+
};
|
|
2580
|
+
[key: string]: unknown;
|
|
2581
|
+
}
|
|
2582
|
+
interface EnsureHooksResult {
|
|
2583
|
+
readonly settings: ClaudeSettings;
|
|
2584
|
+
/** Which hook events we added a VortEX entry to (empty if already wired). */
|
|
2585
|
+
readonly added: readonly ("SessionStart" | "SessionEnd")[];
|
|
2586
|
+
/** True when nothing changed — every VortEX hook was already present. */
|
|
2587
|
+
readonly alreadyWired: boolean;
|
|
2588
|
+
}
|
|
2589
|
+
/**
|
|
2590
|
+
* Parse existing settings.json text. Empty/whitespace → `{}` (fresh). Throws on
|
|
2591
|
+
* malformed JSON so the caller aborts rather than clobbering a hand-edited file.
|
|
2592
|
+
*/
|
|
2593
|
+
declare function parseSettings(text: string | null | undefined): ClaudeSettings;
|
|
2594
|
+
/**
|
|
2595
|
+
* Merge the VortEX hooks into an existing settings object WITHOUT mutating the
|
|
2596
|
+
* input. A hook event is left untouched if it already references our command
|
|
2597
|
+
* (idempotent); otherwise our group is appended alongside any existing groups.
|
|
2598
|
+
*/
|
|
2599
|
+
declare function ensureVortexHooks(existing: ClaudeSettings | null | undefined): EnsureHooksResult;
|
|
2600
|
+
/** Serialize settings the way Claude writes them (2-space, trailing newline). */
|
|
2601
|
+
declare function serializeSettings(settings: ClaudeSettings): string;
|
|
2602
|
+
|
|
2603
|
+
interface ReindexResult {
|
|
2604
|
+
readonly dir: string;
|
|
2605
|
+
readonly status: "written" | "unchanged" | "missing";
|
|
2606
|
+
readonly entries: number;
|
|
2607
|
+
readonly bytes: number;
|
|
2608
|
+
}
|
|
2609
|
+
/**
|
|
2610
|
+
* `/reindex [dir]` — Regenerate `_INDEX.md` for one or all known data
|
|
2611
|
+
* directories. When called with no argument, processes all targets;
|
|
2612
|
+
* when called with a directory name, processes only that target.
|
|
2613
|
+
*
|
|
2614
|
+
* Returns a list of results so the host can summarize. Unchanged
|
|
2615
|
+
* indexes are reported as `unchanged` (no write performed); missing
|
|
2616
|
+
* directories are reported as `missing` (no write attempted).
|
|
2617
|
+
*/
|
|
2618
|
+
declare const reindexCommand: Command<readonly ReindexResult[]>;
|
|
2619
|
+
|
|
2620
|
+
interface NewDecisionResult {
|
|
2621
|
+
readonly path: string;
|
|
2622
|
+
readonly date: string;
|
|
2623
|
+
readonly slug: string;
|
|
2624
|
+
}
|
|
2625
|
+
/**
|
|
2626
|
+
* `/decision <slug> <title...>` — Create a new Decision Log entry from
|
|
2627
|
+
* the canonical template at `data/decision-log/<today>-<slug>.md`.
|
|
2628
|
+
*
|
|
2629
|
+
* `slug` is required and used in the filename. The remaining tokens form
|
|
2630
|
+
* the entry title (the H1 in the rendered body). The command refuses to
|
|
2631
|
+
* overwrite an existing file — it errors out so the caller can decide.
|
|
2632
|
+
*/
|
|
2633
|
+
declare const decisionCommand: Command<NewDecisionResult>;
|
|
2634
|
+
|
|
2635
|
+
interface WorklogAppendResult {
|
|
2636
|
+
readonly path: string;
|
|
2637
|
+
readonly date: string;
|
|
2638
|
+
readonly keyword: string;
|
|
2639
|
+
readonly sectionTitle: string;
|
|
2640
|
+
}
|
|
2641
|
+
/**
|
|
2642
|
+
* `/log <section-title>` — Append a `## <section-title>` section to today's
|
|
2643
|
+
* worklog entry. If no worklog exists for today, the command errors (entry
|
|
2644
|
+
* creation with frontmatter is left to the host so it can apply
|
|
2645
|
+
* project-specific conventions). The body of the new section is left empty
|
|
2646
|
+
* for the caller to fill in.
|
|
2647
|
+
*
|
|
2648
|
+
* This is a deliberately small command — the goal is to make "add a quick
|
|
2649
|
+
* note to today's worklog" a one-liner, not to replace a real editor.
|
|
2650
|
+
*/
|
|
2651
|
+
declare const logCommand: Command<WorklogAppendResult>;
|
|
2652
|
+
|
|
2653
|
+
/**
|
|
2654
|
+
* "What should I do today?" — a read-only synthesis over existing records
|
|
2655
|
+
* (worklog + decision-log + open `- [ ]` checkboxes), the P2 work-management
|
|
2656
|
+
* surface. No new store: it reads what's already written and answers
|
|
2657
|
+
* "what were you doing, what's open, what's next" from it.
|
|
2658
|
+
*
|
|
2659
|
+
* Design goal (operator, 2026-05-30): adapt to EVERY data state — a brand-new
|
|
2660
|
+
* user with nothing, a partly-used instance, and a rich history must each get a
|
|
2661
|
+
* sensible report. So the collector returns a structured, presence-flagged
|
|
2662
|
+
* shape and the renderer branches on what's actually there rather than assuming
|
|
2663
|
+
* any section exists.
|
|
2664
|
+
*/
|
|
2665
|
+
/** An unchecked `- [ ]` item lifted from a recent worklog body. */
|
|
2666
|
+
interface OpenTask {
|
|
2667
|
+
readonly text: string;
|
|
2668
|
+
/** Worklog date the task was found in (`YYYY-MM-DD`). */
|
|
2669
|
+
readonly fromDate: string;
|
|
2670
|
+
}
|
|
2671
|
+
interface OpenDecision {
|
|
2672
|
+
readonly title: string;
|
|
2673
|
+
readonly date: string;
|
|
2674
|
+
readonly slug: string;
|
|
2675
|
+
}
|
|
2676
|
+
interface AgendaReport {
|
|
2677
|
+
/** Most recent worklog (what you were last doing), or null if none. */
|
|
2678
|
+
readonly lastWorklog: {
|
|
2679
|
+
readonly date: string;
|
|
2680
|
+
readonly title: string;
|
|
2681
|
+
readonly path: string;
|
|
2682
|
+
} | null;
|
|
2683
|
+
/**
|
|
2684
|
+
* "Next up" lines lifted from the most recent worklog's hand-off section
|
|
2685
|
+
* (`## 다음 작업` / `## Next` / a `📋`-marked heading) — the planned-work
|
|
2686
|
+
* pointer, mirroring the vault TIL hand-off block. Empty if none.
|
|
2687
|
+
*/
|
|
2688
|
+
readonly nextUp: readonly string[];
|
|
2689
|
+
/** Date of the worklog the nextUp lines came from (or null). */
|
|
2690
|
+
readonly nextUpFrom: string | null;
|
|
2691
|
+
/** Unchecked checkboxes from recent worklogs, newest first, capped. */
|
|
2692
|
+
readonly openTasks: readonly OpenTask[];
|
|
2693
|
+
/** Active (non-archived) decisions, newest first, capped. */
|
|
2694
|
+
readonly openDecisions: readonly OpenDecision[];
|
|
2695
|
+
/** Total worklog / decision counts — used to distinguish "new" from "quiet". */
|
|
2696
|
+
readonly worklogCount: number;
|
|
2697
|
+
readonly decisionCount: number;
|
|
2698
|
+
/** True when there is essentially nothing yet (brand-new instance). */
|
|
2699
|
+
readonly isEmpty: boolean;
|
|
2700
|
+
/** True when there are records but nothing actionable surfaced. */
|
|
2701
|
+
readonly nothingOpen: boolean;
|
|
2702
|
+
}
|
|
2703
|
+
interface CollectAgendaOptions {
|
|
2704
|
+
/** How many recent worklogs to scan for open tasks. Default 7. */
|
|
2705
|
+
readonly recentWorklogs?: number;
|
|
2706
|
+
/** Max open tasks / decisions to surface. Default 8 each. */
|
|
2707
|
+
readonly maxTasks?: number;
|
|
2708
|
+
readonly maxDecisions?: number;
|
|
2709
|
+
}
|
|
2710
|
+
/**
|
|
2711
|
+
* Pull unchecked GitHub-style checkboxes (`- [ ]` / `* [ ]`, any indent) from a
|
|
2712
|
+
* worklog body. Checked items (`- [x]`) are ignored. Returns the trimmed label.
|
|
2713
|
+
*/
|
|
2714
|
+
/**
|
|
2715
|
+
* Lift the "next up / hand-off" section from a worklog body — the planned-work
|
|
2716
|
+
* pointer the agent leaves at wind-down (mirrors the vault's TIL `## 📋 다음
|
|
2717
|
+
* 작업` block). Matches a heading whose text contains any of: "다음 작업",
|
|
2718
|
+
* "다음 세션", "next", "next up", "todo", "후속", "📋". Returns the section's
|
|
2719
|
+
* content lines (bullets de-marked, blanks dropped), capped. Empty if no such
|
|
2720
|
+
* section. Stops at the next heading of the same-or-higher level.
|
|
2721
|
+
*/
|
|
2722
|
+
declare function extractNextUp(body: string, max?: number): string[];
|
|
2723
|
+
/**
|
|
2724
|
+
* Pull unchecked GitHub-style checkboxes (`- [ ]` / `* [ ]`, any indent) from a
|
|
2725
|
+
* worklog body. Checked items (`- [x]`) are ignored. Returns the trimmed label.
|
|
2726
|
+
*/
|
|
2727
|
+
declare function extractOpenTasks(body: string): string[];
|
|
2728
|
+
/**
|
|
2729
|
+
* Collect the agenda inputs. Read-only; tolerant of missing dirs (both stores
|
|
2730
|
+
* return empty rather than throwing), so a brand-new instance yields an empty —
|
|
2731
|
+
* but well-formed — report.
|
|
2732
|
+
*/
|
|
2733
|
+
declare function collectAgenda(ctx: ModuleContext, opts?: CollectAgendaOptions): Promise<AgendaReport>;
|
|
2734
|
+
/**
|
|
2735
|
+
* Render the agenda as a compact markdown block. Branches on data state so the
|
|
2736
|
+
* output is sensible whether the instance is brand-new, quiet, or busy:
|
|
2737
|
+
* - brand-new (no records) → a short "getting started" nudge
|
|
2738
|
+
* - records but nothing open → "you're clear" + last activity
|
|
2739
|
+
* - open tasks / decisions → an actionable list
|
|
2740
|
+
*/
|
|
2741
|
+
declare function renderAgenda(report: AgendaReport): string;
|
|
2742
|
+
|
|
2743
|
+
/**
|
|
2744
|
+
* `/agenda` — "What should I do today?" Read-only synthesis over existing
|
|
2745
|
+
* worklog + decision-log records (open `- [ ]` tasks, active decisions, last
|
|
2746
|
+
* activity). Returns structured {@link AgendaReport} data; the host renders it
|
|
2747
|
+
* (or calls `renderAgenda`). No writes, no new store — answers from what's
|
|
2748
|
+
* already recorded, and adapts to any data state (new / quiet / busy).
|
|
2749
|
+
*/
|
|
2750
|
+
declare const agendaCommand: Command<AgendaReport>;
|
|
2751
|
+
|
|
2752
|
+
/**
|
|
2753
|
+
* `/vortex <sub>` — Root command for VortEX instance operations.
|
|
2754
|
+
*
|
|
2755
|
+
* Subcommands:
|
|
2756
|
+
* init — first-time setup wizard (user profile + first worklog; detects
|
|
2757
|
+
* external folders in $HOME and surfaces an import hint)
|
|
2758
|
+
* status — instance state report (counts, profile, latestWorklog, missing)
|
|
2759
|
+
* import — copy a folder into the instance, auto-classify into 5 categories
|
|
2760
|
+
* or preserve user folder structure, inject frontmatter, scan
|
|
2761
|
+
* wiki-link health via @vortex-os/link-rewriter
|
|
2762
|
+
* doctor — 8-check health diagnosis (system dirs, profile, indexes,
|
|
2763
|
+
* wiki links, data-lint rules, runbook aging, node version,
|
|
2764
|
+
* git remote)
|
|
2765
|
+
* sync — framework-developer workflow: git pull → npm install → npm run
|
|
2766
|
+
* build → npm run verify. Stops on first failure with stdout/stderr
|
|
2767
|
+
* tail. End users who consume vortex from npm registry do not need
|
|
2768
|
+
* this — they get pre-built dist via `npm install @vortex-os/*`.
|
|
2769
|
+
* help — list available subcommands
|
|
2770
|
+
*/
|
|
2771
|
+
declare const PLANNED_SUBS: readonly [];
|
|
2772
|
+
type PlannedSub = (typeof PLANNED_SUBS)[number];
|
|
2773
|
+
interface VortexInitResult {
|
|
2774
|
+
readonly subcommand: "init";
|
|
2775
|
+
readonly status: "completed" | "needs-input" | "already-initialized";
|
|
2776
|
+
readonly created: readonly string[];
|
|
2777
|
+
readonly nextActions: readonly string[];
|
|
2778
|
+
readonly missingInputs?: readonly {
|
|
2779
|
+
name: string;
|
|
2780
|
+
prompt: string;
|
|
2781
|
+
}[];
|
|
2782
|
+
readonly externalFolders?: readonly {
|
|
2783
|
+
readonly path: string;
|
|
2784
|
+
readonly basename: string;
|
|
2785
|
+
readonly mdCount: number;
|
|
2786
|
+
}[];
|
|
2787
|
+
}
|
|
2788
|
+
interface VortexPlannedResult {
|
|
2789
|
+
readonly subcommand: PlannedSub | "unknown";
|
|
2790
|
+
readonly status: "not-implemented";
|
|
2791
|
+
readonly message: string;
|
|
2792
|
+
}
|
|
2793
|
+
interface VortexHelpResult {
|
|
2794
|
+
readonly subcommand: "help";
|
|
2795
|
+
readonly status: "ok";
|
|
2796
|
+
/** `/vortex <sub>` subcommands routed inside this command. */
|
|
2797
|
+
readonly subcommands: readonly {
|
|
2798
|
+
readonly name: string;
|
|
2799
|
+
readonly description: string;
|
|
2800
|
+
readonly state: "active" | "planned";
|
|
2801
|
+
}[];
|
|
2802
|
+
/**
|
|
2803
|
+
* Other top-level slash commands shipped by the same plugin
|
|
2804
|
+
* (`session-rituals`). Independent commands, not `/vortex` subcommands —
|
|
2805
|
+
* surfaced here so users discover the full plugin surface from a single
|
|
2806
|
+
* `/vortex help` call instead of needing to know they exist separately.
|
|
2807
|
+
*/
|
|
2808
|
+
readonly siblingCommands: readonly {
|
|
2809
|
+
readonly name: string;
|
|
2810
|
+
readonly description: string;
|
|
2811
|
+
}[];
|
|
2812
|
+
}
|
|
2813
|
+
interface VortexStatusResult {
|
|
2814
|
+
readonly subcommand: "status";
|
|
2815
|
+
readonly status: "ok" | "uninitialized";
|
|
2816
|
+
readonly instance: {
|
|
2817
|
+
readonly dataDir: string;
|
|
2818
|
+
readonly initialized: boolean;
|
|
2819
|
+
readonly profile?: {
|
|
2820
|
+
readonly name?: string;
|
|
2821
|
+
readonly role?: string;
|
|
2822
|
+
};
|
|
2823
|
+
};
|
|
2824
|
+
readonly counts: {
|
|
2825
|
+
readonly memory: number;
|
|
2826
|
+
readonly worklog: number;
|
|
2827
|
+
readonly decisionLog: number;
|
|
2828
|
+
readonly runbooks: number;
|
|
2829
|
+
readonly hubs: number;
|
|
2830
|
+
};
|
|
2831
|
+
readonly latestWorklog?: {
|
|
2832
|
+
readonly date: string;
|
|
2833
|
+
readonly keyword: string;
|
|
2834
|
+
readonly path: string;
|
|
2835
|
+
};
|
|
2836
|
+
readonly missing: readonly string[];
|
|
2837
|
+
readonly nextActions: readonly string[];
|
|
2838
|
+
}
|
|
2839
|
+
interface VortexImportResult {
|
|
2840
|
+
readonly subcommand: "import";
|
|
2841
|
+
readonly status: "completed" | "dry-run" | "needs-input" | "source-missing";
|
|
2842
|
+
readonly source?: string;
|
|
2843
|
+
readonly totalFiles: number;
|
|
2844
|
+
readonly copied: number;
|
|
2845
|
+
readonly classified: {
|
|
2846
|
+
readonly worklog: number;
|
|
2847
|
+
readonly decisionLog: number;
|
|
2848
|
+
readonly runbooks: number;
|
|
2849
|
+
readonly hubs: number;
|
|
2850
|
+
readonly memory: number;
|
|
2851
|
+
readonly preserved: number;
|
|
2852
|
+
};
|
|
2853
|
+
readonly frontmatterInjected: number;
|
|
2854
|
+
readonly frontmatterPreserved: number;
|
|
2855
|
+
readonly systemDirsCreated: readonly string[];
|
|
2856
|
+
readonly skipped: number;
|
|
2857
|
+
readonly links?: {
|
|
2858
|
+
readonly filesScanned: number;
|
|
2859
|
+
readonly total: number;
|
|
2860
|
+
readonly resolved: number;
|
|
2861
|
+
readonly broken: number;
|
|
2862
|
+
readonly ambiguous: number;
|
|
2863
|
+
};
|
|
2864
|
+
readonly missingInputs?: readonly {
|
|
2865
|
+
name: string;
|
|
2866
|
+
prompt: string;
|
|
2867
|
+
}[];
|
|
2868
|
+
readonly nextActions: readonly string[];
|
|
2869
|
+
}
|
|
2870
|
+
type DoctorCheckStatus = "pass" | "warn" | "fail" | "info";
|
|
2871
|
+
interface DoctorCheck {
|
|
2872
|
+
readonly id: string;
|
|
2873
|
+
readonly label: string;
|
|
2874
|
+
readonly status: DoctorCheckStatus;
|
|
2875
|
+
readonly detail?: string;
|
|
2876
|
+
}
|
|
2877
|
+
interface VortexDoctorResult {
|
|
2878
|
+
readonly subcommand: "doctor";
|
|
2879
|
+
readonly status: "ok" | "warnings" | "errors";
|
|
2880
|
+
readonly checks: readonly DoctorCheck[];
|
|
2881
|
+
readonly summary: {
|
|
2882
|
+
readonly pass: number;
|
|
2883
|
+
readonly warn: number;
|
|
2884
|
+
readonly fail: number;
|
|
2885
|
+
readonly info: number;
|
|
2886
|
+
};
|
|
2887
|
+
readonly nextActions: readonly string[];
|
|
2888
|
+
}
|
|
2889
|
+
type VortexSyncStepId = "pull" | "install" | "build" | "verify";
|
|
2890
|
+
type VortexSyncStepStatus = "ok" | "failed" | "skipped";
|
|
2891
|
+
interface VortexSyncStep {
|
|
2892
|
+
readonly id: VortexSyncStepId;
|
|
2893
|
+
readonly label: string;
|
|
2894
|
+
readonly status: VortexSyncStepStatus;
|
|
2895
|
+
readonly exitCode?: number;
|
|
2896
|
+
readonly durationMs?: number;
|
|
2897
|
+
readonly stdoutTail?: string;
|
|
2898
|
+
readonly stderrTail?: string;
|
|
2899
|
+
}
|
|
2900
|
+
interface VortexSyncResult {
|
|
2901
|
+
readonly subcommand: "sync";
|
|
2902
|
+
readonly status: "completed" | "failed" | "dry-run";
|
|
2903
|
+
readonly steps: readonly VortexSyncStep[];
|
|
2904
|
+
readonly failedAt?: VortexSyncStepId;
|
|
2905
|
+
readonly nextActions: readonly string[];
|
|
2906
|
+
}
|
|
2907
|
+
type VortexResult = VortexInitResult | VortexStatusResult | VortexImportResult | VortexDoctorResult | VortexSyncResult | VortexPlannedResult | VortexHelpResult;
|
|
2908
|
+
declare const vortexCommand: Command<VortexResult>;
|
|
2909
|
+
|
|
2910
|
+
//# sourceMappingURL=index.d.ts.map
|
|
2911
|
+
|
|
2912
|
+
type index_d_AgendaReport = AgendaReport;
|
|
2913
|
+
type index_d_AmbientRecallFactoryOptions = AmbientRecallFactoryOptions;
|
|
2914
|
+
type index_d_CatchUpOptions = CatchUpOptions;
|
|
2915
|
+
type index_d_CatchUpResult = CatchUpResult;
|
|
2916
|
+
type index_d_ClaudeSettings = ClaudeSettings;
|
|
2917
|
+
type index_d_CollectAgendaOptions = CollectAgendaOptions;
|
|
2918
|
+
type index_d_CurateAnyProposal = CurateAnyProposal;
|
|
2919
|
+
type index_d_CurateOptions = CurateOptions;
|
|
2920
|
+
type index_d_CurateResult = CurateResult;
|
|
2921
|
+
type index_d_EnsureHooksResult = EnsureHooksResult;
|
|
2922
|
+
type index_d_EnsureWorklogResult = EnsureWorklogResult;
|
|
2923
|
+
type index_d_GitPullResult = GitPullResult;
|
|
2924
|
+
type index_d_NewDecisionResult = NewDecisionResult;
|
|
2925
|
+
type index_d_OpenDecision = OpenDecision;
|
|
2926
|
+
type index_d_OpenTask = OpenTask;
|
|
2927
|
+
type index_d_RecallOptions = RecallOptions;
|
|
2928
|
+
type index_d_RecentWorklog = RecentWorklog;
|
|
2929
|
+
type index_d_ReindexResult = ReindexResult;
|
|
2930
|
+
type index_d_RitualRegistryOptions = RitualRegistryOptions;
|
|
2931
|
+
declare const index_d_SESSION_END_COMMAND: typeof SESSION_END_COMMAND;
|
|
2932
|
+
declare const index_d_SESSION_START_COMMAND: typeof SESSION_START_COMMAND;
|
|
2933
|
+
type index_d_SessionStartHookReport = SessionStartHookReport;
|
|
2934
|
+
type index_d_SessionStartReport = SessionStartReport;
|
|
2935
|
+
type index_d_VortexHelpResult = VortexHelpResult;
|
|
2936
|
+
type index_d_VortexInitResult = VortexInitResult;
|
|
2937
|
+
type index_d_VortexPlannedResult = VortexPlannedResult;
|
|
2938
|
+
type index_d_VortexResult = VortexResult;
|
|
2939
|
+
type index_d_VortexSyncResult = VortexSyncResult;
|
|
2940
|
+
type index_d_VortexSyncStep = VortexSyncStep;
|
|
2941
|
+
type index_d_VortexSyncStepId = VortexSyncStepId;
|
|
2942
|
+
type index_d_VortexSyncStepStatus = VortexSyncStepStatus;
|
|
2943
|
+
type index_d_WorklogAppendResult = WorklogAppendResult;
|
|
2944
|
+
declare const index_d_agendaCommand: typeof agendaCommand;
|
|
2945
|
+
declare const index_d_catchUpSessions: typeof catchUpSessions;
|
|
2946
|
+
declare const index_d_collectAgenda: typeof collectAgenda;
|
|
2947
|
+
declare const index_d_collectSessionStartReport: typeof collectSessionStartReport;
|
|
2948
|
+
declare const index_d_createAmbientRecaller: typeof createAmbientRecaller;
|
|
2949
|
+
declare const index_d_createRitualRegistry: typeof createRitualRegistry;
|
|
2950
|
+
declare const index_d_curateCommand: typeof curateCommand;
|
|
2951
|
+
declare const index_d_decisionCommand: typeof decisionCommand;
|
|
2952
|
+
declare const index_d_detectWorklogGaps: typeof detectWorklogGaps;
|
|
2953
|
+
declare const index_d_ensureVortexHooks: typeof ensureVortexHooks;
|
|
2954
|
+
declare const index_d_ensureWorklogEntry: typeof ensureWorklogEntry;
|
|
2955
|
+
declare const index_d_extractNextUp: typeof extractNextUp;
|
|
2956
|
+
declare const index_d_extractOpenTasks: typeof extractOpenTasks;
|
|
2957
|
+
declare const index_d_logCommand: typeof logCommand;
|
|
2958
|
+
declare const index_d_parseSettings: typeof parseSettings;
|
|
2959
|
+
declare const index_d_recallCommand: typeof recallCommand;
|
|
2960
|
+
declare const index_d_reindexCommand: typeof reindexCommand;
|
|
2961
|
+
declare const index_d_renderAgenda: typeof renderAgenda;
|
|
2962
|
+
declare const index_d_renderSessionStartReport: typeof renderSessionStartReport;
|
|
2963
|
+
declare const index_d_serializeSettings: typeof serializeSettings;
|
|
2964
|
+
declare const index_d_sessionStartCommand: typeof sessionStartCommand;
|
|
2965
|
+
declare const index_d_vortexCommand: typeof vortexCommand;
|
|
2966
|
+
declare namespace index_d {
|
|
2967
|
+
export { type index_d_AgendaReport as AgendaReport, type index_d_AmbientRecallFactoryOptions as AmbientRecallFactoryOptions, type index_d_CatchUpOptions as CatchUpOptions, type index_d_CatchUpResult as CatchUpResult, type index_d_ClaudeSettings as ClaudeSettings, type index_d_CollectAgendaOptions as CollectAgendaOptions, type index_d_CurateAnyProposal as CurateAnyProposal, type index_d_CurateOptions as CurateOptions, type index_d_CurateResult as CurateResult, type index_d_EnsureHooksResult as EnsureHooksResult, type index_d_EnsureWorklogResult as EnsureWorklogResult, type index_d_GitPullResult as GitPullResult, type index_d_NewDecisionResult as NewDecisionResult, type index_d_OpenDecision as OpenDecision, type index_d_OpenTask as OpenTask, type index_d_RecallOptions as RecallOptions, type index_d_RecentWorklog as RecentWorklog, type index_d_ReindexResult as ReindexResult, type index_d_RitualRegistryOptions as RitualRegistryOptions, index_d_SESSION_END_COMMAND as SESSION_END_COMMAND, index_d_SESSION_START_COMMAND as SESSION_START_COMMAND, type index_d_SessionStartHookReport as SessionStartHookReport, type index_d_SessionStartReport as SessionStartReport, type index_d_VortexHelpResult as VortexHelpResult, type index_d_VortexInitResult as VortexInitResult, type index_d_VortexPlannedResult as VortexPlannedResult, type index_d_VortexResult as VortexResult, type index_d_VortexSyncResult as VortexSyncResult, type index_d_VortexSyncStep as VortexSyncStep, type index_d_VortexSyncStepId as VortexSyncStepId, type index_d_VortexSyncStepStatus as VortexSyncStepStatus, type index_d_WorklogAppendResult as WorklogAppendResult, index_d_agendaCommand as agendaCommand, index_d_catchUpSessions as catchUpSessions, index_d_collectAgenda as collectAgenda, index_d_collectSessionStartReport as collectSessionStartReport, index_d_createAmbientRecaller as createAmbientRecaller, index_d_createRitualRegistry as createRitualRegistry, index_d_curateCommand as curateCommand, index_d_decisionCommand as decisionCommand, index_d_detectWorklogGaps as detectWorklogGaps, index_d_ensureVortexHooks as ensureVortexHooks, index_d_ensureWorklogEntry as ensureWorklogEntry, index_d_extractNextUp as extractNextUp, index_d_extractOpenTasks as extractOpenTasks, index_d_logCommand as logCommand, index_d_parseSettings as parseSettings, index_d_recallCommand as recallCommand, index_d_reindexCommand as reindexCommand, index_d_renderAgenda as renderAgenda, index_d_renderSessionStartReport as renderSessionStartReport, index_d_serializeSettings as serializeSettings, index_d_sessionStartCommand as sessionStartCommand, index_d_vortexCommand as vortexCommand };
|
|
2968
|
+
}
|
|
2969
|
+
|
|
2970
|
+
export { index_d$9 as aiCodingPitfalls, index_d$d as core, index_d$a as dataLint, index_d$5 as decisionLog, index_d$4 as indexGenerator, index_d$2 as linkRewriter, index_d$b as memorySystem, index_d$1 as proactiveCurator, index_d$7 as reportGenerator, index_d$3 as runbooks, index_d as sessionRituals, index_d$c as slashCommands, index_d$8 as toolRules, index_d$6 as worklog };
|