hafez 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,96 +1,113 @@
1
1
  import type { SessionLogEntry, SessionLogType } from './types.js';
2
- /**
3
- * Known structural section headings in Hafez entities, knowledge notes, and
4
- * session files. Derived from contracts.ts (defaultSections + optionalSections
5
- * + session sections) plus auto-generated sections not tracked in contracts
6
- * (Related). Only these are treated as section boundaries. Any other `## `
7
- * heading inside section content (e.g. in a brief or session log) is
8
- * preserved as-is.
9
- */
10
- export declare const STRUCTURAL_SECTIONS: Set<string>;
11
- /**
12
- * Find the next structural `## Heading` boundary after a given position.
13
- * Skips `## ` headings that are not known structural sections (content headings).
14
- * Returns the index of the `\n` before the `## `, or -1 if no structural heading found.
15
- */
16
- export declare function findNextStructuralHeading(body: string, from: number): number;
17
- /**
18
- * Find a ## Heading section and its content.
19
- * Returns { start, headingEnd, end, content } or null if not found.
20
- * Matches heading exactly (e.g. "## Brief" won't match "## Briefing").
21
- * Trailing whitespace on the heading line is tolerated — the splitter's
22
- * boundary tokenizer trims headings, so anything it treats as a boundary
23
- * must also be findable here (a hand-edited `## Session Log ` otherwise
24
- * gets a duplicate section and archival never fires).
25
- * Only treats known structural headings as section boundaries -- content
26
- * inside a section may contain arbitrary `## ` headings without corruption.
27
- */
28
- export declare function findSection(body: string, heading: string): {
29
- start: number;
30
- headingEnd: number;
31
- end: number;
32
- content: string;
33
- } | null;
34
- export interface DocSection {
35
- heading: string;
36
- content: string;
37
- }
38
- /**
39
- * Split a body into preamble + structural sections. Non-structural `## `
40
- * headings stay inside the enclosing section's content — sections are
41
- * atomic units of authored content, never split at user headings.
42
- * Headings and content come back trimmed; reassemble with
43
- * `## ${heading}\n\n${content}` joined by blank lines.
44
- */
45
- export declare function splitStructural(body: string): {
46
- preamble: string;
47
- sections: DocSection[];
48
- };
49
- /**
50
- * Replace a structural section's content, or create the section: before
51
- * `insertBefore` when that section exists, at EOF otherwise.
52
- */
53
- export declare function setSection(body: string, heading: string, content: string, insertBefore?: string): string;
54
- /** Append content at the end of a structural section (creating it at EOF if absent). */
55
- export declare function appendToSection(body: string, heading: string, content: string): string;
56
- /** Insert a formatted session-log entry newest-first (creating the section at EOF if absent). */
57
- export declare function prependSessionLogEntry(body: string, entry: string): string;
58
- /** Body up to the real Session Log section — the `summary` read depth. */
59
- export declare function bodyBeforeSessionLog(body: string): string;
60
2
  export declare function parseSessionLogHeading(line: string): {
61
3
  date: string;
62
4
  agent: string;
63
5
  type: SessionLogType;
64
6
  } | null;
65
7
  export declare function formatSessionLogEntry(entry: SessionLogEntry): string;
