fraim 2.0.100

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 (70) hide show
  1. package/README.md +445 -0
  2. package/bin/fraim.js +23 -0
  3. package/dist/src/cli/api/get-provider-client.js +41 -0
  4. package/dist/src/cli/api/provider-client.js +107 -0
  5. package/dist/src/cli/commands/add-ide.js +430 -0
  6. package/dist/src/cli/commands/add-provider.js +233 -0
  7. package/dist/src/cli/commands/doctor.js +149 -0
  8. package/dist/src/cli/commands/init-project.js +301 -0
  9. package/dist/src/cli/commands/list-overridable.js +184 -0
  10. package/dist/src/cli/commands/list.js +57 -0
  11. package/dist/src/cli/commands/login.js +84 -0
  12. package/dist/src/cli/commands/mcp.js +15 -0
  13. package/dist/src/cli/commands/migrate-project-fraim.js +42 -0
  14. package/dist/src/cli/commands/override.js +177 -0
  15. package/dist/src/cli/commands/setup.js +651 -0
  16. package/dist/src/cli/commands/sync.js +162 -0
  17. package/dist/src/cli/commands/test-mcp.js +171 -0
  18. package/dist/src/cli/doctor/check-runner.js +199 -0
  19. package/dist/src/cli/doctor/checks/global-setup-checks.js +220 -0
  20. package/dist/src/cli/doctor/checks/ide-config-checks.js +250 -0
  21. package/dist/src/cli/doctor/checks/mcp-connectivity-checks.js +381 -0
  22. package/dist/src/cli/doctor/checks/project-setup-checks.js +282 -0
  23. package/dist/src/cli/doctor/checks/scripts-checks.js +157 -0
  24. package/dist/src/cli/doctor/checks/workflow-checks.js +251 -0
  25. package/dist/src/cli/doctor/reporters/console-reporter.js +96 -0
  26. package/dist/src/cli/doctor/reporters/json-reporter.js +11 -0
  27. package/dist/src/cli/doctor/types.js +6 -0
  28. package/dist/src/cli/fraim.js +100 -0
  29. package/dist/src/cli/internal/device-flow-service.js +83 -0
  30. package/dist/src/cli/mcp/ide-formats.js +243 -0
  31. package/dist/src/cli/mcp/mcp-server-builder.js +48 -0
  32. package/dist/src/cli/mcp/mcp-server-registry.js +160 -0
  33. package/dist/src/cli/mcp/types.js +3 -0
  34. package/dist/src/cli/providers/local-provider-registry.js +166 -0
  35. package/dist/src/cli/providers/provider-registry.js +230 -0
  36. package/dist/src/cli/setup/auto-mcp-setup.js +331 -0
  37. package/dist/src/cli/setup/codex-local-config.js +37 -0
  38. package/dist/src/cli/setup/first-run.js +242 -0
  39. package/dist/src/cli/setup/ide-detector.js +179 -0
  40. package/dist/src/cli/setup/mcp-config-generator.js +192 -0
  41. package/dist/src/cli/setup/provider-prompts.js +339 -0
  42. package/dist/src/cli/utils/agent-adapters.js +126 -0
  43. package/dist/src/cli/utils/digest-utils.js +47 -0
  44. package/dist/src/cli/utils/fraim-gitignore.js +40 -0
  45. package/dist/src/cli/utils/platform-detection.js +258 -0
  46. package/dist/src/cli/utils/project-bootstrap.js +93 -0
  47. package/dist/src/cli/utils/remote-sync.js +315 -0
  48. package/dist/src/cli/utils/script-sync-utils.js +221 -0
  49. package/dist/src/cli/utils/version-utils.js +32 -0
  50. package/dist/src/core/ai-mentor.js +230 -0
  51. package/dist/src/core/config-loader.js +114 -0
  52. package/dist/src/core/config-writer.js +75 -0
  53. package/dist/src/core/types.js +23 -0
  54. package/dist/src/core/utils/git-utils.js +95 -0
  55. package/dist/src/core/utils/include-resolver.js +92 -0
  56. package/dist/src/core/utils/inheritance-parser.js +288 -0
  57. package/dist/src/core/utils/job-parser.js +176 -0
  58. package/dist/src/core/utils/local-registry-resolver.js +616 -0
  59. package/dist/src/core/utils/object-utils.js +11 -0
  60. package/dist/src/core/utils/project-fraim-migration.js +103 -0
  61. package/dist/src/core/utils/project-fraim-paths.js +38 -0
  62. package/dist/src/core/utils/provider-utils.js +18 -0
  63. package/dist/src/core/utils/server-startup.js +34 -0
  64. package/dist/src/core/utils/stub-generator.js +147 -0
  65. package/dist/src/core/utils/workflow-parser.js +174 -0
  66. package/dist/src/local-mcp-server/learning-context-builder.js +229 -0
  67. package/dist/src/local-mcp-server/stdio-server.js +1698 -0
  68. package/dist/src/local-mcp-server/usage-collector.js +264 -0
  69. package/index.js +85 -0
  70. package/package.json +139 -0
