@vainplex/openclaw-cortex 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +151 -0
  3. package/dist/index.d.ts +10 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +50 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/src/boot-context.d.ts +43 -0
  8. package/dist/src/boot-context.d.ts.map +1 -0
  9. package/dist/src/boot-context.js +215 -0
  10. package/dist/src/boot-context.js.map +1 -0
  11. package/dist/src/config.d.ts +10 -0
  12. package/dist/src/config.d.ts.map +1 -0
  13. package/dist/src/config.js +100 -0
  14. package/dist/src/config.js.map +1 -0
  15. package/dist/src/decision-tracker.d.ts +48 -0
  16. package/dist/src/decision-tracker.d.ts.map +1 -0
  17. package/dist/src/decision-tracker.js +135 -0
  18. package/dist/src/decision-tracker.js.map +1 -0
  19. package/dist/src/hooks.d.ts +7 -0
  20. package/dist/src/hooks.d.ts.map +1 -0
  21. package/dist/src/hooks.js +104 -0
  22. package/dist/src/hooks.js.map +1 -0
  23. package/dist/src/narrative-generator.d.ts +34 -0
  24. package/dist/src/narrative-generator.d.ts.map +1 -0
  25. package/dist/src/narrative-generator.js +153 -0
  26. package/dist/src/narrative-generator.js.map +1 -0
  27. package/dist/src/patterns.d.ts +24 -0
  28. package/dist/src/patterns.d.ts.map +1 -0
  29. package/dist/src/patterns.js +98 -0
  30. package/dist/src/patterns.js.map +1 -0
  31. package/dist/src/pre-compaction.d.ts +21 -0
  32. package/dist/src/pre-compaction.d.ts.map +1 -0
  33. package/dist/src/pre-compaction.js +108 -0
  34. package/dist/src/pre-compaction.js.map +1 -0
  35. package/dist/src/storage.d.ts +44 -0
  36. package/dist/src/storage.d.ts.map +1 -0
  37. package/dist/src/storage.js +126 -0
  38. package/dist/src/storage.js.map +1 -0
  39. package/dist/src/thread-tracker.d.ts +75 -0
  40. package/dist/src/thread-tracker.d.ts.map +1 -0
  41. package/dist/src/thread-tracker.js +250 -0
  42. package/dist/src/thread-tracker.js.map +1 -0
  43. package/dist/src/types.d.ts +202 -0
  44. package/dist/src/types.d.ts.map +1 -0
  45. package/dist/src/types.js +24 -0
  46. package/dist/src/types.js.map +1 -0
  47. package/openclaw.plugin.json +154 -0
  48. package/package.json +48 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vainplex
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,151 @@
1
+ # @vainplex/openclaw-cortex
2
+
3
+ > Conversation intelligence layer for [OpenClaw](https://github.com/openclaw/openclaw) — automated thread tracking, decision extraction, boot context generation, and pre-compaction snapshots.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@vainplex/openclaw-cortex)](https://www.npmjs.com/package/@vainplex/openclaw-cortex)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## What It Does
9
+
10
+ `openclaw-cortex` listens to OpenClaw message hooks and automatically:
11
+
12
+ - **📋 Tracks conversation threads** — detects topic shifts, closures, decisions, and blocking items
13
+ - **🎯 Extracts decisions** — recognizes when decisions are made (English + German) and logs them
14
+ - **🚀 Generates boot context** — assembles a dense `BOOTSTRAP.md` at session start so the agent has continuity
15
+ - **📸 Pre-compaction snapshots** — saves thread state + hot snapshot before memory compaction
16
+ - **📖 Structured narratives** — generates 24h activity summaries from threads + decisions
17
+
18
+ Works **alongside** `memory-core` (OpenClaw's built-in memory) — doesn't replace it.
19
+
20
+ ## Install
21
+
22
+ ```bash
23
+ # From npm
24
+ npm install @vainplex/openclaw-cortex
25
+
26
+ # Copy to OpenClaw extensions
27
+ cp -r node_modules/@vainplex/openclaw-cortex ~/.openclaw/extensions/openclaw-cortex
28
+ ```
29
+
30
+ Or clone directly:
31
+
32
+ ```bash
33
+ cd ~/.openclaw/extensions
34
+ git clone https://github.com/alberthild/openclaw-cortex.git
35
+ cd openclaw-cortex && npm install && npm run build
36
+ ```
37
+
38
+ ## Configure
39
+
40
+ Add to your OpenClaw config:
41
+
42
+ ```json
43
+ {
44
+ "plugins": {
45
+ "openclaw-cortex": {
46
+ "enabled": true,
47
+ "patterns": {
48
+ "language": "both"
49
+ },
50
+ "threadTracker": {
51
+ "enabled": true,
52
+ "pruneDays": 7,
53
+ "maxThreads": 50
54
+ },
55
+ "decisionTracker": {
56
+ "enabled": true,
57
+ "maxDecisions": 100,
58
+ "dedupeWindowHours": 24
59
+ },
60
+ "bootContext": {
61
+ "enabled": true,
62
+ "maxChars": 16000,
63
+ "onSessionStart": true,
64
+ "maxThreadsInBoot": 7,
65
+ "maxDecisionsInBoot": 10,
66
+ "decisionRecencyDays": 14
67
+ },
68
+ "preCompaction": {
69
+ "enabled": true,
70
+ "maxSnapshotMessages": 15
71
+ },
72
+ "narrative": {
73
+ "enabled": true
74
+ }
75
+ }
76
+ }
77
+ }
78
+ ```
79
+
80
+ Restart OpenClaw after configuring.
81
+
82
+ ## How It Works
83
+
84
+ ### Hooks
85
+
86
+ | Hook | Feature | Priority |
87
+ |---|---|---|
88
+ | `message_received` | Thread + Decision Tracking | 100 |
89
+ | `message_sent` | Thread + Decision Tracking | 100 |
90
+ | `session_start` | Boot Context Generation | 10 |
91
+ | `before_compaction` | Pre-Compaction Snapshot | 5 |
92
+ | `after_compaction` | Logging | 200 |
93
+
94
+ ### Output Files
95
+
96
+ ```
97
+ {workspace}/
98
+ ├── BOOTSTRAP.md # Dense boot context (regenerated each session)
99
+ └── memory/
100
+ └── reboot/
101
+ ├── threads.json # Thread state
102
+ ├── decisions.json # Decision log
103
+ ├── narrative.md # 24h activity summary
104
+ └── hot-snapshot.md # Pre-compaction snapshot
105
+ ```
106
+
107
+ ### Pattern Languages
108
+
109
+ Thread and decision detection supports English, German, or both:
110
+
111
+ - **Decision patterns**: "we decided", "let's do", "the plan is", "wir machen", "beschlossen"
112
+ - **Closure patterns**: "is done", "it works", "fixed ✅", "erledigt", "gefixt"
113
+ - **Wait patterns**: "waiting for", "blocked by", "warte auf"
114
+ - **Topic patterns**: "back to", "now about", "jetzt zu", "bzgl."
115
+ - **Mood detection**: frustrated, excited, tense, productive, exploratory
116
+
117
+ ### Graceful Degradation
118
+
119
+ - Read-only workspace → runs in-memory, skips writes
120
+ - Corrupt JSON → starts fresh, next write recovers
121
+ - Missing directories → creates them automatically
122
+ - Hook errors → caught and logged, never crashes the gateway
123
+
124
+ ## Development
125
+
126
+ ```bash
127
+ npm install
128
+ npm test # 270 tests
129
+ npm run typecheck # TypeScript strict mode
130
+ npm run build # Compile to dist/
131
+ ```
132
+
133
+ ## Performance
134
+
135
+ - Zero runtime dependencies (Node built-ins only)
136
+ - All hook handlers are non-blocking (fire-and-forget)
137
+ - Atomic file writes via `.tmp` + rename
138
+ - Tested with 270 unit + integration tests
139
+
140
+ ## Architecture
141
+
142
+ See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the full design document including module diagrams, data flows, type definitions, and testing strategy.
143
+
144
+ ## License
145
+
146
+ MIT — see [LICENSE](LICENSE)
147
+
148
+ ## Related
149
+
150
+ - [@vainplex/nats-eventstore](https://www.npmjs.com/package/@vainplex/nats-eventstore) — Publish OpenClaw events to NATS JetStream
151
+ - [OpenClaw](https://github.com/openclaw/openclaw) — Multi-channel AI gateway
@@ -0,0 +1,10 @@
1
+ import type { OpenClawPluginApi } from "./src/types.js";
2
+ declare const plugin: {
3
+ id: string;
4
+ name: string;
5
+ description: string;
6
+ version: string;
7
+ register(api: OpenClawPluginApi): void;
8
+ };
9
+ export default plugin;
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAe,MAAM,gBAAgB,CAAC;AAErE,QAAA,MAAM,MAAM;;;;;kBAOI,iBAAiB;CA8ChC,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,50 @@
1
+ import { registerCortexHooks } from "./src/hooks.js";
2
+ import { resolveConfig, resolveWorkspace } from "./src/config.js";
3
+ import { loadJson, rebootDir } from "./src/storage.js";
4
+ const plugin = {
5
+ id: "openclaw-cortex",
6
+ name: "OpenClaw Cortex",
7
+ description: "Conversation intelligence — thread tracking, decision extraction, boot context, pre-compaction snapshots",
8
+ version: "0.1.0",
9
+ register(api) {
10
+ const config = resolveConfig(api.pluginConfig);
11
+ if (!config.enabled) {
12
+ api.logger.info("[cortex] Disabled via config");
13
+ return;
14
+ }
15
+ api.logger.info("[cortex] Registering conversation intelligence hooks...");
16
+ // Register all hook handlers
17
+ registerCortexHooks(api, config);
18
+ // Register /cortexstatus command
19
+ api.registerCommand({
20
+ name: "cortexstatus",
21
+ description: "Show cortex plugin status: thread count, last update, mood",
22
+ requireAuth: true,
23
+ handler: () => {
24
+ try {
25
+ const workspace = resolveWorkspace(config);
26
+ const data = loadJson(`${rebootDir(workspace)}/threads.json`);
27
+ const threads = data.threads ?? [];
28
+ const openCount = threads.filter(t => t.status === "open").length;
29
+ const closedCount = threads.filter(t => t.status === "closed").length;
30
+ const mood = data.session_mood ?? "neutral";
31
+ const updated = data.updated ?? "never";
32
+ return {
33
+ text: [
34
+ "**Cortex Status**",
35
+ `Threads: ${openCount} open, ${closedCount} closed`,
36
+ `Mood: ${mood}`,
37
+ `Updated: ${updated}`,
38
+ ].join("\n"),
39
+ };
40
+ }
41
+ catch {
42
+ return { text: "[cortex] Status: operational (no data yet)" };
43
+ }
44
+ },
45
+ });
46
+ api.logger.info("[cortex] Ready");
47
+ },
48
+ };
49
+ export default plugin;
50
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGvD,MAAM,MAAM,GAAG;IACb,EAAE,EAAE,iBAAiB;IACrB,IAAI,EAAE,iBAAiB;IACvB,WAAW,EACT,0GAA0G;IAC5G,OAAO,EAAE,OAAO;IAEhB,QAAQ,CAAC,GAAsB;QAC7B,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAE/C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;YAChD,OAAO;QACT,CAAC;QAED,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;QAE3E,6BAA6B;QAC7B,mBAAmB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAEjC,iCAAiC;QACjC,GAAG,CAAC,eAAe,CAAC;YAClB,IAAI,EAAE,cAAc;YACpB,WAAW,EAAE,4DAA4D;YACzE,WAAW,EAAE,IAAI;YACjB,OAAO,EAAE,GAAG,EAAE;gBACZ,IAAI,CAAC;oBACH,MAAM,SAAS,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;oBAC3C,MAAM,IAAI,GAAG,QAAQ,CACnB,GAAG,SAAS,CAAC,SAAS,CAAC,eAAe,CACvC,CAAC;oBACF,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;oBACnC,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;oBAClE,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;oBACtE,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,IAAI,SAAS,CAAC;oBAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC;oBAExC,OAAO;wBACL,IAAI,EAAE;4BACJ,mBAAmB;4BACnB,YAAY,SAAS,UAAU,WAAW,SAAS;4BACnD,SAAS,IAAI,EAAE;4BACf,YAAY,OAAO,EAAE;yBACtB,CAAC,IAAI,CAAC,IAAI,CAAC;qBACb,CAAC;gBACJ,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,EAAE,IAAI,EAAE,4CAA4C,EAAE,CAAC;gBAChE,CAAC;YACH,CAAC;SACF,CAAC,CAAC;QAEH,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACpC,CAAC;CACF,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -0,0 +1,43 @@
1
+ import type { Thread, ExecutionMode, PluginLogger, CortexConfig } from "./types.js";
2
+ /**
3
+ * Determine execution mode from current hour.
4
+ */
5
+ export declare function getExecutionMode(): ExecutionMode;
6
+ /**
7
+ * Get sorted open threads by priority and recency.
8
+ */
9
+ export declare function getOpenThreads(workspace: string, limit: number): Thread[];
10
+ /**
11
+ * Generate staleness warning from integrity data.
12
+ */
13
+ export declare function integrityWarning(workspace: string): string;
14
+ /**
15
+ * Boot Context Generator — assembles BOOTSTRAP.md from persisted state.
16
+ */
17
+ export declare class BootContextGenerator {
18
+ private readonly workspace;
19
+ private readonly config;
20
+ private readonly logger;
21
+ constructor(workspace: string, config: CortexConfig["bootContext"], logger: PluginLogger);
22
+ /**
23
+ * Check if boot context should be generated.
24
+ */
25
+ shouldGenerate(): boolean;
26
+ /** Build header section. */
27
+ private buildHeader;
28
+ /** Build state section (mode, mood, warnings). */
29
+ private buildState;
30
+ /** Build threads section. */
31
+ private buildThreads;
32
+ /** Build decisions section. */
33
+ private buildDecisions;
34
+ /**
35
+ * Assemble and return BOOTSTRAP.md content.
36
+ */
37
+ generate(): string;
38
+ /**
39
+ * Generate and write BOOTSTRAP.md to the workspace root.
40
+ */
41
+ write(): boolean;
42
+ }
43
+ //# sourceMappingURL=boot-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boot-context.d.ts","sourceRoot":"","sources":["../../src/boot-context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,MAAM,EAIN,aAAa,EACb,YAAY,EACZ,YAAY,EAEb,MAAM,YAAY,CAAC;AAIpB;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAMhD;AAgBD;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAazE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAuB1D;AAwCD;;GAEG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8B;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;gBAGpC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,CAAC,aAAa,CAAC,EACnC,MAAM,EAAE,YAAY;IAOtB;;OAEG;IACH,cAAc,IAAI,OAAO;IAIzB,4BAA4B;IAC5B,OAAO,CAAC,WAAW;IASnB,kDAAkD;IAClD,OAAO,CAAC,UAAU;IAiBlB,6BAA6B;IAC7B,OAAO,CAAC,YAAY;IAgBpB,+BAA+B;IAC/B,OAAO,CAAC,cAAc;IAYtB;;OAEG;IACH,QAAQ,IAAI,MAAM;IA8BlB;;OAEG;IACH,KAAK,IAAI,OAAO;CAUjB"}
@@ -0,0 +1,215 @@
1
+ import { join } from "node:path";
2
+ import { MOOD_EMOJI, PRIORITY_EMOJI, PRIORITY_ORDER } from "./types.js";
3
+ import { loadJson, loadText, rebootDir, isFileOlderThan, saveText, ensureRebootDir } from "./storage.js";
4
+ /**
5
+ * Determine execution mode from current hour.
6
+ */
7
+ export function getExecutionMode() {
8
+ const hour = new Date().getHours();
9
+ if (hour >= 6 && hour < 12)
10
+ return "Morning — brief, directive, efficient";
11
+ if (hour >= 12 && hour < 18)
12
+ return "Afternoon — execution mode";
13
+ if (hour >= 18 && hour < 22)
14
+ return "Evening — strategic, philosophical possible";
15
+ return "Night — emergencies only";
16
+ }
17
+ /**
18
+ * Load threads data from disk.
19
+ */
20
+ function loadThreadsData(workspace) {
21
+ const data = loadJson(join(rebootDir(workspace), "threads.json"));
22
+ // Handle legacy format where data is an array
23
+ if (Array.isArray(data)) {
24
+ return { threads: data };
25
+ }
26
+ return data;
27
+ }
28
+ /**
29
+ * Get sorted open threads by priority and recency.
30
+ */
31
+ export function getOpenThreads(workspace, limit) {
32
+ const data = loadThreadsData(workspace);
33
+ const threads = (data.threads ?? []).filter(t => t.status === "open");
34
+ threads.sort((a, b) => {
35
+ const priA = PRIORITY_ORDER[a.priority] ?? 3;
36
+ const priB = PRIORITY_ORDER[b.priority] ?? 3;
37
+ if (priA !== priB)
38
+ return priA - priB;
39
+ // More recent first
40
+ return b.last_activity.localeCompare(a.last_activity);
41
+ });
42
+ return threads.slice(0, limit);
43
+ }
44
+ /**
45
+ * Generate staleness warning from integrity data.
46
+ */
47
+ export function integrityWarning(workspace) {
48
+ const data = loadThreadsData(workspace);
49
+ const integrity = data.integrity;
50
+ if (!integrity?.last_event_timestamp) {
51
+ return "⚠️ No integrity data — thread tracker may not have run yet.";
52
+ }
53
+ try {
54
+ const lastTs = integrity.last_event_timestamp;
55
+ const lastDt = new Date(lastTs.endsWith("Z") ? lastTs : lastTs + "Z");
56
+ const ageMin = (Date.now() - lastDt.getTime()) / 60000;
57
+ if (ageMin > 480) {
58
+ return `🚨 STALE DATA: Thread data is ${Math.round(ageMin / 60)}h old.`;
59
+ }
60
+ if (ageMin > 120) {
61
+ return `⚠️ Data staleness: Thread data is ${Math.round(ageMin / 60)}h old.`;
62
+ }
63
+ return "";
64
+ }
65
+ catch {
66
+ return "⚠️ Could not parse integrity timestamp.";
67
+ }
68
+ }
69
+ /**
70
+ * Load hot snapshot if it's fresh (< 1 hour old).
71
+ */
72
+ function loadHotSnapshot(workspace) {
73
+ const filePath = join(rebootDir(workspace), "hot-snapshot.md");
74
+ if (isFileOlderThan(filePath, 1))
75
+ return "";
76
+ const content = loadText(filePath);
77
+ return content.trim().slice(0, 1000);
78
+ }
79
+ /**
80
+ * Load decisions from the last N days, return last `limit` entries.
81
+ */
82
+ function loadRecentDecisions(workspace, days, limit) {
83
+ const data = loadJson(join(rebootDir(workspace), "decisions.json"));
84
+ const decisions = Array.isArray(data.decisions) ? data.decisions : [];
85
+ const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
86
+ return decisions
87
+ .filter(d => d.date >= cutoff)
88
+ .slice(-limit);
89
+ }
90
+ /**
91
+ * Load narrative if it's fresh (< 36 hours old).
92
+ */
93
+ function loadNarrative(workspace) {
94
+ const filePath = join(rebootDir(workspace), "narrative.md");
95
+ if (isFileOlderThan(filePath, 36))
96
+ return "";
97
+ const content = loadText(filePath);
98
+ return content.trim().slice(0, 2000);
99
+ }
100
+ /**
101
+ * Boot Context Generator — assembles BOOTSTRAP.md from persisted state.
102
+ */
103
+ export class BootContextGenerator {
104
+ workspace;
105
+ config;
106
+ logger;
107
+ constructor(workspace, config, logger) {
108
+ this.workspace = workspace;
109
+ this.config = config;
110
+ this.logger = logger;
111
+ }
112
+ /**
113
+ * Check if boot context should be generated.
114
+ */
115
+ shouldGenerate() {
116
+ return this.config.enabled && this.config.onSessionStart;
117
+ }
118
+ /** Build header section. */
119
+ buildHeader() {
120
+ const now = new Date();
121
+ return [
122
+ "# Context Briefing",
123
+ `Generated: ${now.toISOString().slice(0, 19)}Z | Local: ${now.toTimeString().slice(0, 5)}`,
124
+ "",
125
+ ].join("\n");
126
+ }
127
+ /** Build state section (mode, mood, warnings). */
128
+ buildState() {
129
+ const lines = ["## ⚡ State", `Mode: ${getExecutionMode()}`];
130
+ const threadsData = loadThreadsData(this.workspace);
131
+ const mood = (threadsData.session_mood ?? "neutral");
132
+ if (mood !== "neutral") {
133
+ lines.push(`Last session mood: ${mood} ${MOOD_EMOJI[mood] ?? ""}`);
134
+ }
135
+ const warning = integrityWarning(this.workspace);
136
+ if (warning) {
137
+ lines.push("", warning);
138
+ }
139
+ lines.push("");
140
+ return lines.join("\n");
141
+ }
142
+ /** Build threads section. */
143
+ buildThreads(threads) {
144
+ if (threads.length === 0)
145
+ return "";
146
+ const lines = ["## 🧵 Active Threads"];
147
+ for (const t of threads) {
148
+ const priEmoji = PRIORITY_EMOJI[t.priority] ?? "⚪";
149
+ const moodTag = t.mood && t.mood !== "neutral" ? ` [${t.mood}]` : "";
150
+ lines.push("", `### ${priEmoji} ${t.title}${moodTag}`);
151
+ lines.push(`Priority: ${t.priority} | Last: ${t.last_activity.slice(0, 16)}`);
152
+ lines.push(`Summary: ${t.summary || "no summary"}`);
153
+ if (t.waiting_for)
154
+ lines.push(`⏳ Waiting for: ${t.waiting_for}`);
155
+ if (t.decisions.length > 0)
156
+ lines.push(`Decisions: ${t.decisions.join(", ")}`);
157
+ }
158
+ lines.push("");
159
+ return lines.join("\n");
160
+ }
161
+ /** Build decisions section. */
162
+ buildDecisions(decisions) {
163
+ if (decisions.length === 0)
164
+ return "";
165
+ const impactEmoji = { critical: "🔴", high: "🟠", medium: "🟡", low: "🔵" };
166
+ const lines = ["## 🎯 Recent Decisions"];
167
+ for (const d of decisions) {
168
+ lines.push(`- ${impactEmoji[d.impact] ?? "⚪"} **${d.what}** (${d.date})`);
169
+ if (d.why)
170
+ lines.push(` Why: ${d.why.slice(0, 100)}`);
171
+ }
172
+ lines.push("");
173
+ return lines.join("\n");
174
+ }
175
+ /**
176
+ * Assemble and return BOOTSTRAP.md content.
177
+ */
178
+ generate() {
179
+ ensureRebootDir(this.workspace, this.logger);
180
+ const threads = getOpenThreads(this.workspace, this.config.maxThreadsInBoot);
181
+ const decisions = loadRecentDecisions(this.workspace, this.config.decisionRecencyDays, this.config.maxDecisionsInBoot);
182
+ const hot = loadHotSnapshot(this.workspace);
183
+ const narrative = loadNarrative(this.workspace);
184
+ const sections = [
185
+ this.buildHeader(),
186
+ this.buildState(),
187
+ hot ? `## 🔥 Last Session Snapshot\n${hot}\n` : "",
188
+ narrative ? `## 📖 Narrative (last 24h)\n${narrative}\n` : "",
189
+ this.buildThreads(threads),
190
+ this.buildDecisions(decisions),
191
+ "---",
192
+ `_Boot context | ${threads.length} active threads | ${decisions.length} recent decisions_`,
193
+ ];
194
+ let result = sections.filter(Boolean).join("\n");
195
+ if (result.length > this.config.maxChars) {
196
+ result = result.slice(0, this.config.maxChars) + "\n\n_[truncated to token budget]_";
197
+ }
198
+ return result;
199
+ }
200
+ /**
201
+ * Generate and write BOOTSTRAP.md to the workspace root.
202
+ */
203
+ write() {
204
+ try {
205
+ const content = this.generate();
206
+ const outputPath = join(this.workspace, "BOOTSTRAP.md");
207
+ return saveText(outputPath, content, this.logger);
208
+ }
209
+ catch (err) {
210
+ this.logger.warn(`[cortex] Boot context generation failed: ${err}`);
211
+ return false;
212
+ }
213
+ }
214
+ }
215
+ //# sourceMappingURL=boot-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boot-context.js","sourceRoot":"","sources":["../../src/boot-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAWjC,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEzG;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC;IACnC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,GAAG,EAAE;QAAE,OAAO,uCAAuC,CAAC;IAC3E,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,GAAG,EAAE;QAAE,OAAO,4BAA4B,CAAC;IACjE,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,GAAG,EAAE;QAAE,OAAO,6CAA6C,CAAC;IAClF,OAAO,0BAA0B,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,SAAiB;IACxC,MAAM,IAAI,GAAG,QAAQ,CACnB,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,cAAc,CAAC,CAC3C,CAAC;IACF,8CAA8C;IAC9C,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,OAAO,EAAE,IAA2B,EAAE,CAAC;IAClD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,KAAa;IAC7D,MAAM,IAAI,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;IAEtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACpB,MAAM,IAAI,GAAG,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,IAAI,GAAG,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,IAAI,GAAG,IAAI,CAAC;QACtC,oBAAoB;QACpB,OAAO,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB;IAChD,MAAM,IAAI,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IAEjC,IAAI,CAAC,SAAS,EAAE,oBAAoB,EAAE,CAAC;QACrC,OAAO,6DAA6D,CAAC;IACvE,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,CAAC,oBAAoB,CAAC;QAC9C,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;QACtE,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,GAAG,KAAK,CAAC;QAEvD,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;YACjB,OAAO,iCAAiC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC,QAAQ,CAAC;QAC1E,CAAC;QACD,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;YACjB,OAAO,qCAAqC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC,QAAQ,CAAC;QAC9E,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,yCAAyC,CAAC;IACnD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,SAAiB;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,iBAAiB,CAAC,CAAC;IAC/D,IAAI,eAAe,CAAC,QAAQ,EAAE,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IAC5C,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACnC,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,SAAS,mBAAmB,CAAC,SAAiB,EAAE,IAAY,EAAE,KAAa;IACzE,MAAM,IAAI,GAAG,QAAQ,CACnB,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,gBAAgB,CAAC,CAC7C,CAAC;IACF,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IAEtE,MAAM,MAAM,GAAG,IAAI,IAAI,CACrB,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CACxC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAE7B,OAAO,SAAS;SACb,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC;SAC7B,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,SAAiB;IACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,cAAc,CAAC,CAAC;IAC5D,IAAI,eAAe,CAAC,QAAQ,EAAE,EAAE,CAAC;QAAE,OAAO,EAAE,CAAC;IAC7C,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACnC,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,MAAM,OAAO,oBAAoB;IACd,SAAS,CAAS;IAClB,MAAM,CAA8B;IACpC,MAAM,CAAe;IAEtC,YACE,SAAiB,EACjB,MAAmC,EACnC,MAAoB;QAEpB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC;IAC3D,CAAC;IAED,4BAA4B;IACpB,WAAW;QACjB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,OAAO;YACL,oBAAoB;YACpB,cAAc,GAAG,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,GAAG,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;YAC1F,EAAE;SACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;IAED,kDAAkD;IAC1C,UAAU;QAChB,MAAM,KAAK,GAAa,CAAC,YAAY,EAAE,SAAS,gBAAgB,EAAE,EAAE,CAAC,CAAC;QAEtE,MAAM,WAAW,GAAG,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACpD,MAAM,IAAI,GAAG,CAAC,WAAW,CAAC,YAAY,IAAI,SAAS,CAAS,CAAC;QAC7D,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,KAAK,CAAC,IAAI,CAAC,sBAAsB,IAAI,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,OAAO,EAAE,CAAC;YACZ,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC1B,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,6BAA6B;IACrB,YAAY,CAAC,OAAiB;QACpC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QACpC,MAAM,KAAK,GAAa,CAAC,sBAAsB,CAAC,CAAC;QACjD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,MAAM,QAAQ,GAAG,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC;YACnD,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACrE,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,QAAQ,IAAI,CAAC,CAAC,KAAK,GAAG,OAAO,EAAE,CAAC,CAAC;YACvD,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,QAAQ,YAAY,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;YAC9E,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,IAAI,YAAY,EAAE,CAAC,CAAC;YACpD,IAAI,CAAC,CAAC,WAAW;gBAAE,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;YACjE,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjF,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,+BAA+B;IACvB,cAAc,CAAC,SAAqB;QAC1C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QACtC,MAAM,WAAW,GAA2B,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QACpG,MAAM,KAAK,GAAa,CAAC,wBAAwB,CAAC,CAAC;QACnD,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;YAC1E,IAAI,CAAC,CAAC,GAAG;gBAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QACzD,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,eAAe,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAE7C,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;QAC7E,MAAM,SAAS,GAAG,mBAAmB,CACnC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,mBAAmB,EAAE,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAChF,CAAC;QACF,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC5C,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAEhD,MAAM,QAAQ,GAAG;YACf,IAAI,CAAC,WAAW,EAAE;YAClB,IAAI,CAAC,UAAU,EAAE;YACjB,GAAG,CAAC,CAAC,CAAC,gCAAgC,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE;YAClD,SAAS,CAAC,CAAC,CAAC,+BAA+B,SAAS,IAAI,CAAC,CAAC,CAAC,EAAE;YAC7D,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;YAC1B,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC;YAC9B,KAAK;YACL,mBAAmB,OAAO,CAAC,MAAM,qBAAqB,SAAS,CAAC,MAAM,oBAAoB;SAC3F,CAAC;QAEF,IAAI,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEjD,IAAI,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACzC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,mCAAmC,CAAC;QACvF,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;YACxD,OAAO,QAAQ,CAAC,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACpD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4CAA4C,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ import type { CortexConfig } from "./types.js";
2
+ export declare const DEFAULTS: CortexConfig;
3
+ export declare function resolveConfig(pluginConfig?: Record<string, unknown>): CortexConfig;
4
+ /**
5
+ * Resolve workspace directory from config, hook context, env, or cwd.
6
+ */
7
+ export declare function resolveWorkspace(config: CortexConfig, ctx?: {
8
+ workspaceDir?: string;
9
+ }): string;
10
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,eAAO,MAAM,QAAQ,EAAE,YA+BtB,CAAC;AAoBF,wBAAgB,aAAa,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,CAyClF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,YAAY,EACpB,GAAG,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9B,MAAM,CAIR"}
@@ -0,0 +1,100 @@
1
+ export const DEFAULTS = {
2
+ enabled: true,
3
+ workspace: "",
4
+ threadTracker: {
5
+ enabled: true,
6
+ pruneDays: 7,
7
+ maxThreads: 50,
8
+ },
9
+ decisionTracker: {
10
+ enabled: true,
11
+ maxDecisions: 100,
12
+ dedupeWindowHours: 24,
13
+ },
14
+ bootContext: {
15
+ enabled: true,
16
+ maxChars: 16000,
17
+ onSessionStart: true,
18
+ maxThreadsInBoot: 7,
19
+ maxDecisionsInBoot: 10,
20
+ decisionRecencyDays: 14,
21
+ },
22
+ preCompaction: {
23
+ enabled: true,
24
+ maxSnapshotMessages: 15,
25
+ },
26
+ narrative: {
27
+ enabled: true,
28
+ },
29
+ patterns: {
30
+ language: "both",
31
+ },
32
+ };
33
+ function bool(value, fallback) {
34
+ return typeof value === "boolean" ? value : fallback;
35
+ }
36
+ function int(value, fallback) {
37
+ if (typeof value === "number" && Number.isFinite(value))
38
+ return Math.round(value);
39
+ return fallback;
40
+ }
41
+ function str(value, fallback) {
42
+ return typeof value === "string" ? value : fallback;
43
+ }
44
+ function lang(value) {
45
+ if (value === "en" || value === "de" || value === "both")
46
+ return value;
47
+ return "both";
48
+ }
49
+ export function resolveConfig(pluginConfig) {
50
+ const raw = pluginConfig ?? {};
51
+ const tt = (raw.threadTracker ?? {});
52
+ const dt = (raw.decisionTracker ?? {});
53
+ const bc = (raw.bootContext ?? {});
54
+ const pc = (raw.preCompaction ?? {});
55
+ const nr = (raw.narrative ?? {});
56
+ const pt = (raw.patterns ?? {});
57
+ return {
58
+ enabled: bool(raw.enabled, DEFAULTS.enabled),
59
+ workspace: str(raw.workspace, DEFAULTS.workspace),
60
+ threadTracker: {
61
+ enabled: bool(tt.enabled, DEFAULTS.threadTracker.enabled),
62
+ pruneDays: int(tt.pruneDays, DEFAULTS.threadTracker.pruneDays),
63
+ maxThreads: int(tt.maxThreads, DEFAULTS.threadTracker.maxThreads),
64
+ },
65
+ decisionTracker: {
66
+ enabled: bool(dt.enabled, DEFAULTS.decisionTracker.enabled),
67
+ maxDecisions: int(dt.maxDecisions, DEFAULTS.decisionTracker.maxDecisions),
68
+ dedupeWindowHours: int(dt.dedupeWindowHours, DEFAULTS.decisionTracker.dedupeWindowHours),
69
+ },
70
+ bootContext: {
71
+ enabled: bool(bc.enabled, DEFAULTS.bootContext.enabled),
72
+ maxChars: int(bc.maxChars, DEFAULTS.bootContext.maxChars),
73
+ onSessionStart: bool(bc.onSessionStart, DEFAULTS.bootContext.onSessionStart),
74
+ maxThreadsInBoot: int(bc.maxThreadsInBoot, DEFAULTS.bootContext.maxThreadsInBoot),
75
+ maxDecisionsInBoot: int(bc.maxDecisionsInBoot, DEFAULTS.bootContext.maxDecisionsInBoot),
76
+ decisionRecencyDays: int(bc.decisionRecencyDays, DEFAULTS.bootContext.decisionRecencyDays),
77
+ },
78
+ preCompaction: {
79
+ enabled: bool(pc.enabled, DEFAULTS.preCompaction.enabled),
80
+ maxSnapshotMessages: int(pc.maxSnapshotMessages, DEFAULTS.preCompaction.maxSnapshotMessages),
81
+ },
82
+ narrative: {
83
+ enabled: bool(nr.enabled, DEFAULTS.narrative.enabled),
84
+ },
85
+ patterns: {
86
+ language: lang(pt.language),
87
+ },
88
+ };
89
+ }
90
+ /**
91
+ * Resolve workspace directory from config, hook context, env, or cwd.
92
+ */
93
+ export function resolveWorkspace(config, ctx) {
94
+ if (config.workspace)
95
+ return config.workspace;
96
+ if (ctx?.workspaceDir)
97
+ return ctx.workspaceDir;
98
+ return process.env.WORKSPACE_DIR ?? process.cwd();
99
+ }
100
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}