pi-continuous-learning 0.3.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 (153) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +326 -0
  3. package/dist/active-instincts.d.ts +4 -0
  4. package/dist/active-instincts.d.ts.map +1 -0
  5. package/dist/active-instincts.js +11 -0
  6. package/dist/active-instincts.js.map +1 -0
  7. package/dist/agents-md.d.ts +12 -0
  8. package/dist/agents-md.d.ts.map +1 -0
  9. package/dist/agents-md.js +23 -0
  10. package/dist/agents-md.js.map +1 -0
  11. package/dist/cli/analyze-prompt.d.ts +2 -0
  12. package/dist/cli/analyze-prompt.d.ts.map +1 -0
  13. package/dist/cli/analyze-prompt.js +72 -0
  14. package/dist/cli/analyze-prompt.js.map +1 -0
  15. package/dist/cli/analyze.d.ts +3 -0
  16. package/dist/cli/analyze.d.ts.map +1 -0
  17. package/dist/cli/analyze.js +214 -0
  18. package/dist/cli/analyze.js.map +1 -0
  19. package/dist/confidence.d.ts +25 -0
  20. package/dist/confidence.d.ts.map +1 -0
  21. package/dist/confidence.js +77 -0
  22. package/dist/confidence.js.map +1 -0
  23. package/dist/config.d.ts +19 -0
  24. package/dist/config.d.ts.map +1 -0
  25. package/dist/config.js +89 -0
  26. package/dist/config.js.map +1 -0
  27. package/dist/error-logger.d.ts +34 -0
  28. package/dist/error-logger.d.ts.map +1 -0
  29. package/dist/error-logger.js +102 -0
  30. package/dist/error-logger.js.map +1 -0
  31. package/dist/index.d.ts +10 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +118 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/instinct-decay.d.ts +39 -0
  36. package/dist/instinct-decay.d.ts.map +1 -0
  37. package/dist/instinct-decay.js +93 -0
  38. package/dist/instinct-decay.js.map +1 -0
  39. package/dist/instinct-evolve.d.ts +5 -0
  40. package/dist/instinct-evolve.d.ts.map +1 -0
  41. package/dist/instinct-evolve.js +24 -0
  42. package/dist/instinct-evolve.js.map +1 -0
  43. package/dist/instinct-export.d.ts +40 -0
  44. package/dist/instinct-export.d.ts.map +1 -0
  45. package/dist/instinct-export.js +94 -0
  46. package/dist/instinct-export.js.map +1 -0
  47. package/dist/instinct-import.d.ts +50 -0
  48. package/dist/instinct-import.d.ts.map +1 -0
  49. package/dist/instinct-import.js +168 -0
  50. package/dist/instinct-import.js.map +1 -0
  51. package/dist/instinct-injector.d.ts +39 -0
  52. package/dist/instinct-injector.d.ts.map +1 -0
  53. package/dist/instinct-injector.js +89 -0
  54. package/dist/instinct-injector.js.map +1 -0
  55. package/dist/instinct-loader.d.ts +37 -0
  56. package/dist/instinct-loader.d.ts.map +1 -0
  57. package/dist/instinct-loader.js +96 -0
  58. package/dist/instinct-loader.js.map +1 -0
  59. package/dist/instinct-parser.d.ts +28 -0
  60. package/dist/instinct-parser.d.ts.map +1 -0
  61. package/dist/instinct-parser.js +143 -0
  62. package/dist/instinct-parser.js.map +1 -0
  63. package/dist/instinct-projects.d.ts +32 -0
  64. package/dist/instinct-projects.d.ts.map +1 -0
  65. package/dist/instinct-projects.js +96 -0
  66. package/dist/instinct-projects.js.map +1 -0
  67. package/dist/instinct-promote.d.ts +51 -0
  68. package/dist/instinct-promote.d.ts.map +1 -0
  69. package/dist/instinct-promote.js +169 -0
  70. package/dist/instinct-promote.js.map +1 -0
  71. package/dist/instinct-status.d.ts +39 -0
  72. package/dist/instinct-status.d.ts.map +1 -0
  73. package/dist/instinct-status.js +108 -0
  74. package/dist/instinct-status.js.map +1 -0
  75. package/dist/instinct-store.d.ts +30 -0
  76. package/dist/instinct-store.d.ts.map +1 -0
  77. package/dist/instinct-store.js +118 -0
  78. package/dist/instinct-store.js.map +1 -0
  79. package/dist/instinct-tools.d.ts +161 -0
  80. package/dist/instinct-tools.d.ts.map +1 -0
  81. package/dist/instinct-tools.js +240 -0
  82. package/dist/instinct-tools.js.map +1 -0
  83. package/dist/observations.d.ts +22 -0
  84. package/dist/observations.d.ts.map +1 -0
  85. package/dist/observations.js +62 -0
  86. package/dist/observations.js.map +1 -0
  87. package/dist/observer-guard.d.ts +3 -0
  88. package/dist/observer-guard.d.ts.map +1 -0
  89. package/dist/observer-guard.js +13 -0
  90. package/dist/observer-guard.js.map +1 -0
  91. package/dist/project.d.ts +16 -0
  92. package/dist/project.d.ts.map +1 -0
  93. package/dist/project.js +59 -0
  94. package/dist/project.js.map +1 -0
  95. package/dist/prompt-observer.d.ts +25 -0
  96. package/dist/prompt-observer.d.ts.map +1 -0
  97. package/dist/prompt-observer.js +63 -0
  98. package/dist/prompt-observer.js.map +1 -0
  99. package/dist/prompts/analyzer-user.d.ts +38 -0
  100. package/dist/prompts/analyzer-user.d.ts.map +1 -0
  101. package/dist/prompts/analyzer-user.js +105 -0
  102. package/dist/prompts/analyzer-user.js.map +1 -0
  103. package/dist/prompts/evolve-prompt.d.ts +3 -0
  104. package/dist/prompts/evolve-prompt.d.ts.map +1 -0
  105. package/dist/prompts/evolve-prompt.js +51 -0
  106. package/dist/prompts/evolve-prompt.js.map +1 -0
  107. package/dist/scrubber.d.ts +9 -0
  108. package/dist/scrubber.d.ts.map +1 -0
  109. package/dist/scrubber.js +40 -0
  110. package/dist/scrubber.js.map +1 -0
  111. package/dist/storage.d.ts +22 -0
  112. package/dist/storage.d.ts.map +1 -0
  113. package/dist/storage.js +71 -0
  114. package/dist/storage.js.map +1 -0
  115. package/dist/tool-observer.d.ts +32 -0
  116. package/dist/tool-observer.d.ts.map +1 -0
  117. package/dist/tool-observer.js +77 -0
  118. package/dist/tool-observer.js.map +1 -0
  119. package/dist/types.d.ts +64 -0
  120. package/dist/types.d.ts.map +1 -0
  121. package/dist/types.js +6 -0
  122. package/dist/types.js.map +1 -0
  123. package/package.json +66 -0
  124. package/src/active-instincts.ts +13 -0
  125. package/src/agents-md.ts +23 -0
  126. package/src/cli/analyze-prompt.ts +71 -0
  127. package/src/cli/analyze.ts +286 -0
  128. package/src/confidence.ts +103 -0
  129. package/src/config.ts +111 -0
  130. package/src/error-logger.ts +130 -0
  131. package/src/index.ts +144 -0
  132. package/src/instinct-decay.ts +117 -0
  133. package/src/instinct-evolve.ts +44 -0
  134. package/src/instinct-export.ts +138 -0
  135. package/src/instinct-import.ts +260 -0
  136. package/src/instinct-injector.ts +128 -0
  137. package/src/instinct-loader.ts +146 -0
  138. package/src/instinct-parser.ts +171 -0
  139. package/src/instinct-projects.ts +119 -0
  140. package/src/instinct-promote.ts +231 -0
  141. package/src/instinct-status.ts +135 -0
  142. package/src/instinct-store.ts +149 -0
  143. package/src/instinct-tools.ts +340 -0
  144. package/src/observations.ts +82 -0
  145. package/src/observer-guard.ts +14 -0
  146. package/src/project.ts +70 -0
  147. package/src/prompt-observer.ts +92 -0
  148. package/src/prompts/analyzer-user.ts +156 -0
  149. package/src/prompts/evolve-prompt.ts +71 -0
  150. package/src/scrubber.ts +42 -0
  151. package/src/storage.ts +91 -0
  152. package/src/tool-observer.ts +114 -0
  153. package/src/types.ts +90 -0