66
- /** Entries inside the real Session Log section only — entry-shaped lines
67
- * elsewhere in the body (e.g. quoted in a Brief) do not count. */
68
- export declare function countSessionLogEntries(body: string): number;
8
+ /**
9
+ * Split a Session Log section's content into raw entry blocks, each beginning
10
+ * with a parseable entry heading. Non-entry text before the first heading is
11
+ * not an entry and is dropped. Document owns entry block splitting — merge's
12
+ * dedup/sort policy stays in merge.ts.
13
+ */
14
+ export declare function splitLogEntries(content: string): string[];
15
+ export declare function firstNonEmptyLine(s: string | null | undefined): string;
16
+ /** The one wiki-link syntax the vault recognizes: [[slug]] or
17
+ * [[slug|display text]] — slug in group 1, display text in group 2.
18
+ * Padding inside the brackets is Obsidian-idiomatic ([[ slug ]], [[slug | Label]])
19
+ * and is absorbed by the pattern, so both captures come out already trimmed —
20
+ * every consumer (Related coverage, mention harvesting, export) sees the bare slug.
21
+ * Non-global — wrap with `new RegExp(WIKI_LINK_RE.source, 'g')` for iteration. */
22
+ export declare const WIKI_LINK_RE: RegExp;
23
+ /** What documentFor needs to know about a file to bind its section set.
24
+ *
25
+ * KIND is the whole context — deliberately no type/subtype narrowing. A file
26
+ * can legitimately carry sections outside its current type's contract (a
27
+ * promote race merged in a capture's Notes, a plan-shaped note never had its
28
+ * subtype persisted, a hand edit added Open Questions to a plain entity), and
29
+ * a narrower binding demotes those headings to non-structural text that the
30
+ * next section rewrite silently deletes. The kind-level union makes every
31
+ * same-kind heading a boundary, so no same-kind section is ever swallowed;
32
+ * the cost is that a same-kind heading quoted at line start inside a section
33
+ * strands as its own section on rewrite — visible and recoverable, unlike
34
+ * deletion. Cross-KIND headings (a session-only ## Decisions quoted in an
35
+ * entity Brief) are still not boundaries. */
36
+ export interface DocContext {
37
+ kind: 'entity' | 'knowledge' | 'session';
38
+ }
39
+ /** The structural set a context binds — exposed for introspection and the
40
+ * contract-coverage tests; runtime consumers go through documentFor. */
41
+ export declare function structuralSectionsFor(ctx: DocContext): ReadonlySet<string>;
42
+ /** The Document operations bound to one file's structural section set. */
43
+ export declare function documentFor(ctx: DocContext): Doc;
44
+ /** Bind from a parsed vault file — kind from Layout. */
45
+ export declare function documentForFile(parsed: {
46
+ kind: 'entity' | 'knowledge' | 'session';
47
+ }): Doc;
48
+ export interface DocSection {
49
+ heading: string;
50
+ content: string;
51
+ }
52
+ export interface Doc {
53
+ findNextStructuralHeading(body: string, from: number): number;
54
+ findSection(body: string, heading: string): {
55
+ start: number;
56
+ headingEnd: number;
57
+ end: number;
58
+ content: string;
59
+ } | null;
60
+ splitStructural(body: string): {
61
+ preamble: string;
62
+ sections: DocSection[];
63
+ };
64
+ setSection(body: string, heading: string, content: string, insertBefore?: string): string;
65
+ appendToSection(body: string, heading: string, content: string): string;
66
+ renameSection(body: string, from: string, to: string): string;
67
+ ensureSection(body: string, heading: string, opts?: {
68
+ after?: string;
69
+ }): string;
70
+ prependSessionLogEntry(body: string, entry: string): string;
71
+ bodyBeforeSessionLog(body: string): string;
72
+ countSessionLogEntries(body: string): number;
73
+ parseSessionLog(body: string): Array<{
74
+ date: string;
75
+ agent: string;
76
+ type: SessionLogType;
77
+ summary: string;
78
+ }>;
79
+ extractOldestSessionLogEntry(body: string): {
80
+ entry: string;
81
+ remaining: string;
82
+ } | null;
83
+ getBrief(body: string): string | null;
84
+ setBrief(body: string, content: string): string;
85
+ removeBrief(body: string): string;
86
+ getNextActions(body: string): string[];
87
+ addNextAction(body: string, action: string): string;
88
+ completeNextAction(body: string, query: string): {
89
+ matched: string;
90
+ body: string;
91
+ };
92
+ removeNextAction(body: string, query: string): {
93
+ matched: string;
94
+ body: string;
95
+ };
96
+ clearNextActions(body: string): string;
97
+ syncRelatedSection(body: string, frontmatter: {
98
+ parent?: string;
99
+ related?: string[];
100
+ }): string;
101
+ }
102
+ export declare function getBrief(body: string): string | null;
103
+ export declare function getNextActions(body: string): string[];
69
104
  export declare function parseSessionLog(body: string): Array<{
70
105
  date: string;
71
106
  agent: string;
72
107
  type: SessionLogType;
73
108
  summary: string;
74
109
  }>;
75
- export declare function extractOldestSessionLogEntry(body: string): {
76
- entry: string;
77
- remaining: string;
78
- } | null;
79
- export declare function getBrief(body: string): string | null;
80
- export declare function setBrief(body: string, content: string): string;
81
- export declare function removeBrief(body: string): string;
82
- export declare function getNextActions(body: string): string[];
83
- export declare function addNextAction(body: string, action: string): string;
84
- export declare function completeNextAction(body: string, query: string): {
85
- matched: string;
86
- body: string;
87
- };
88
- export declare function removeNextAction(body: string, query: string): {
89
- matched: string;
90
- body: string;
91
- };
92
- export declare function clearNextActions(body: string): string;
93
- export declare function firstNonEmptyLine(s: string | null | undefined): string;
110
+ export declare function countSessionLogEntries(body: string): number;
94
111
  /**
95
112
  * One-line summary for a doc: frontmatter description first, then the first
96
113
  * non-empty line of the kind's primary section (entity: Brief; knowledge:
@@ -98,11 +115,3 @@ export declare function firstNonEmptyLine(s: string | null | undefined): string;
98
115
  * Shared by the vault index and the OKF export so the two surfaces agree.
99
116
  */
100
117
  export declare function deriveSummary(kind: 'entity' | 'knowledge' | 'session', fm: Record<string, any>, body: string): string;
101
- /** The one wiki-link syntax the vault recognizes: [[slug]] or
102
- * [[slug|display text]] — slug in group 1, display text in group 2.
103
- * Non-global — wrap with `new RegExp(WIKI_LINK_RE.source, 'g')` for iteration. */
104
- export declare const WIKI_LINK_RE: RegExp;
105
- export declare function syncRelatedSection(body: string, frontmatter: {
106
- parent?: string;
107
- related?: string[];
108
- }): string;