fraim 2.0.154 → 2.0.160
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/src/ai-hub/cert-store.js +70 -0
- package/dist/src/ai-hub/desktop-main.js +225 -50
- package/dist/src/ai-hub/hosts.js +135 -8
- package/dist/src/ai-hub/manager-turns.js +38 -0
- package/dist/src/ai-hub/office-sideload.js +138 -0
- package/dist/src/ai-hub/openclaw-bridge.js +239 -0
- package/dist/src/ai-hub/server.js +479 -48
- package/dist/src/ai-hub/word-sideload.js +95 -0
- package/dist/src/cli/commands/add-ide.js +9 -0
- package/dist/src/cli/commands/init-project.js +46 -34
- package/dist/src/cli/commands/login.js +1 -2
- package/dist/src/cli/commands/setup.js +0 -2
- package/dist/src/cli/commands/sync.js +41 -11
- package/dist/src/cli/doctor/checks/mcp-connectivity-checks.js +66 -2
- package/dist/src/cli/doctor/checks/workflow-checks.js +1 -65
- package/dist/src/cli/mcp/fraim-mcp-latest-launcher.js +136 -0
- package/dist/src/cli/mcp/mcp-server-registry.js +14 -10
- package/dist/src/cli/setup/auto-mcp-setup.js +1 -1
- package/dist/src/cli/setup/ide-invocation-surfaces.js +2 -2
- package/dist/src/cli/utils/fraim-gitignore.js +11 -0
- package/dist/src/cli/utils/github-workflow-sync.js +231 -0
- package/dist/src/cli/utils/managed-agent-paths.js +1 -1
- package/dist/src/cli/utils/project-bootstrap.js +6 -3
- package/dist/src/cli/utils/remote-sync.js +1 -1
- package/dist/src/core/ai-mentor.js +46 -37
- package/dist/src/core/config-loader.js +69 -2
- package/dist/src/core/fraim-config-schema.generated.js +267 -6
- package/dist/src/core/types.js +0 -1
- package/dist/src/core/utils/fraim-labels.js +182 -0
- package/dist/src/core/utils/git-utils.js +22 -1
- package/dist/src/core/utils/project-fraim-paths.js +58 -0
- package/dist/src/first-run/session-service.js +3 -3
- package/dist/src/first-run/types.js +1 -1
- package/dist/src/local-mcp-server/learning-context-builder.js +77 -52
- package/dist/src/local-mcp-server/stdio-server.js +212 -13
- package/package.json +6 -2
- package/public/ai-hub/index.html +289 -229
- package/public/ai-hub/powerpoint-taskpane/icon-64.png +0 -0
- package/public/ai-hub/powerpoint-taskpane/index.html +235 -0
- package/public/ai-hub/powerpoint-taskpane/manifest.xml +30 -0
- package/public/ai-hub/script.js +1155 -586
- package/public/ai-hub/styles.css +1226 -722
- package/public/first-run/index.html +35 -35
- package/public/first-run/script.js +667 -667
|
@@ -9,7 +9,12 @@ exports.workspaceFraimExists = workspaceFraimExists;
|
|
|
9
9
|
exports.getWorkspaceConfigPath = getWorkspaceConfigPath;
|
|
10
10
|
exports.getWorkspaceFraimPath = getWorkspaceFraimPath;
|
|
11
11
|
exports.getWorkspaceFraimDisplayPath = getWorkspaceFraimDisplayPath;
|
|
12
|
+
exports.getUserFraimDisplayPath = getUserFraimDisplayPath;
|
|
12
13
|
exports.getUserFraimDirPath = getUserFraimDirPath;
|
|
14
|
+
exports.getUserFraimLearningsDir = getUserFraimLearningsDir;
|
|
15
|
+
exports.getWorkspaceLearningsDir = getWorkspaceLearningsDir;
|
|
16
|
+
exports.getConfiguredPortableLearningsDir = getConfiguredPortableLearningsDir;
|
|
17
|
+
exports.getConfiguredPortableLearningsDisplayPath = getConfiguredPortableLearningsDisplayPath;
|
|
13
18
|
exports.getEffectiveFraimDir = getEffectiveFraimDir;
|
|
14
19
|
const fs_1 = require("fs");
|
|
15
20
|
const path_1 = require("path");
|
|
@@ -24,6 +29,9 @@ exports.WORKSPACE_SYNCED_CONTENT_DIRS = [
|
|
|
24
29
|
function normalizeRelativePath(relativePath) {
|
|
25
30
|
return relativePath.replace(/^[\\/]+/, '').replace(/[\\/]+/g, '/');
|
|
26
31
|
}
|
|
32
|
+
function normalizeDisplayPath(fullPath) {
|
|
33
|
+
return fullPath.replace(/\\/g, '/');
|
|
34
|
+
}
|
|
27
35
|
function getWorkspaceFraimDir(projectRoot = process.cwd()) {
|
|
28
36
|
return (0, path_1.join)(projectRoot, exports.WORKSPACE_FRAIM_DIRNAME);
|
|
29
37
|
}
|
|
@@ -42,6 +50,10 @@ function getWorkspaceFraimDisplayPath(relativePath = '') {
|
|
|
42
50
|
? `${exports.WORKSPACE_FRAIM_DIRNAME}/${normalized}`
|
|
43
51
|
: `${exports.WORKSPACE_FRAIM_DIRNAME}/`;
|
|
44
52
|
}
|
|
53
|
+
function getUserFraimDisplayPath(relativePath = '') {
|
|
54
|
+
const normalized = normalizeRelativePath(relativePath);
|
|
55
|
+
return normalized.length > 0 ? `~/.fraim/${normalized}` : '~/.fraim/';
|
|
56
|
+
}
|
|
45
57
|
/**
|
|
46
58
|
* Get the user-level FRAIM directory (~/.fraim/).
|
|
47
59
|
* Can be overridden with FRAIM_USER_DIR env var for testing.
|
|
@@ -49,6 +61,52 @@ function getWorkspaceFraimDisplayPath(relativePath = '') {
|
|
|
49
61
|
function getUserFraimDirPath() {
|
|
50
62
|
return process.env.FRAIM_USER_DIR || (0, path_1.join)(os_1.default.homedir(), '.fraim');
|
|
51
63
|
}
|
|
64
|
+
function getUserFraimLearningsDir() {
|
|
65
|
+
return (0, path_1.join)(getUserFraimDirPath(), 'personalized-employee', 'learnings');
|
|
66
|
+
}
|
|
67
|
+
function getWorkspaceLearningsDir(projectRoot = process.cwd()) {
|
|
68
|
+
return getWorkspaceFraimPath(projectRoot, 'personalized-employee', 'learnings');
|
|
69
|
+
}
|
|
70
|
+
function resolveConfiguredLearningGlobalPath(rawPath) {
|
|
71
|
+
if (typeof rawPath !== 'string')
|
|
72
|
+
return null;
|
|
73
|
+
const trimmed = rawPath.trim();
|
|
74
|
+
if (!trimmed)
|
|
75
|
+
return null;
|
|
76
|
+
if (/^[a-z]+:\/\//i.test(trimmed))
|
|
77
|
+
return null;
|
|
78
|
+
if (trimmed.startsWith('~')) {
|
|
79
|
+
const homeRelative = trimmed.slice(1).replace(/^[\\/]+/, '');
|
|
80
|
+
return (0, path_1.normalize)((0, path_1.join)(os_1.default.homedir(), homeRelative));
|
|
81
|
+
}
|
|
82
|
+
if (!(0, path_1.isAbsolute)(trimmed))
|
|
83
|
+
return null;
|
|
84
|
+
return (0, path_1.normalize)(trimmed);
|
|
85
|
+
}
|
|
86
|
+
function readWorkspaceConfig(projectRoot) {
|
|
87
|
+
try {
|
|
88
|
+
const configPath = getWorkspaceConfigPath(projectRoot);
|
|
89
|
+
if (!(0, fs_1.existsSync)(configPath))
|
|
90
|
+
return null;
|
|
91
|
+
return JSON.parse((0, fs_1.readFileSync)(configPath, 'utf8'));
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function getConfiguredPortableLearningsDir(projectRoot = process.cwd()) {
|
|
98
|
+
const config = readWorkspaceConfig(projectRoot);
|
|
99
|
+
const configured = resolveConfiguredLearningGlobalPath(config?.learning?.globalPath);
|
|
100
|
+
return configured || getUserFraimLearningsDir();
|
|
101
|
+
}
|
|
102
|
+
function getConfiguredPortableLearningsDisplayPath(projectRoot = process.cwd()) {
|
|
103
|
+
const config = readWorkspaceConfig(projectRoot);
|
|
104
|
+
const configured = resolveConfiguredLearningGlobalPath(config?.learning?.globalPath);
|
|
105
|
+
if (configured) {
|
|
106
|
+
return normalizeDisplayPath(configured);
|
|
107
|
+
}
|
|
108
|
+
return getUserFraimDisplayPath('personalized-employee/learnings').replace(/\/$/, '');
|
|
109
|
+
}
|
|
52
110
|
/**
|
|
53
111
|
* Determine the effective FRAIM content root directory.
|
|
54
112
|
*
|
|
@@ -507,7 +507,7 @@ class FirstRunSessionService {
|
|
|
507
507
|
fs_1.default.mkdirSync(prefix, { recursive: true });
|
|
508
508
|
row.streamOutput = 'Installing FRAIM on this machine...';
|
|
509
509
|
this.persist();
|
|
510
|
-
await runProcess('npm', ['install', '-g', 'fraim
|
|
510
|
+
await runProcess('npm', ['install', '-g', 'fraim@latest'], { npm_config_prefix: prefix });
|
|
511
511
|
}
|
|
512
512
|
persistShellPath();
|
|
513
513
|
const detectedIDEs = (0, ide_detector_1.detectInstalledIDEs)();
|
|
@@ -752,7 +752,7 @@ class FirstRunSessionService {
|
|
|
752
752
|
appendInstallLog(`hub-opened ${hubUrl}`);
|
|
753
753
|
return {
|
|
754
754
|
ok: true,
|
|
755
|
-
message: `Hub is open at ${hubUrl}. From now on, run \`npx fraim
|
|
755
|
+
message: `Hub is open at ${hubUrl}. From now on, run \`npx fraim@latest hub --browser\` to launch it again — the standalone launcher binary ships in v2 (#355).`,
|
|
756
756
|
hubUrl,
|
|
757
757
|
};
|
|
758
758
|
}
|
|
@@ -761,7 +761,7 @@ class FirstRunSessionService {
|
|
|
761
761
|
appendInstallLog(`hub-open-failed ${detail}`);
|
|
762
762
|
return {
|
|
763
763
|
ok: false,
|
|
764
|
-
message: `Could not open the Hub automatically: ${detail}. Run \`npx fraim
|
|
764
|
+
message: `Could not open the Hub automatically: ${detail}. Run \`npx fraim@latest hub --browser\` from a terminal to open it manually.`,
|
|
765
765
|
};
|
|
766
766
|
}
|
|
767
767
|
}
|
|
@@ -60,7 +60,7 @@ function createInitialRows() {
|
|
|
60
60
|
{ id: 'node', label: 'Node.js', status: 'pending', verb: "we'll install" },
|
|
61
61
|
{ id: 'git', label: 'git', status: 'pending', verb: "we'll install", optional: true },
|
|
62
62
|
{ id: 'fraim', label: 'FRAIM', status: 'pending', verb: "we'll set up FRAIM" },
|
|
63
|
-
{ id: 'agent', label: '
|
|
63
|
+
{ id: 'agent', label: 'Execution surfaces', status: 'pending', verb: "we'll detect execution surfaces" },
|
|
64
64
|
];
|
|
65
65
|
}
|
|
66
66
|
/**
|
|
@@ -11,14 +11,37 @@ exports.buildLearningContextSection = buildLearningContextSection;
|
|
|
11
11
|
const fs_1 = require("fs");
|
|
12
12
|
const path_1 = require("path");
|
|
13
13
|
const project_fraim_paths_1 = require("../core/utils/project-fraim-paths");
|
|
14
|
-
const
|
|
14
|
+
const REPO_LEARNINGS_REL = (0, project_fraim_paths_1.getWorkspaceFraimDisplayPath)('personalized-employee/learnings').replace(/\/$/, '');
|
|
15
15
|
const DEFAULT_THRESHOLD = 3.0;
|
|
16
16
|
const AGING_HORIZON_DAYS = 7;
|
|
17
17
|
const MAX_ENTRIES_SCANNED = 200;
|
|
18
18
|
const BACKLOG_MIN = 5;
|
|
19
19
|
const OLDEST_AGE_DAYS_TRIGGER = 3;
|
|
20
|
-
function
|
|
21
|
-
return
|
|
20
|
+
function getLearningRoots(workspaceRoot) {
|
|
21
|
+
return {
|
|
22
|
+
globalPersonalBase: (0, project_fraim_paths_1.getConfiguredPortableLearningsDir)(workspaceRoot),
|
|
23
|
+
globalPersonalDisplayBase: (0, project_fraim_paths_1.getConfiguredPortableLearningsDisplayPath)(workspaceRoot),
|
|
24
|
+
repoLearningsBase: (0, project_fraim_paths_1.getWorkspaceLearningsDir)(workspaceRoot)
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function resolvePersonalLearningFile(repoBase, globalBase, globalDisplayBase, fileName) {
|
|
28
|
+
const repoPath = (0, path_1.join)(repoBase, fileName);
|
|
29
|
+
if ((0, fs_1.existsSync)(repoPath)) {
|
|
30
|
+
return {
|
|
31
|
+
present: true,
|
|
32
|
+
path: repoPath,
|
|
33
|
+
displayPath: `${REPO_LEARNINGS_REL}/${fileName}`
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const globalPath = (0, path_1.join)(globalBase, fileName);
|
|
37
|
+
if ((0, fs_1.existsSync)(globalPath)) {
|
|
38
|
+
return {
|
|
39
|
+
present: true,
|
|
40
|
+
path: globalPath,
|
|
41
|
+
displayPath: `${globalDisplayBase.replace(/\/$/, '')}/${fileName}`
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return { present: false, path: globalPath, displayPath: `${globalDisplayBase.replace(/\/$/, '')}/${fileName}` };
|
|
22
45
|
}
|
|
23
46
|
function buildUserIdCandidates(userId) {
|
|
24
47
|
const candidates = new Set();
|
|
@@ -40,7 +63,7 @@ function countMatchingFilesByPrefix(dirPath, matcher) {
|
|
|
40
63
|
return 0;
|
|
41
64
|
}
|
|
42
65
|
}
|
|
43
|
-
function collectAvailableUserPrefixes(workspaceRoot,
|
|
66
|
+
function collectAvailableUserPrefixes(workspaceRoot, personalRoots) {
|
|
44
67
|
const prefixes = new Set();
|
|
45
68
|
const collect = (dirPath, extractor) => {
|
|
46
69
|
if (!(0, fs_1.existsSync)(dirPath))
|
|
@@ -56,13 +79,15 @@ function collectAvailableUserPrefixes(workspaceRoot, learningsBase) {
|
|
|
56
79
|
// Ignore unreadable directories.
|
|
57
80
|
}
|
|
58
81
|
};
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
82
|
+
for (const personalRoot of personalRoots) {
|
|
83
|
+
collect(personalRoot, (fileName) => {
|
|
84
|
+
if (!fileName.endsWith('.md') || fileName.startsWith('org-'))
|
|
85
|
+
return null;
|
|
86
|
+
const match = fileName.match(/^(.*?)-(preferences|manager-coaching|mistake-patterns|validated-patterns)\.md$/);
|
|
87
|
+
return match ? match[1] : null;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
collect((0, path_1.join)(personalRoots[0], 'raw'), (fileName) => {
|
|
66
91
|
const match = fileName.match(/^(.*?)-\d{4}-\d{2}-\d{2}-.*\.md$/);
|
|
67
92
|
return match ? match[1] : null;
|
|
68
93
|
});
|
|
@@ -72,16 +97,20 @@ function collectAvailableUserPrefixes(workspaceRoot, learningsBase) {
|
|
|
72
97
|
});
|
|
73
98
|
return prefixes;
|
|
74
99
|
}
|
|
75
|
-
function resolveLearningUserId(workspaceRoot, userId) {
|
|
76
|
-
const learningsBase = getLearningsBase(workspaceRoot);
|
|
100
|
+
function resolveLearningUserId(workspaceRoot, userId, roots) {
|
|
77
101
|
const candidates = buildUserIdCandidates(userId);
|
|
78
102
|
let bestCandidate = candidates[0] || userId;
|
|
79
103
|
let bestScore = -1;
|
|
80
104
|
for (const candidate of candidates) {
|
|
81
|
-
const score = ((0, fs_1.existsSync)((0, path_1.join)(
|
|
82
|
-
((0, fs_1.existsSync)((0, path_1.join)(
|
|
83
|
-
((0, fs_1.existsSync)((0, path_1.join)(
|
|
84
|
-
|
|
105
|
+
const score = ((0, fs_1.existsSync)((0, path_1.join)(roots.globalPersonalBase, `${candidate}-preferences.md`)) ? 1 : 0) +
|
|
106
|
+
((0, fs_1.existsSync)((0, path_1.join)(roots.globalPersonalBase, `${candidate}-manager-coaching.md`)) ? 1 : 0) +
|
|
107
|
+
((0, fs_1.existsSync)((0, path_1.join)(roots.globalPersonalBase, `${candidate}-mistake-patterns.md`)) ? 1 : 0) +
|
|
108
|
+
((0, fs_1.existsSync)((0, path_1.join)(roots.globalPersonalBase, `${candidate}-validated-patterns.md`)) ? 1 : 0) +
|
|
109
|
+
((0, fs_1.existsSync)((0, path_1.join)(roots.repoLearningsBase, `${candidate}-preferences.md`)) ? 1 : 0) +
|
|
110
|
+
((0, fs_1.existsSync)((0, path_1.join)(roots.repoLearningsBase, `${candidate}-manager-coaching.md`)) ? 1 : 0) +
|
|
111
|
+
((0, fs_1.existsSync)((0, path_1.join)(roots.repoLearningsBase, `${candidate}-mistake-patterns.md`)) ? 1 : 0) +
|
|
112
|
+
((0, fs_1.existsSync)((0, path_1.join)(roots.repoLearningsBase, `${candidate}-validated-patterns.md`)) ? 1 : 0) +
|
|
113
|
+
countMatchingFilesByPrefix((0, path_1.join)(roots.repoLearningsBase, 'raw'), (fileName) => fileName.startsWith(`${candidate}-`)) +
|
|
85
114
|
countMatchingFilesByPrefix((0, path_1.join)(workspaceRoot, 'docs', 'retrospectives'), (fileName) => fileName.startsWith(`${candidate}-`) && fileName.endsWith('.md'));
|
|
86
115
|
if (score > bestScore) {
|
|
87
116
|
bestCandidate = candidate;
|
|
@@ -90,7 +119,7 @@ function resolveLearningUserId(workspaceRoot, userId) {
|
|
|
90
119
|
}
|
|
91
120
|
if (bestScore > 0)
|
|
92
121
|
return bestCandidate;
|
|
93
|
-
const availablePrefixes = collectAvailableUserPrefixes(workspaceRoot,
|
|
122
|
+
const availablePrefixes = collectAvailableUserPrefixes(workspaceRoot, [roots.repoLearningsBase, roots.globalPersonalBase]);
|
|
94
123
|
if (availablePrefixes.size === 1) {
|
|
95
124
|
return Array.from(availablePrefixes)[0];
|
|
96
125
|
}
|
|
@@ -242,7 +271,7 @@ function isUnsynthesizedRetrospective(filePath) {
|
|
|
242
271
|
}
|
|
243
272
|
/** Oldest mtime-age in days across this user's L0 signals. 0 if none. */
|
|
244
273
|
function computeOldestL0AgeDays(workspaceRoot, userId) {
|
|
245
|
-
const learningsBase =
|
|
274
|
+
const learningsBase = (0, project_fraim_paths_1.getWorkspaceLearningsDir)(workspaceRoot);
|
|
246
275
|
const now = Date.now();
|
|
247
276
|
let oldest = 0;
|
|
248
277
|
const consider = (filePath) => {
|
|
@@ -287,31 +316,27 @@ function computeOldestL0AgeDays(workspaceRoot, userId) {
|
|
|
287
316
|
return oldest;
|
|
288
317
|
}
|
|
289
318
|
function buildLearningContextSection(workspaceRoot, userId, forJob) {
|
|
290
|
-
const
|
|
291
|
-
const resolvedUserId = resolveLearningUserId(workspaceRoot, userId);
|
|
319
|
+
const roots = getLearningRoots(workspaceRoot);
|
|
320
|
+
const resolvedUserId = resolveLearningUserId(workspaceRoot, userId, roots);
|
|
292
321
|
const threshold = getScoreThreshold(workspaceRoot);
|
|
293
|
-
const l2MistakePath = (0, path_1.join)(
|
|
294
|
-
const l2PrefPath = (0, path_1.join)(
|
|
295
|
-
const l2CoachPath = (0, path_1.join)(
|
|
296
|
-
const l2ValidatedPath = (0, path_1.join)(
|
|
322
|
+
const l2MistakePath = (0, path_1.join)(roots.repoLearningsBase, 'org-mistake-patterns.md');
|
|
323
|
+
const l2PrefPath = (0, path_1.join)(roots.repoLearningsBase, 'org-preferences.md');
|
|
324
|
+
const l2CoachPath = (0, path_1.join)(roots.repoLearningsBase, 'org-manager-coaching.md');
|
|
325
|
+
const l2ValidatedPath = (0, path_1.join)(roots.repoLearningsBase, 'org-validated-patterns.md');
|
|
297
326
|
const l2MistakePresent = (0, fs_1.existsSync)(l2MistakePath);
|
|
298
327
|
const l2PrefPresent = (0, fs_1.existsSync)(l2PrefPath);
|
|
299
328
|
const l2CoachPresent = (0, fs_1.existsSync)(l2CoachPath);
|
|
300
329
|
const l2ValidatedPresent = (0, fs_1.existsSync)(l2ValidatedPath);
|
|
301
330
|
const l2MistakeStats = l2MistakePresent ? scanMistakePatternFile(l2MistakePath, threshold, 'mistake-patterns') : null;
|
|
302
331
|
const l2ValidatedStats = l2ValidatedPresent ? scanMistakePatternFile(l2ValidatedPath, threshold, 'validated-patterns') : null;
|
|
303
|
-
const
|
|
304
|
-
const
|
|
305
|
-
const
|
|
306
|
-
const
|
|
307
|
-
const
|
|
308
|
-
const
|
|
309
|
-
const l1CoachPresent = (0, fs_1.existsSync)(l1CoachPath);
|
|
310
|
-
const l1ValidatedPresent = (0, fs_1.existsSync)(l1ValidatedPath);
|
|
311
|
-
const l1MistakeStats = l1MistakePresent ? scanMistakePatternFile(l1MistakePath, threshold, 'mistake-patterns') : null;
|
|
312
|
-
const l1ValidatedStats = l1ValidatedPresent ? scanMistakePatternFile(l1ValidatedPath, threshold, 'validated-patterns') : null;
|
|
332
|
+
const l1Mistake = resolvePersonalLearningFile(roots.repoLearningsBase, roots.globalPersonalBase, roots.globalPersonalDisplayBase, `${resolvedUserId}-mistake-patterns.md`);
|
|
333
|
+
const l1Pref = resolvePersonalLearningFile(roots.repoLearningsBase, roots.globalPersonalBase, roots.globalPersonalDisplayBase, `${resolvedUserId}-preferences.md`);
|
|
334
|
+
const l1Coach = resolvePersonalLearningFile(roots.repoLearningsBase, roots.globalPersonalBase, roots.globalPersonalDisplayBase, `${resolvedUserId}-manager-coaching.md`);
|
|
335
|
+
const l1Validated = resolvePersonalLearningFile(roots.repoLearningsBase, roots.globalPersonalBase, roots.globalPersonalDisplayBase, `${resolvedUserId}-validated-patterns.md`);
|
|
336
|
+
const l1MistakeStats = l1Mistake.present ? scanMistakePatternFile(l1Mistake.path, threshold, 'mistake-patterns') : null;
|
|
337
|
+
const l1ValidatedStats = l1Validated.present ? scanMistakePatternFile(l1Validated.path, threshold, 'validated-patterns') : null;
|
|
313
338
|
let l0CoachingCount = 0;
|
|
314
|
-
const rawPath = (0, path_1.join)(
|
|
339
|
+
const rawPath = (0, path_1.join)(roots.repoLearningsBase, 'raw');
|
|
315
340
|
if ((0, fs_1.existsSync)(rawPath)) {
|
|
316
341
|
try {
|
|
317
342
|
l0CoachingCount = (0, fs_1.readdirSync)(rawPath).filter(f => f.startsWith(`${resolvedUserId}-`)).length;
|
|
@@ -333,7 +358,7 @@ function buildLearningContextSection(workspaceRoot, userId, forJob) {
|
|
|
333
358
|
}
|
|
334
359
|
}
|
|
335
360
|
const hasL2 = l2MistakePresent || l2PrefPresent || l2CoachPresent || l2ValidatedPresent;
|
|
336
|
-
const hasL1 =
|
|
361
|
+
const hasL1 = l1Mistake.present || l1Pref.present || l1Coach.present || l1Validated.present;
|
|
337
362
|
const hasContent = hasL2 || hasL1 || l0CoachingCount > 0 || l0RetroCount > 0;
|
|
338
363
|
if (!hasContent)
|
|
339
364
|
return '';
|
|
@@ -343,13 +368,13 @@ function buildLearningContextSection(workspaceRoot, userId, forJob) {
|
|
|
343
368
|
if (hasL2) {
|
|
344
369
|
section += '### L2 - Org patterns\n';
|
|
345
370
|
if (l2MistakePresent)
|
|
346
|
-
section += `\`${
|
|
371
|
+
section += `\`${REPO_LEARNINGS_REL}/org-mistake-patterns.md\` (entries above score threshold)\n`;
|
|
347
372
|
if (l2PrefPresent)
|
|
348
|
-
section += `\`${
|
|
373
|
+
section += `\`${REPO_LEARNINGS_REL}/org-preferences.md\` (all entries)\n`;
|
|
349
374
|
if (l2CoachPresent)
|
|
350
|
-
section += `\`${
|
|
375
|
+
section += `\`${REPO_LEARNINGS_REL}/org-manager-coaching.md\` (manager-facing; all entries)\n`;
|
|
351
376
|
if (l2ValidatedPresent)
|
|
352
|
-
section += `\`${
|
|
377
|
+
section += `\`${REPO_LEARNINGS_REL}/org-validated-patterns.md\` (entries above score threshold)\n`;
|
|
353
378
|
const l2DormantTotal = (l2MistakeStats?.dormant || 0) + (l2ValidatedStats?.dormant || 0);
|
|
354
379
|
if (l2DormantTotal > 0) {
|
|
355
380
|
section += `Dormant: ${l2DormantTotal} org pattern${l2DormantTotal !== 1 ? 's' : ''} below threshold\n`;
|
|
@@ -358,14 +383,14 @@ function buildLearningContextSection(workspaceRoot, userId, forJob) {
|
|
|
358
383
|
}
|
|
359
384
|
if (hasL1) {
|
|
360
385
|
section += '### L1 - Your patterns\n';
|
|
361
|
-
if (
|
|
362
|
-
section += `\`${
|
|
363
|
-
if (
|
|
364
|
-
section += `\`${
|
|
365
|
-
if (
|
|
366
|
-
section += `\`${
|
|
367
|
-
if (
|
|
368
|
-
section += `\`${
|
|
386
|
+
if (l1Pref.present)
|
|
387
|
+
section += `\`${l1Pref.displayPath}\` (all entries)\n`;
|
|
388
|
+
if (l1Coach.present)
|
|
389
|
+
section += `\`${l1Coach.displayPath}\` (manager-facing; all entries)\n`;
|
|
390
|
+
if (l1Mistake.present)
|
|
391
|
+
section += `\`${l1Mistake.displayPath}\` (entries above score threshold)\n`;
|
|
392
|
+
if (l1Validated.present)
|
|
393
|
+
section += `\`${l1Validated.displayPath}\` (entries above score threshold)\n`;
|
|
369
394
|
const l1DormantTotal = (l1MistakeStats?.dormant || 0) + (l1ValidatedStats?.dormant || 0);
|
|
370
395
|
if (l1DormantTotal > 0) {
|
|
371
396
|
section += `Dormant: ${l1DormantTotal} personal pattern${l1DormantTotal !== 1 ? 's' : ''} below threshold\n`;
|
|
@@ -375,7 +400,7 @@ function buildLearningContextSection(workspaceRoot, userId, forJob) {
|
|
|
375
400
|
if (l0CoachingCount > 0 || l0RetroCount > 0) {
|
|
376
401
|
section += '### L0 - Your unprocessed signals\n';
|
|
377
402
|
if (l0CoachingCount > 0) {
|
|
378
|
-
section += `${l0CoachingCount} coaching moment${l0CoachingCount !== 1 ? 's' : ''} in \`${
|
|
403
|
+
section += `${l0CoachingCount} coaching moment${l0CoachingCount !== 1 ? 's' : ''} in \`${REPO_LEARNINGS_REL}/raw/${resolvedUserId}-*\`\n`;
|
|
379
404
|
}
|
|
380
405
|
if (l0RetroCount > 0) {
|
|
381
406
|
section += `${l0RetroCount} retrospective${l0RetroCount !== 1 ? 's' : ''} in \`docs/retrospectives/${resolvedUserId}-*\` with unsynthesized or missing \`synthesized\` frontmatter\n`;
|
|
@@ -389,7 +414,7 @@ function buildLearningContextSection(workspaceRoot, userId, forJob) {
|
|
|
389
414
|
if (forJob) {
|
|
390
415
|
if (hasL2 || hasL1) {
|
|
391
416
|
section += 'Use the relevant patterns and preferences in this job.\n';
|
|
392
|
-
if (
|
|
417
|
+
if (l1Coach.present || l2CoachPresent) {
|
|
393
418
|
section += 'Treat manager-coaching as feedback for how the manager should continue or improve managing AI, not as agent instruction.\n';
|
|
394
419
|
}
|
|
395
420
|
}
|
|
@@ -401,7 +426,7 @@ function buildLearningContextSection(workspaceRoot, userId, forJob) {
|
|
|
401
426
|
}
|
|
402
427
|
else {
|
|
403
428
|
section += 'Use this synthesized learning context throughout the session.\n';
|
|
404
|
-
if (
|
|
429
|
+
if (l1Coach.present || l2CoachPresent) {
|
|
405
430
|
section += 'Manager-coaching entries are manager-facing feedback, not instructions for the AI to follow.\n';
|
|
406
431
|
}
|
|
407
432
|
if (backlogTriggered) {
|