@@ -0,0 +1,214 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, readFileSync, statSync, writeFileSync, unlinkSync, } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { createAgentSession, SessionManager, AuthStorage, ModelRegistry, DefaultResourceLoader, } from "@mariozechner/pi-coding-agent";
5
+ import { getModel } from "@mariozechner/pi-ai";
6
+ import { loadConfig, DEFAULT_CONFIG } from "../config.js";
7
+ import { getBaseDir, getProjectsRegistryPath, getObservationsPath, getProjectDir, } from "../storage.js";
8
+ import { countObservations } from "../observations.js";
9
+ import { runDecayPass } from "../instinct-decay.js";
10
+ import { buildAnalyzerUserPrompt, tailObservationsSince } from "../prompts/analyzer-user.js";
11
+ import { buildAnalyzerSystemPrompt } from "./analyze-prompt.js";
12
+ import { createInstinctListTool, createInstinctReadTool, createInstinctWriteTool, createInstinctDeleteTool, } from "../instinct-tools.js";
13
+ import { readAgentsMd } from "../agents-md.js";
14
+ import { homedir } from "node:os";
15
+ // ---------------------------------------------------------------------------
16
+ // Lockfile guard — ensures only one instance runs at a time
17
+ // ---------------------------------------------------------------------------
18
+ const LOCKFILE_NAME = "analyze.lock";
19
+ const LOCK_STALE_MS = 10 * 60 * 1000; // 10 minutes — stale lock threshold
20
+ function getLockfilePath(baseDir) {
21
+ return join(baseDir, LOCKFILE_NAME);
22
+ }
23
+ function acquireLock(baseDir) {
24
+ const lockPath = getLockfilePath(baseDir);
25
+ if (existsSync(lockPath)) {
26
+ try {
27
+ const content = readFileSync(lockPath, "utf-8");
28
+ const lock = JSON.parse(content);
29
+ const age = Date.now() - new Date(lock.started_at).getTime();
30
+ // Check if the owning process is still alive
31
+ try {
32
+ process.kill(lock.pid, 0); // signal 0 = existence check, no actual signal
33
+ if (age < LOCK_STALE_MS) {
34
+ return false; // Process alive and lock is fresh
35
+ }
36
+ // Process alive but lock is stale — treat as abandoned
37
+ }
38
+ catch {
39
+ // Process is dead — lock is orphaned, safe to take over
40
+ }
41
+ }
42
+ catch {
43
+ // Malformed lockfile — remove and proceed
44
+ }
45
+ }
46
+ writeFileSync(lockPath, JSON.stringify({ pid: process.pid, started_at: new Date().toISOString() }), "utf-8");
47
+ return true;
48
+ }
49
+ function releaseLock(baseDir) {
50
+ const lockPath = getLockfilePath(baseDir);
51
+ try {
52
+ if (existsSync(lockPath))
53
+ unlinkSync(lockPath);
54
+ }
55
+ catch {
56
+ // Best effort — don't crash on cleanup
57
+ }
58
+ }
59
+ // ---------------------------------------------------------------------------
60
+ // Global timeout
61
+ // ---------------------------------------------------------------------------
62
+ const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes total
63
+ function startGlobalTimeout(timeoutMs) {
64
+ setTimeout(() => {
65
+ console.error("[analyze] Global timeout reached. Exiting.");
66
+ process.exit(2);
67
+ }, timeoutMs).unref();
68
+ }
69
+ function loadProjectsRegistry(baseDir) {
70
+ const path = getProjectsRegistryPath(baseDir);
71
+ if (!existsSync(path))
72
+ return {};
73
+ try {
74
+ return JSON.parse(readFileSync(path, "utf-8"));
75
+ }
76
+ catch {
77
+ return {};
78
+ }
79
+ }
80
+ function loadProjectMeta(projectId, baseDir) {
81
+ const metaPath = join(getProjectDir(projectId, baseDir), "project.json");
82
+ if (!existsSync(metaPath))
83
+ return {};
84
+ try {
85
+ return JSON.parse(readFileSync(metaPath, "utf-8"));
86
+ }
87
+ catch {
88
+ return {};
89
+ }
90
+ }
91
+ function saveProjectMeta(projectId, meta, baseDir) {
92
+ const metaPath = join(getProjectDir(projectId, baseDir), "project.json");
93
+ writeFileSync(metaPath, JSON.stringify(meta, null, 2), "utf-8");
94
+ }
95
+ function hasNewObservations(projectId, meta, baseDir) {
96
+ const obsPath = getObservationsPath(projectId, baseDir);
97
+ if (!existsSync(obsPath))
98
+ return false;
99
+ const stat = statSync(obsPath);
100
+ if (meta.last_analyzed_at) {
101
+ const lastAnalyzed = new Date(meta.last_analyzed_at).getTime();
102
+ if (stat.mtimeMs <= lastAnalyzed)
103
+ return false;
104
+ }
105
+ return true;
106
+ }
107
+ async function analyzeProject(project, config, baseDir) {
108
+ const meta = loadProjectMeta(project.id, baseDir);
109
+ if (!hasNewObservations(project.id, meta, baseDir))
110
+ return false;
111
+ const obsPath = getObservationsPath(project.id, baseDir);
112
+ const sinceLineCount = meta.last_observation_line_count ?? 0;
113
+ const { lines: newObsLines, totalLineCount } = tailObservationsSince(obsPath, sinceLineCount);
114
+ if (newObsLines.length === 0)
115
+ return false;
116
+ const obsCount = countObservations(project.id, baseDir);
117
+ if (obsCount < config.min_observations_to_analyze)
118
+ return false;
119
+ console.log(`[analyze] Processing ${project.name} (${project.id}): ${newObsLines.length} new observations (${obsCount} total)`);
120
+ runDecayPass(project.id, baseDir);
121
+ const instinctsDir = join(getProjectDir(project.id, baseDir), "instincts", "personal");
122
+ const agentsMdProject = readAgentsMd(join(project.root, "AGENTS.md"));
123
+ const agentsMdGlobal = readAgentsMd(join(homedir(), ".pi", "agent", "AGENTS.md"));
124
+ let installedSkills = [];
125
+ try {
126
+ const { loadSkills } = await import("@mariozechner/pi-coding-agent");
127
+ const result = loadSkills({ cwd: project.root });
128
+ installedSkills = result.skills.map((s) => ({
129
+ name: s.name,
130
+ description: s.description,
131
+ }));
132
+ }
133
+ catch {
134
+ // Skills loading is best-effort — continue without them
135
+ }
136
+ const userPrompt = buildAnalyzerUserPrompt(obsPath, instinctsDir, project, {
137
+ agentsMdProject,
138
+ agentsMdGlobal,
139
+ installedSkills,
140
+ observationLines: newObsLines,
141
+ });
142
+ const authStorage = AuthStorage.create();
143
+ const modelRegistry = new ModelRegistry(authStorage);
144
+ const modelId = (config.model || DEFAULT_CONFIG.model);
145
+ const model = getModel("anthropic", modelId);
146
+ const customTools = [
147
+ createInstinctListTool(project.id, baseDir),
148
+ createInstinctReadTool(project.id, baseDir),
149
+ createInstinctWriteTool(project.id, project.name, baseDir),
150
+ createInstinctDeleteTool(project.id, baseDir),
151
+ ];
152
+ const loader = new DefaultResourceLoader({
153
+ systemPromptOverride: () => buildAnalyzerSystemPrompt(),
154
+ });
155
+ await loader.reload();
156
+ const { session } = await createAgentSession({
157
+ model,
158
+ authStorage,
159
+ modelRegistry,
160
+ sessionManager: SessionManager.inMemory(),
161
+ customTools,
162
+ resourceLoader: loader,
163
+ });
164
+ try {
165
+ await session.prompt(userPrompt);
166
+ }
167
+ finally {
168
+ session.dispose();
169
+ }
170
+ saveProjectMeta(project.id, { ...meta, last_analyzed_at: new Date().toISOString(), last_observation_line_count: totalLineCount }, baseDir);
171
+ console.log(`[analyze] Completed ${project.name}`);
172
+ return true;
173
+ }
174
+ // ---------------------------------------------------------------------------
175
+ // Main
176
+ // ---------------------------------------------------------------------------
177
+ async function main() {
178
+ const baseDir = getBaseDir();
179
+ if (!acquireLock(baseDir)) {
180
+ console.log("[analyze] Another instance is already running. Exiting.");
181
+ process.exit(0);
182
+ }
183
+ startGlobalTimeout(DEFAULT_TIMEOUT_MS);
184
+ try {
185
+ const config = loadConfig();
186
+ const registry = loadProjectsRegistry(baseDir);
187
+ const projects = Object.values(registry);
188
+ if (projects.length === 0) {
189
+ console.log("[analyze] No projects registered. Use pi with the continuous-learning extension first.");
190
+ return;
191
+ }
192
+ let processed = 0;
193
+ for (const project of projects) {
194
+ try {
195
+ const didRun = await analyzeProject(project, config, baseDir);
196
+ if (didRun)
197
+ processed++;
198
+ }
199
+ catch (err) {
200
+ console.error(`[analyze] Error processing ${project.name}: ${String(err)}`);
201
+ }
202
+ }
203
+ console.log(`[analyze] Done. Processed ${processed}/${projects.length} project(s).`);
204
+ }
205
+ finally {
206
+ releaseLock(baseDir);
207
+ }
208
+ }
209
+ main().catch((err) => {
210
+ releaseLock(getBaseDir());
211
+ console.error(`[analyze] Fatal error: ${String(err)}`);
212
+ process.exit(1);
213
+ });
214
+ //# sourceMappingURL=analyze.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/cli/analyze.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Pure functions for instinct confidence scoring.
3
+ * No I/O - all functions take plain values and return plain values.
4
+ */
5
+ export type FeedbackOutcome = "confirmed" | "contradicted" | "inactive";
6
+ export interface ConfidenceResult {
7
+ confidence: number;
8
+ flaggedForRemoval: boolean;
9
+ }
10
+ /**
11
+ * Returns the initial confidence score for a newly discovered instinct
12
+ * based on how many observations support it.
13
+ */
14
+ export declare function initialConfidence(observationCount: number): number;
15
+ /**
16
+ * Adjusts confidence based on a feedback outcome from the observer loop.
17
+ * Returns the clamped confidence and a flag indicating if removal is warranted.
18
+ */
19
+ export declare function adjustConfidence(current: number, outcome: FeedbackOutcome): ConfidenceResult;
20
+ /**
21
+ * Applies passive time-based decay of -0.02 per week since lastUpdated.
22
+ * Future lastUpdated values produce zero decay.
23
+ */
24
+ export declare function applyPassiveDecay(confidence: number, lastUpdated: string): ConfidenceResult;
25
+ //# sourceMappingURL=confidence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confidence.d.ts","sourceRoot":"","sources":["../src/confidence.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgCH,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,cAAc,GAAG,UAAU,CAAC;AAExE,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAmBD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAKlE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,eAAe,GACvB,gBAAgB,CAQlB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,gBAAgB,CAQlB"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Pure functions for instinct confidence scoring.
3
+ * No I/O - all functions take plain values and return plain values.
4
+ */
5
+ // ---------------------------------------------------------------------------
6
+ // Constants
7
+ // ---------------------------------------------------------------------------
8
+ const CLAMP_MIN = 0.1;
9
+ const CLAMP_MAX = 0.9;
10
+ // initialConfidence brackets
11
+ const INITIAL_LOW = 0.3;
12
+ const INITIAL_MED = 0.5;
13
+ const INITIAL_HIGH = 0.7;
14
+ const INITIAL_VERY_HIGH = 0.85;
15
+ const OBS_BRACKET_LOW_MAX = 2;
16
+ const OBS_BRACKET_MED_MAX = 5;
17
+ const OBS_BRACKET_HIGH_MAX = 10;
18
+ // adjustConfidence deltas
19
+ const DELTA_CONFIRMED = 0.05;
20
+ const DELTA_CONTRADICTED = -0.15;
21
+ const DELTA_INACTIVE = 0;
22
+ // applyPassiveDecay
23
+ const DECAY_PER_WEEK = 0.02;
24
+ const MS_PER_WEEK = 7 * 24 * 60 * 60 * 1000;
25
+ // ---------------------------------------------------------------------------
26
+ // Helpers
27
+ // ---------------------------------------------------------------------------
28
+ function clamp(value) {
29
+ return Math.max(CLAMP_MIN, Math.min(CLAMP_MAX, value));
30
+ }
31
+ function toResult(raw) {
32
+ const flaggedForRemoval = raw < CLAMP_MIN;
33
+ return { confidence: clamp(raw), flaggedForRemoval };
34
+ }
35
+ // ---------------------------------------------------------------------------
36
+ // Public API
37
+ // ---------------------------------------------------------------------------
38
+ /**
39
+ * Returns the initial confidence score for a newly discovered instinct
40
+ * based on how many observations support it.
41
+ */
42
+ export function initialConfidence(observationCount) {
43
+ if (observationCount <= OBS_BRACKET_LOW_MAX)
44
+ return INITIAL_LOW;
45
+ if (observationCount <= OBS_BRACKET_MED_MAX)
46
+ return INITIAL_MED;
47
+ if (observationCount <= OBS_BRACKET_HIGH_MAX)
48
+ return INITIAL_HIGH;
49
+ return INITIAL_VERY_HIGH;
50
+ }
51
+ /**
52
+ * Adjusts confidence based on a feedback outcome from the observer loop.
53
+ * Returns the clamped confidence and a flag indicating if removal is warranted.
54
+ */
55
+ export function adjustConfidence(current, outcome) {
56
+ const deltas = {
57
+ confirmed: DELTA_CONFIRMED,
58
+ contradicted: DELTA_CONTRADICTED,
59
+ inactive: DELTA_INACTIVE,
60
+ };
61
+ const raw = current + deltas[outcome];
62
+ return toResult(raw);
63
+ }
64
+ /**
65
+ * Applies passive time-based decay of -0.02 per week since lastUpdated.
66
+ * Future lastUpdated values produce zero decay.
67
+ */
68
+ export function applyPassiveDecay(confidence, lastUpdated) {
69
+ const now = Date.now();
70
+ const updatedAt = new Date(lastUpdated).getTime();
71
+ const elapsedMs = Math.max(0, now - updatedAt);
72
+ const weeksElapsed = elapsedMs / MS_PER_WEEK;
73
+ const decay = weeksElapsed * DECAY_PER_WEEK;
74
+ const raw = confidence - decay;
75
+ return toResult(raw);
76
+ }
77
+ //# sourceMappingURL=confidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confidence.js","sourceRoot":"","sources":["../src/confidence.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,MAAM,SAAS,GAAG,GAAG,CAAC;AAEtB,6BAA6B;AAC7B,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,YAAY,GAAG,GAAG,CAAC;AACzB,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAE/B,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAC9B,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAC9B,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEhC,0BAA0B;AAC1B,MAAM,eAAe,GAAG,IAAI,CAAC;AAC7B,MAAM,kBAAkB,GAAG,CAAC,IAAI,CAAC;AACjC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB,oBAAoB;AACpB,MAAM,cAAc,GAAG,IAAI,CAAC;AAC5B,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAa5C,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,SAAS,KAAK,CAAC,KAAa;IAC1B,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW;IAC3B,MAAM,iBAAiB,GAAG,GAAG,GAAG,SAAS,CAAC;IAC1C,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,iBAAiB,EAAE,CAAC;AACvD,CAAC;AAED,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,gBAAwB;IACxD,IAAI,gBAAgB,IAAI,mBAAmB;QAAE,OAAO,WAAW,CAAC;IAChE,IAAI,gBAAgB,IAAI,mBAAmB;QAAE,OAAO,WAAW,CAAC;IAChE,IAAI,gBAAgB,IAAI,oBAAoB;QAAE,OAAO,YAAY,CAAC;IAClE,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAe,EACf,OAAwB;IAExB,MAAM,MAAM,GAAoC;QAC9C,SAAS,EAAE,eAAe;QAC1B,YAAY,EAAE,kBAAkB;QAChC,QAAQ,EAAE,cAAc;KACzB,CAAC;IACF,MAAM,GAAG,GAAG,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IACtC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;AACvB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAAkB,EAClB,WAAmB;IAEnB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC;IAClD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,SAAS,CAAC,CAAC;IAC/C,MAAM,YAAY,GAAG,SAAS,GAAG,WAAW,CAAC;IAC7C,MAAM,KAAK,GAAG,YAAY,GAAG,cAAc,CAAC;IAC5C,MAAM,GAAG,GAAG,UAAU,GAAG,KAAK,CAAC;IAC/B,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;AACvB,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Configuration module for pi-continuous-learning.
3
+ * Loads user settings from ~/.pi/continuous-learning/config.json with defaults.
4
+ */
5
+ import type { Config } from "./types.js";
6
+ /**
7
+ * Maps instinct domain names to human-readable purposes.
8
+ * Used by findSkillShadows() to detect when an instinct is covered by an installed Pi skill.
9
+ */
10
+ export declare const SKILL_DOMAINS: Record<string, string>;
11
+ export declare const CONFIG_PATH: string;
12
+ export declare const DEFAULT_CONFIG: Config;
13
+ /**
14
+ * Loads config from ~/.pi/continuous-learning/config.json.
15
+ * Returns defaults when file is absent or contains invalid JSON.
16
+ * Merges partial overrides with defaults (overrides win).
17
+ */
18
+ export declare function loadConfig(): Config;
19
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAMzC;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAWhD,CAAC;AAEF,eAAO,MAAM,WAAW,QAKvB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,MAW5B,CAAC;AA2BF;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,MAAM,CA2BnC"}
package/dist/config.js ADDED
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Configuration module for pi-continuous-learning.
3
+ * Loads user settings from ~/.pi/continuous-learning/config.json with defaults.
4
+ */
5
+ import * as fs from "node:fs";
6
+ import * as os from "node:os";
7
+ import * as path from "node:path";
8
+ import { Type } from "@sinclair/typebox";
9
+ import { Value } from "@sinclair/typebox/value";
10
+ // ---------------------------------------------------------------------------
11
+ // Constants
12
+ // ---------------------------------------------------------------------------
13
+ /**
14
+ * Maps instinct domain names to human-readable purposes.
15
+ * Used by findSkillShadows() to detect when an instinct is covered by an installed Pi skill.
16
+ */
17
+ export const SKILL_DOMAINS = {
18
+ git: "version control and git workflows",
19
+ testing: "test writing and test frameworks",
20
+ debugging: "error analysis and debugging",
21
+ workflow: "development workflow and automation",
22
+ typescript: "TypeScript language and type system",
23
+ css: "CSS and styling",
24
+ design: "UI design and component patterns",
25
+ security: "security practices and vulnerability prevention",
26
+ performance: "performance optimization",
27
+ documentation: "documentation writing and standards",
28
+ };
29
+ export const CONFIG_PATH = path.join(os.homedir(), ".pi", "continuous-learning", "config.json");
30
+ export const DEFAULT_CONFIG = {
31
+ run_interval_minutes: 5,
32
+ min_observations_to_analyze: 20,
33
+ min_confidence: 0.5,
34
+ max_instincts: 20,
35
+ max_injection_chars: 4000,
36
+ model: "claude-haiku-4-5",
37
+ timeout_seconds: 120,
38
+ active_hours_start: 8,
39
+ active_hours_end: 23,
40
+ max_idle_seconds: 1800,
41
+ };
42
+ // ---------------------------------------------------------------------------
43
+ // TypeBox schema for partial config overrides (runtime validation)
44
+ // ---------------------------------------------------------------------------
45
+ const PartialConfigSchema = Type.Partial(Type.Object({
46
+ run_interval_minutes: Type.Number(),
47
+ min_observations_to_analyze: Type.Number(),
48
+ min_confidence: Type.Number(),
49
+ max_instincts: Type.Number(),
50
+ max_injection_chars: Type.Number(),
51
+ model: Type.String(),
52
+ timeout_seconds: Type.Number(),
53
+ active_hours_start: Type.Number(),
54
+ active_hours_end: Type.Number(),
55
+ max_idle_seconds: Type.Number(),
56
+ }));
57
+ // ---------------------------------------------------------------------------
58
+ // loadConfig
59
+ // ---------------------------------------------------------------------------
60
+ /**
61
+ * Loads config from ~/.pi/continuous-learning/config.json.
62
+ * Returns defaults when file is absent or contains invalid JSON.
63
+ * Merges partial overrides with defaults (overrides win).
64
+ */
65
+ export function loadConfig() {
66
+ if (!fs.existsSync(CONFIG_PATH)) {
67
+ return { ...DEFAULT_CONFIG };
68
+ }
69
+ let raw;
70
+ try {
71
+ raw = fs.readFileSync(CONFIG_PATH, "utf-8");
72
+ }
73
+ catch (err) {
74
+ console.warn(`[pi-continuous-learning] Failed to read config.json: ${String(err)}`);
75
+ return { ...DEFAULT_CONFIG };
76
+ }
77
+ let parsed;
78
+ try {
79
+ parsed = JSON.parse(raw);
80
+ }
81
+ catch (err) {
82
+ console.warn(`[pi-continuous-learning] Invalid JSON in config.json: ${String(err)}. Using defaults.`);
83
+ return { ...DEFAULT_CONFIG };
84
+ }
85
+ // Validate and extract only known config fields (runtime boundary check)
86
+ const cleaned = Value.Clean(PartialConfigSchema, parsed);
87
+ return { ...DEFAULT_CONFIG, ...cleaned };
88
+ }
89
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Error logging utility for pi-continuous-learning.
3
+ * Writes structured error entries to projects/<id>/analyzer.log.
4
+ * All write failures are silently swallowed - the logger must never throw.
5
+ */
6
+ /**
7
+ * Returns the absolute path to the analyzer log for the given project.
8
+ * Exported for testing.
9
+ */
10
+ export declare function getLogPath(projectId: string, baseDir?: string): string;
11
+ /**
12
+ * Logs an error to `projects/<projectId>/analyzer.log`.
13
+ *
14
+ * When `projectId` is null (e.g. session_start failed before project detection),
15
+ * falls back to `console.warn` only.
16
+ *
17
+ * Never throws - all I/O failures are silently swallowed.
18
+ */
19
+ export declare function logError(projectId: string | null, context: string, error: unknown, baseDir?: string): void;
20
+ /**
21
+ * Logs a warning (non-error) message to the analyzer log.
22
+ * Used for subprocess stderr output and other non-fatal warnings.
23
+ *
24
+ * Never throws - all I/O failures are silently swallowed.
25
+ */
26
+ export declare function logWarning(projectId: string | null, context: string, message: string, baseDir?: string): void;
27
+ /**
28
+ * Logs an informational message to the analyzer log.
29
+ * Used for tracking analyzer lifecycle events (started, completed, skipped).
30
+ *
31
+ * Never throws - all I/O failures are silently swallowed.
32
+ */
33
+ export declare function logInfo(projectId: string | null, context: string, message: string, baseDir?: string): void;
34
+ //# sourceMappingURL=error-logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-logger.d.ts","sourceRoot":"","sources":["../src/error-logger.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAiBH;;;GAGG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtE;AAgBD;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CACtB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,MAAM,GACf,IAAI,CAgBN;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf,IAAI,CAgBN;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CACrB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf,IAAI,CAeN"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Error logging utility for pi-continuous-learning.
3
+ * Writes structured error entries to projects/<id>/analyzer.log.
4
+ * All write failures are silently swallowed - the logger must never throw.
5
+ */
6
+ import { appendFileSync, mkdirSync } from "node:fs";
7
+ import { join, dirname } from "node:path";
8
+ import { getProjectDir, getBaseDir } from "./storage.js";
9
+ // ---------------------------------------------------------------------------
10
+ // Constants
11
+ // ---------------------------------------------------------------------------
12
+ const LOG_FILENAME = "analyzer.log";
13
+ const PREFIX = "[pi-continuous-learning]";
14
+ // ---------------------------------------------------------------------------
15
+ // Helpers
16
+ // ---------------------------------------------------------------------------
17
+ /**
18
+ * Returns the absolute path to the analyzer log for the given project.
19
+ * Exported for testing.
20
+ */
21
+ export function getLogPath(projectId, baseDir) {
22
+ return join(getProjectDir(projectId, baseDir ?? getBaseDir()), LOG_FILENAME);
23
+ }
24
+ function formatError(context, error) {
25
+ const timestamp = new Date().toISOString();
26
+ const message = error instanceof Error ? error.message : String(error);
27
+ const stack = error instanceof Error && error.stack
28
+ ? `\nStack: ${error.stack}`
29
+ : "";
30
+ return `[${timestamp}] [${context}] Error: ${message}${stack}\n`;
31
+ }
32
+ // ---------------------------------------------------------------------------
33
+ // Public API
34
+ // ---------------------------------------------------------------------------
35
+ /**
36
+ * Logs an error to `projects/<projectId>/analyzer.log`.
37
+ *
38
+ * When `projectId` is null (e.g. session_start failed before project detection),
39
+ * falls back to `console.warn` only.
40
+ *
41
+ * Never throws - all I/O failures are silently swallowed.
42
+ */
43
+ export function logError(projectId, context, error, baseDir) {
44
+ const line = formatError(context, error);
45
+ if (projectId === null) {
46
+ console.warn(`${PREFIX} ${context}: ${line.trim()}`);
47
+ return;
48
+ }
49
+ const logPath = getLogPath(projectId, baseDir);
50
+ try {
51
+ mkdirSync(dirname(logPath), { recursive: true });
52
+ appendFileSync(logPath, line, "utf-8");
53
+ }
54
+ catch {
55
+ // Cannot log the logger failing - fall back to console
56
+ console.warn(`${PREFIX} ${context}: ${line.trim()}`);
57
+ }
58
+ }
59
+ /**
60
+ * Logs a warning (non-error) message to the analyzer log.
61
+ * Used for subprocess stderr output and other non-fatal warnings.
62
+ *
63
+ * Never throws - all I/O failures are silently swallowed.
64
+ */
65
+ export function logWarning(projectId, context, message, baseDir) {
66
+ const timestamp = new Date().toISOString();
67
+ const line = `[${timestamp}] [${context}] Warning: ${message}\n`;
68
+ if (projectId === null) {
69
+ console.warn(`${PREFIX} ${context}: ${message}`);
70
+ return;
71
+ }
72
+ const logPath = getLogPath(projectId, baseDir);
73
+ try {
74
+ mkdirSync(dirname(logPath), { recursive: true });
75
+ appendFileSync(logPath, line, "utf-8");
76
+ }
77
+ catch {
78
+ console.warn(`${PREFIX} ${context}: ${message}`);
79
+ }
80
+ }
81
+ /**
82
+ * Logs an informational message to the analyzer log.
83
+ * Used for tracking analyzer lifecycle events (started, completed, skipped).
84
+ *
85
+ * Never throws - all I/O failures are silently swallowed.
86
+ */
87
+ export function logInfo(projectId, context, message, baseDir) {
88
+ const timestamp = new Date().toISOString();
89
+ const line = `[${timestamp}] [${context}] Info: ${message}\n`;
90
+ if (projectId === null) {
91
+ return;
92
+ }
93
+ const logPath = getLogPath(projectId, baseDir);
94
+ try {
95
+ mkdirSync(dirname(logPath), { recursive: true });
96
+ appendFileSync(logPath, line, "utf-8");
97
+ }
98
+ catch {
99
+ // silently swallow
100
+ }
101
+ }
102
+ //# sourceMappingURL=error-logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-logger.js","sourceRoot":"","sources":["../src/error-logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Pi Continuous Learning Extension - Entry Point
3
+ *
4
+ * Observes coding sessions, records events as observations, and injects
5
+ * learned instincts into the agent's system prompt. Background analysis
6
+ * runs via a separate standalone script (src/cli/analyze.ts).
7
+ */
8
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
9
+ export default function (pi: ExtensionAPI): void;
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAA2B,MAAM,+BAA+B,CAAC;AAuB3F,MAAM,CAAC,OAAO,WAAW,EAAE,EAAE,YAAY,GAAG,IAAI,CAgH/C"}