fraim 2.0.261 → 2.0.262
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.
|
@@ -230,15 +230,15 @@ const runSync = async (options) => {
|
|
|
230
230
|
else if (outcome.status === 'absent') {
|
|
231
231
|
console.log(chalk_1.default.yellow(`Org context not synced: ${outcome.error}`));
|
|
232
232
|
}
|
|
233
|
-
//
|
|
234
|
-
//
|
|
235
|
-
// silently orphaning a manager's work is worse than a noisy sync.
|
|
233
|
+
// Migrate stranded content from the legacy standard path to contentRoot,
|
|
234
|
+
// then report any files that still could not be moved.
|
|
236
235
|
try {
|
|
237
|
-
const { findStrandedLegacyContent, resolvePackHome } = await Promise.resolve().then(() => __importStar(require('../utils/pack-home')));
|
|
236
|
+
const { migrateStrandedContent, findStrandedLegacyContent, resolvePackHome } = await Promise.resolve().then(() => __importStar(require('../utils/pack-home')));
|
|
237
|
+
migrateStrandedContent('org');
|
|
238
238
|
const stranded = findStrandedLegacyContent('org');
|
|
239
239
|
if (stranded.length > 0) {
|
|
240
240
|
const home = resolvePackHome('org');
|
|
241
|
-
console.log(chalk_1.default.yellow(`${stranded.length} org file(s)
|
|
241
|
+
console.log(chalk_1.default.yellow(`${stranded.length} org file(s) could not be migrated to your org home and are no longer read:`));
|
|
242
242
|
for (const rel of stranded.slice(0, 10))
|
|
243
243
|
console.log(chalk_1.default.yellow(` ${rel}`));
|
|
244
244
|
if (stranded.length > 10)
|
|
@@ -274,15 +274,15 @@ const runSync = async (options) => {
|
|
|
274
274
|
else if (outcome.status === 'absent') {
|
|
275
275
|
console.log(chalk_1.default.yellow(`Manager context not synced: ${outcome.error}`));
|
|
276
276
|
}
|
|
277
|
-
//
|
|
278
|
-
//
|
|
279
|
-
// silently orphaning a manager's work is worse than a noisy sync.
|
|
277
|
+
// Migrate stranded content from the legacy standard path to contentRoot,
|
|
278
|
+
// then report any files that still could not be moved.
|
|
280
279
|
try {
|
|
281
|
-
const { findStrandedLegacyContent, resolvePackHome } = await Promise.resolve().then(() => __importStar(require('../utils/pack-home')));
|
|
280
|
+
const { migrateStrandedContent, findStrandedLegacyContent, resolvePackHome } = await Promise.resolve().then(() => __importStar(require('../utils/pack-home')));
|
|
281
|
+
migrateStrandedContent('manager');
|
|
282
282
|
const stranded = findStrandedLegacyContent('manager');
|
|
283
283
|
if (stranded.length > 0) {
|
|
284
284
|
const home = resolvePackHome('manager');
|
|
285
|
-
console.log(chalk_1.default.yellow(`${stranded.length} manager file(s)
|
|
285
|
+
console.log(chalk_1.default.yellow(`${stranded.length} manager file(s) could not be migrated to your manager home and are no longer read:`));
|
|
286
286
|
for (const rel of stranded.slice(0, 10))
|
|
287
287
|
console.log(chalk_1.default.yellow(` ${rel}`));
|
|
288
288
|
if (stranded.length > 10)
|
|
@@ -224,6 +224,12 @@ async function syncManagerCache(options) {
|
|
|
224
224
|
const clone = (0, pack_home_1.ensurePackClone)(managerStorage.gitUrl, home.root);
|
|
225
225
|
if (clone.sha === null)
|
|
226
226
|
throw new Error(clone.offlineReason ?? 'Pack clone unavailable.');
|
|
227
|
+
// When a clone exists but the remote was unreachable, offlineReason is
|
|
228
|
+
// set and the SHA is the last cached value. Return stale so callers
|
|
229
|
+
// know the content is potentially out of date (R4.3).
|
|
230
|
+
if (clone.offlineReason) {
|
|
231
|
+
return failureOutcome(new Error(clone.offlineReason));
|
|
232
|
+
}
|
|
227
233
|
const metadata = {
|
|
228
234
|
version: clone.sha,
|
|
229
235
|
backend: 'git',
|
|
@@ -275,6 +275,12 @@ async function syncOrgCache(options) {
|
|
|
275
275
|
const clone = (0, pack_home_1.ensurePackClone)(organization.gitUrl, home.root);
|
|
276
276
|
if (clone.sha === null)
|
|
277
277
|
throw new Error(clone.offlineReason ?? 'Pack clone unavailable.');
|
|
278
|
+
// When a clone exists but the remote was unreachable, offlineReason is
|
|
279
|
+
// set and the SHA is the last cached value. Return stale so callers
|
|
280
|
+
// know the content is potentially out of date (R4.3).
|
|
281
|
+
if (clone.offlineReason) {
|
|
282
|
+
return failureOutcome(new Error(clone.offlineReason));
|
|
283
|
+
}
|
|
278
284
|
const metadata = {
|
|
279
285
|
version: clone.sha,
|
|
280
286
|
backend: 'git',
|
|
@@ -7,6 +7,7 @@ exports.packsDir = packsDir;
|
|
|
7
7
|
exports.defaultCloneDir = defaultCloneDir;
|
|
8
8
|
exports.resolvePackHome = resolvePackHome;
|
|
9
9
|
exports.packReadRoots = packReadRoots;
|
|
10
|
+
exports.migrateStrandedContent = migrateStrandedContent;
|
|
10
11
|
exports.findStrandedLegacyContent = findStrandedLegacyContent;
|
|
11
12
|
exports.gitUrlHasUserinfo = gitUrlHasUserinfo;
|
|
12
13
|
exports.ensurePackClone = ensurePackClone;
|
|
@@ -172,6 +173,78 @@ function resolvePackHome(layer) {
|
|
|
172
173
|
function packReadRoots(layer) {
|
|
173
174
|
return [resolvePackHome(layer).contentRoot];
|
|
174
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Auto-migrate content stranded at the legacy standard path to the configured
|
|
178
|
+
* contentRoot. Runs at most once per process per (layer + contentRoot) pair.
|
|
179
|
+
* Never throws: migration failures are silently skipped.
|
|
180
|
+
*
|
|
181
|
+
* Applies when a synced backend (local-folder, git, fraim-cloud) is configured
|
|
182
|
+
* and the legacy standard path differs from contentRoot. Each file is moved
|
|
183
|
+
* with renameSync; on a cross-device rename (e.g. ~/.fraim → OneDrive) it
|
|
184
|
+
* falls back to copyFileSync + unlinkSync. Files already present in contentRoot
|
|
185
|
+
* are never overwritten — contentRoot is always authoritative.
|
|
186
|
+
*/
|
|
187
|
+
const _migratedStrandedLayers = new Set();
|
|
188
|
+
function migrateStrandedContent(layer) {
|
|
189
|
+
const home = resolvePackHome(layer);
|
|
190
|
+
const key = `${layer}:${home.contentRoot}`;
|
|
191
|
+
if (_migratedStrandedLayers.has(key))
|
|
192
|
+
return;
|
|
193
|
+
_migratedStrandedLayers.add(key);
|
|
194
|
+
const legacyContentRoot = home.legacyRoot ? path_1.default.join(home.legacyRoot, 'personalized-employee') : null;
|
|
195
|
+
if (!legacyContentRoot || legacyContentRoot === home.contentRoot)
|
|
196
|
+
return;
|
|
197
|
+
if (!fs_1.default.existsSync(legacyContentRoot))
|
|
198
|
+
return;
|
|
199
|
+
try {
|
|
200
|
+
const walk = (absDir, relDir) => {
|
|
201
|
+
let entries;
|
|
202
|
+
try {
|
|
203
|
+
entries = fs_1.default.readdirSync(absDir, { withFileTypes: true });
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
for (const entry of entries) {
|
|
209
|
+
const rel = relDir ? `${relDir}/${entry.name}` : entry.name;
|
|
210
|
+
const src = path_1.default.join(absDir, entry.name);
|
|
211
|
+
const dst = path_1.default.join(home.contentRoot, rel);
|
|
212
|
+
if (entry.isDirectory()) {
|
|
213
|
+
walk(src, rel);
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (!entry.isFile())
|
|
217
|
+
continue;
|
|
218
|
+
if (fs_1.default.existsSync(dst))
|
|
219
|
+
continue;
|
|
220
|
+
try {
|
|
221
|
+
fs_1.default.mkdirSync(path_1.default.dirname(dst), { recursive: true });
|
|
222
|
+
fs_1.default.renameSync(src, dst);
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
try {
|
|
226
|
+
fs_1.default.copyFileSync(src, dst);
|
|
227
|
+
fs_1.default.unlinkSync(src);
|
|
228
|
+
}
|
|
229
|
+
catch { /* leave source intact */ }
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
walk(legacyContentRoot, '');
|
|
234
|
+
// Clean up empty dirs left behind (best-effort).
|
|
235
|
+
for (const dir of ORG_CONTENT_DIRS) {
|
|
236
|
+
try {
|
|
237
|
+
fs_1.default.rmdirSync(path_1.default.join(legacyContentRoot, dir));
|
|
238
|
+
}
|
|
239
|
+
catch { /* not empty — fine */ }
|
|
240
|
+
}
|
|
241
|
+
try {
|
|
242
|
+
fs_1.default.rmdirSync(legacyContentRoot);
|
|
243
|
+
}
|
|
244
|
+
catch { /* not empty — fine */ }
|
|
245
|
+
}
|
|
246
|
+
catch { /* migration is best-effort; never fail a sync over it */ }
|
|
247
|
+
}
|
|
175
248
|
/**
|
|
176
249
|
* Content sitting at the standard local path that the configured home does not
|
|
177
250
|
* hold. Since the home is the single read location, this content is stranded:
|
|
@@ -72,11 +72,18 @@ function managerSecondaryLearningsBase() {
|
|
|
72
72
|
function getLearningRoots(workspaceRoot) {
|
|
73
73
|
const managerHome = (0, pack_home_1.resolvePackHome)('manager');
|
|
74
74
|
const managerHomeBase = (0, path_1.join)(managerHome.contentRoot, 'learnings');
|
|
75
|
+
const managerCacheBase = managerSecondaryLearningsBase();
|
|
76
|
+
// Derive the display base from the actual cache path relative to ~/.fraim so
|
|
77
|
+
// the display string always matches the filesystem path (fixed by #1043r2).
|
|
78
|
+
const fraimDir = (0, project_fraim_paths_1.getUserFraimDirPath)();
|
|
79
|
+
const managerCacheDisplayBase = managerCacheBase.startsWith(fraimDir)
|
|
80
|
+
? (0, project_fraim_paths_1.getUserFraimDisplayPath)(managerCacheBase.slice(fraimDir.length).replace(/\\/g, '/').replace(/^\//, ''))
|
|
81
|
+
: managerCacheBase.replace(/\\/g, '/');
|
|
75
82
|
return {
|
|
76
83
|
globalPersonalBase: (0, project_fraim_paths_1.getConfiguredPortableLearningsDir)(workspaceRoot),
|
|
77
84
|
globalPersonalDisplayBase: (0, project_fraim_paths_1.getConfiguredPortableLearningsDisplayPath)(workspaceRoot),
|
|
78
|
-
managerCacheBase
|
|
79
|
-
managerCacheDisplayBase
|
|
85
|
+
managerCacheBase,
|
|
86
|
+
managerCacheDisplayBase,
|
|
80
87
|
managerHomeBase,
|
|
81
88
|
managerHomeDisplayBase: managerHomeBase.replace(/\\/g, '/'),
|
|
82
89
|
repoLearningsBase: (0, project_fraim_paths_1.getWorkspaceLearningsDir)(workspaceRoot)
|
|
@@ -637,11 +644,20 @@ function resolveOrgContextFile(workspaceRoot, relativePath, orgCacheEligible = t
|
|
|
637
644
|
}
|
|
638
645
|
}
|
|
639
646
|
if (!orgCacheEligible) {
|
|
640
|
-
const
|
|
647
|
+
const managerHome = (0, pack_home_1.resolvePackHome)('manager');
|
|
648
|
+
const managerCachePath = (0, path_1.join)(managerHome.contentRoot, relativePath);
|
|
641
649
|
if ((0, fs_1.existsSync)(managerCachePath)) {
|
|
650
|
+
// Derive the display path relative to ~/.fraim. For the standard
|
|
651
|
+
// single-machine backend contentRoot is ~/.fraim/personalized-employee
|
|
652
|
+
// so the display path is ~/.fraim/personalized-employee/... For a
|
|
653
|
+
// synced backend it may be elsewhere (e.g. ~/.fraim/packs/manager-repo).
|
|
654
|
+
const fraimDir = (0, project_fraim_paths_1.getUserFraimDirPath)();
|
|
655
|
+
const relToFraim = managerCachePath.startsWith(fraimDir)
|
|
656
|
+
? managerCachePath.slice(fraimDir.length).replace(/\\/g, '/').replace(/^\//, '')
|
|
657
|
+
: `personalized-employee/${relativePath}`;
|
|
642
658
|
return {
|
|
643
659
|
present: true,
|
|
644
|
-
displayPath: (0, project_fraim_paths_1.getUserFraimDisplayPath)(
|
|
660
|
+
displayPath: (0, project_fraim_paths_1.getUserFraimDisplayPath)(relToFraim)
|
|
645
661
|
};
|
|
646
662
|
}
|
|
647
663
|
}
|
|
@@ -812,13 +828,18 @@ function resolveTeamContextFile(workspaceRoot, key) {
|
|
|
812
828
|
}
|
|
813
829
|
}
|
|
814
830
|
if (key === 'manager' || key === 'managerRules') {
|
|
815
|
-
const
|
|
831
|
+
const managerHome = (0, pack_home_1.resolvePackHome)('manager');
|
|
832
|
+
const managerCachePath = (0, path_1.join)(managerHome.contentRoot, relativePath);
|
|
816
833
|
if ((0, fs_1.existsSync)(managerCachePath)) {
|
|
834
|
+
const fraimDir = (0, project_fraim_paths_1.getUserFraimDirPath)();
|
|
835
|
+
const relToFraim = managerCachePath.startsWith(fraimDir)
|
|
836
|
+
? managerCachePath.slice(fraimDir.length).replace(/\\/g, '/').replace(/^\//, '')
|
|
837
|
+
: `personalized-employee/${relativePath}`;
|
|
817
838
|
return {
|
|
818
839
|
present: true,
|
|
819
840
|
readPath: managerCachePath,
|
|
820
841
|
writePath: '',
|
|
821
|
-
displayPath: (0, project_fraim_paths_1.getUserFraimDisplayPath)(
|
|
842
|
+
displayPath: (0, project_fraim_paths_1.getUserFraimDisplayPath)(relToFraim),
|
|
822
843
|
scope,
|
|
823
844
|
managedByManagerSync: true
|
|
824
845
|
};
|