@@ -0,0 +1,229 @@
1
+ "use strict";
2
+ /**
3
+ * LearningContextBuilder builds the learning context section for a user.
4
+ *
5
+ * Lives in the local proxy so learning files are always read from the correct
6
+ * workspace root on the user's machine.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.buildLearningContextSection = buildLearningContextSection;
10
+ const fs_1 = require("fs");
11
+ const path_1 = require("path");
12
+ const project_fraim_paths_1 = require("../core/utils/project-fraim-paths");
13
+ const LEARNINGS_REL = (0, project_fraim_paths_1.getWorkspaceFraimDisplayPath)('personalized-employee/learnings').replace(/\/$/, '');
14
+ const DEFAULT_THRESHOLD = 3.0;
15
+ function getLearningsBase(workspaceRoot) {
16
+ return (0, path_1.join)(workspaceRoot, LEARNINGS_REL);
17
+ }
18
+ function getScoreThreshold(workspaceRoot) {
19
+ try {
20
+ const configPath = (0, project_fraim_paths_1.getWorkspaceConfigPath)(workspaceRoot);
21
+ if ((0, fs_1.existsSync)(configPath)) {
22
+ const config = JSON.parse((0, fs_1.readFileSync)(configPath, 'utf8'));
23
+ const t = config?.learning?.scoreThreshold;
24
+ if (typeof t === 'number' && t > 0)
25
+ return t;
26
+ }
27
+ }
28
+ catch {
29
+ // Fall through to default.
30
+ }
31
+ return DEFAULT_THRESHOLD;
32
+ }
33
+ function computeEffectiveScore(severity, lastSeenDate, recurrences, fileType) {
34
+ const baseScore = severity === 'P-HIGH' ? 8 : severity === 'P-MED' ? 5 : 3;
35
+ const halfLife = fileType === 'mistake-patterns' ? 90 : 180;
36
+ let daysSinceLastSeen = 0;
37
+ try {
38
+ const lastSeen = new Date(lastSeenDate);
39
+ const now = new Date();
40
+ daysSinceLastSeen = Math.max(0, (now.getTime() - lastSeen.getTime()) / (1000 * 60 * 60 * 24));
41
+ }
42
+ catch {
43
+ // Treat as fresh.
44
+ }
45
+ const decay = Math.pow(0.5, daysSinceLastSeen / halfLife);
46
+ const recurrenceBoost = Math.log2(Math.max(1, recurrences) + 1);
47
+ return baseScore * decay * recurrenceBoost;
48
+ }
49
+ function countMistakePatternEntries(filePath, threshold) {
50
+ if (!(0, fs_1.existsSync)(filePath))
51
+ return { active: 0, dormant: 0 };
52
+ try {
53
+ const content = (0, fs_1.readFileSync)(filePath, 'utf8');
54
+ const lines = content.split('\n');
55
+ let active = 0;
56
+ let dormant = 0;
57
+ let inEntry = false;
58
+ let currentSeverity = null;
59
+ let currentLastSeen = '';
60
+ let currentRecurrences = 1;
61
+ const processCurrentEntry = () => {
62
+ if (!currentSeverity)
63
+ return;
64
+ const score = computeEffectiveScore(currentSeverity, currentLastSeen, currentRecurrences, 'mistake-patterns');
65
+ if (score >= threshold)
66
+ active++;
67
+ else
68
+ dormant++;
69
+ };
70
+ for (const line of lines) {
71
+ const headerMatch = line.match(/^## \[(P-HIGH|P-MED|P-LOW)\]/);
72
+ if (headerMatch) {
73
+ processCurrentEntry();
74
+ inEntry = true;
75
+ currentSeverity = headerMatch[1];
76
+ currentLastSeen = '';
77
+ currentRecurrences = 1;
78
+ continue;
79
+ }
80
+ if (!inEntry)
81
+ continue;
82
+ const lastSeenMatch = line.match(/^\*\*Last seen\*\*:\s*(.+)/);
83
+ if (lastSeenMatch) {
84
+ currentLastSeen = lastSeenMatch[1].trim();
85
+ continue;
86
+ }
87
+ const recurrenceMatch = line.match(/^\*\*Recurrences\*\*:\s*(\d+)/);
88
+ if (recurrenceMatch) {
89
+ currentRecurrences = parseInt(recurrenceMatch[1], 10);
90
+ }
91
+ }
92
+ processCurrentEntry();
93
+ return { active, dormant };
94
+ }
95
+ catch {
96
+ return { active: 0, dormant: 0 };
97
+ }
98
+ }
99
+ function readFrontmatter(content) {
100
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
101
+ if (!match)
102
+ return {};
103
+ const frontmatter = {};
104
+ for (const line of match[1].split(/\r?\n/)) {
105
+ const separator = line.indexOf(':');
106
+ if (separator === -1)
107
+ continue;
108
+ const key = line.slice(0, separator).trim();
109
+ const value = line.slice(separator + 1).trim();
110
+ if (key) {
111
+ frontmatter[key] = value;
112
+ }
113
+ }
114
+ return frontmatter;
115
+ }
116
+ function isUnsynthesizedRetrospective(filePath) {
117
+ try {
118
+ const content = (0, fs_1.readFileSync)(filePath, 'utf8');
119
+ const frontmatter = readFrontmatter(content);
120
+ const synthesized = frontmatter.synthesized?.toLowerCase();
121
+ return synthesized !== 'true' && synthesized !== 'yes';
122
+ }
123
+ catch {
124
+ return false;
125
+ }
126
+ }
127
+ function buildLearningContextSection(workspaceRoot, userId, forJob) {
128
+ const learningsBase = getLearningsBase(workspaceRoot);
129
+ const threshold = getScoreThreshold(workspaceRoot);
130
+ const l2MistakePath = (0, path_1.join)(learningsBase, 'org-mistake-patterns.md');
131
+ const l2PrefPath = (0, path_1.join)(learningsBase, 'org-preferences.md');
132
+ const l2CoachPath = (0, path_1.join)(learningsBase, 'org-manager-coaching.md');
133
+ const l2MistakePresent = (0, fs_1.existsSync)(l2MistakePath);
134
+ const l2PrefPresent = (0, fs_1.existsSync)(l2PrefPath);
135
+ const l2CoachPresent = (0, fs_1.existsSync)(l2CoachPath);
136
+ const l2MistakeCounts = l2MistakePresent ? countMistakePatternEntries(l2MistakePath, threshold) : null;
137
+ const l1MistakePath = (0, path_1.join)(learningsBase, `${userId}-mistake-patterns.md`);
138
+ const l1PrefPath = (0, path_1.join)(learningsBase, `${userId}-preferences.md`);
139
+ const l1CoachPath = (0, path_1.join)(learningsBase, `${userId}-manager-coaching.md`);
140
+ const l1MistakePresent = (0, fs_1.existsSync)(l1MistakePath);
141
+ const l1PrefPresent = (0, fs_1.existsSync)(l1PrefPath);
142
+ const l1CoachPresent = (0, fs_1.existsSync)(l1CoachPath);
143
+ const l1MistakeCounts = l1MistakePresent ? countMistakePatternEntries(l1MistakePath, threshold) : null;
144
+ let l0CoachingCount = 0;
145
+ const rawPath = (0, path_1.join)(learningsBase, 'raw');
146
+ if ((0, fs_1.existsSync)(rawPath)) {
147
+ try {
148
+ l0CoachingCount = (0, fs_1.readdirSync)(rawPath).filter(f => f.startsWith(`${userId}-`)).length;
149
+ }
150
+ catch {
151
+ // Ignore read failures.
152
+ }
153
+ }
154
+ let l0RetroCount = 0;
155
+ const retrospectivesPath = (0, path_1.join)(workspaceRoot, 'docs', 'retrospectives');
156
+ if ((0, fs_1.existsSync)(retrospectivesPath)) {
157
+ try {
158
+ l0RetroCount = (0, fs_1.readdirSync)(retrospectivesPath)
159
+ .filter(f => f.startsWith(`${userId}-`) && f.endsWith('.md'))
160
+ .filter(f => isUnsynthesizedRetrospective((0, path_1.join)(retrospectivesPath, f))).length;
161
+ }
162
+ catch {
163
+ // Ignore read failures.
164
+ }
165
+ }
166
+ const hasL2 = l2MistakePresent || l2PrefPresent || l2CoachPresent;
167
+ const hasL1 = l1MistakePresent || l1PrefPresent || l1CoachPresent;
168
+ const hasContent = hasL2 || hasL1 || l0CoachingCount > 0 || l0RetroCount > 0;
169
+ if (!hasContent)
170
+ return '';
171
+ let section = forJob
172
+ ? '\n\n## Learning Context for This Job\n\n'
173
+ : '\n\n## Learning Context\n\n';
174
+ if (hasL2) {
175
+ section += '### L2 - Org patterns\n';
176
+ if (l2MistakePresent)
177
+ section += `\`${LEARNINGS_REL}/org-mistake-patterns.md\` (entries above score threshold)\n`;
178
+ if (l2PrefPresent)
179
+ section += `\`${LEARNINGS_REL}/org-preferences.md\` (all entries)\n`;
180
+ if (l2CoachPresent)
181
+ section += `\`${LEARNINGS_REL}/org-manager-coaching.md\` (all entries)\n`;
182
+ if (l2MistakeCounts && l2MistakeCounts.dormant > 0) {
183
+ section += `Dormant: ${l2MistakeCounts.dormant} org pattern${l2MistakeCounts.dormant !== 1 ? 's' : ''} below threshold\n`;
184
+ }
185
+ section += '\n';
186
+ }
187
+ if (hasL1) {
188
+ section += '### L1 - Your patterns\n';
189
+ if (l1PrefPresent)
190
+ section += `\`${LEARNINGS_REL}/${userId}-preferences.md\` (all entries)\n`;
191
+ if (l1CoachPresent)
192
+ section += `\`${LEARNINGS_REL}/${userId}-manager-coaching.md\` (all entries)\n`;
193
+ if (l1MistakePresent)
194
+ section += `\`${LEARNINGS_REL}/${userId}-mistake-patterns.md\` (entries above score threshold)\n`;
195
+ if (l1MistakeCounts && l1MistakeCounts.dormant > 0) {
196
+ section += `Dormant: ${l1MistakeCounts.dormant} personal pattern${l1MistakeCounts.dormant !== 1 ? 's' : ''} below threshold\n`;
197
+ }
198
+ section += '\n';
199
+ }
200
+ if (l0CoachingCount > 0 || l0RetroCount > 0) {
201
+ section += '### L0 - Your unprocessed signals\n';
202
+ if (l0CoachingCount > 0) {
203
+ section += `${l0CoachingCount} coaching moment${l0CoachingCount !== 1 ? 's' : ''} in \`${LEARNINGS_REL}/raw/${userId}-*\`\n`;
204
+ }
205
+ if (l0RetroCount > 0) {
206
+ section += `${l0RetroCount} retrospective${l0RetroCount !== 1 ? 's' : ''} in \`docs/retrospectives/${userId}-*\` with \`synthesized: false\` or missing\n`;
207
+ }
208
+ section += '\n';
209
+ }
210
+ const totalL0 = l0CoachingCount + l0RetroCount;
211
+ if (forJob) {
212
+ if (hasL2 || hasL1) {
213
+ section += 'Use the relevant patterns, preferences, and coaching signals in this job.\n';
214
+ }
215
+ if (totalL0 >= 5) {
216
+ section += '\n';
217
+ section += `Warning: ${totalL0} unprocessed signals pending. Consider running \`end-of-day-debrief\` before starting today's work.\n`;
218
+ }
219
+ }
220
+ else {
221
+ section += 'Use this synthesized learning context throughout the session.\n';
222
+ if (totalL0 >= 5) {
223
+ section += '\n';
224
+ section += `Warning: synthesis overdue with ${totalL0} unprocessed signals.\n`;
225
+ section += 'Run `end-of-day-debrief` before starting today\'s work.\n';
226
+ }
227
+ }
228
+ return section;
229
+ }