fraim 2.0.248 → 2.0.249
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/dist/src/cli/commands/manager.js +26 -7
- package/dist/src/cli/commands/org.js +26 -7
- package/dist/src/cli/commands/sync.js +34 -0
- package/dist/src/cli/utils/local-folder-sync.js +100 -48
- package/dist/src/cli/utils/manager-pack-sync.js +77 -40
- package/dist/src/cli/utils/manager-publish.js +38 -40
- package/dist/src/cli/utils/org-pack-sync.js +80 -41
- package/dist/src/cli/utils/org-publish.js +37 -40
- package/dist/src/cli/utils/pack-git-publish.js +248 -0
- package/dist/src/cli/utils/pack-home.js +279 -0
- package/dist/src/cli/utils/user-config.js +10 -2
- package/dist/src/core/capability-pack.js +23 -1
- package/dist/src/core/manager-pack.js +21 -5
- package/dist/src/local-mcp-server/learning-context-builder.js +29 -8
- package/dist/src/local-mcp-server/stdio-server.js +12 -4
- package/package.json +1 -1
|
@@ -6,32 +6,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.managerPackRelativePathFor = managerPackRelativePathFor;
|
|
7
7
|
exports.publishManagerArtifacts = publishManagerArtifacts;
|
|
8
8
|
/**
|
|
9
|
-
* Publish manager context
|
|
10
|
-
* (issue #580
|
|
9
|
+
* Publish manager context, rules, learnings, capabilities, and employees to the
|
|
10
|
+
* configured manager backend (issue #580; capability and employee support and
|
|
11
|
+
* pull-request creation added in issue #1043).
|
|
11
12
|
*/
|
|
12
13
|
const axios_1 = __importDefault(require("axios"));
|
|
13
|
-
const child_process_1 = require("child_process");
|
|
14
|
-
const fs_1 = __importDefault(require("fs"));
|
|
15
|
-
const os_1 = __importDefault(require("os"));
|
|
16
14
|
const path_1 = __importDefault(require("path"));
|
|
17
15
|
const manager_pack_1 = require("../../core/manager-pack");
|
|
18
16
|
const user_config_1 = require("./user-config");
|
|
19
17
|
const local_folder_sync_1 = require("./local-folder-sync");
|
|
20
|
-
const
|
|
18
|
+
const pack_git_publish_1 = require("./pack-git-publish");
|
|
19
|
+
const pack_home_1 = require("./pack-home");
|
|
21
20
|
function managerPackRelativePathFor(filePath) {
|
|
22
21
|
const relativePath = (0, manager_pack_1.managerPackRelativePathForFileName)(filePath);
|
|
23
22
|
if (relativePath)
|
|
24
23
|
return relativePath;
|
|
25
|
-
// Capability files (jobs/skills/rules/templates/scripts) carry their pack-relative
|
|
26
|
-
// path verbatim — the caller supplies the full relative path, not just a basename.
|
|
27
24
|
const base = path_1.default.basename(filePath);
|
|
28
|
-
throw new Error(`Cannot infer manager-pack location for '${base}' (expected manager_context.md, manager_rules.md, a personal learning file, or a full capability path like jobs/<cat>/<name>.md)`);
|
|
29
|
-
}
|
|
30
|
-
function gitCompareUrl(gitUrl, branch) {
|
|
31
|
-
const httpUrl = gitUrl.replace(/\.git$/, '').replace(/^git@([^:]+):/, 'https://$1/');
|
|
32
|
-
if (/^https?:\/\//.test(httpUrl))
|
|
33
|
-
return `${httpUrl}/compare/${branch}?expand=1`;
|
|
34
|
-
return undefined;
|
|
25
|
+
throw new Error(`Cannot infer manager-pack location for '${base}' (expected manager_context.md, manager_rules.md, a personal learning file, or a full capability path like jobs/<cat>/<name>.md or employees/<slug>.json)`);
|
|
35
26
|
}
|
|
36
27
|
async function publishManagerArtifacts(artifacts, opts) {
|
|
37
28
|
const managerStorage = (0, user_config_1.getManagerStorageConfig)();
|
|
@@ -42,7 +33,13 @@ async function publishManagerArtifacts(artifacts, opts) {
|
|
|
42
33
|
throw new Error('No artifacts to publish.');
|
|
43
34
|
for (const artifact of artifacts) {
|
|
44
35
|
if (!(0, manager_pack_1.isManagerPackRelativePath)(artifact.relativePath)) {
|
|
45
|
-
throw new Error(`Invalid manager-pack path '${artifact.relativePath}' (must be context/manager_context.md, rules/manager_rules.md,
|
|
36
|
+
throw new Error(`Invalid manager-pack path '${artifact.relativePath}' (must be context/manager_context.md, rules/manager_rules.md, learnings/<user>-*.md, or a capability path like jobs/<cat>/<name>.md or employees/<slug>.json).`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const deletions = opts?.deletions ?? [];
|
|
40
|
+
for (const relativePath of deletions) {
|
|
41
|
+
if (!(0, manager_pack_1.isManagerPackRelativePath)(relativePath)) {
|
|
42
|
+
throw new Error(`Invalid manager-pack deletion path '${relativePath}'.`);
|
|
46
43
|
}
|
|
47
44
|
}
|
|
48
45
|
if (managerStorage.backend === 'local-folder') {
|
|
@@ -55,7 +52,8 @@ async function publishManagerArtifacts(artifacts, opts) {
|
|
|
55
52
|
}
|
|
56
53
|
writtenPaths.push(path_1.default.join(localPath, artifact.relativePath));
|
|
57
54
|
}
|
|
58
|
-
|
|
55
|
+
const deletedPaths = (0, local_folder_sync_1.removeLocalFolderFiles)(localPath, deletions, artifacts.map((a) => a.relativePath));
|
|
56
|
+
return { backend: 'local-folder', writtenPaths, deletedPaths };
|
|
59
57
|
}
|
|
60
58
|
if (managerStorage.backend === 'fraim-cloud') {
|
|
61
59
|
const remoteUrl = opts?.remoteUrl || process.env.FRAIM_REMOTE_URL || 'https://fraim.wellnessatwork.me';
|
|
@@ -65,27 +63,27 @@ async function publishManagerArtifacts(artifacts, opts) {
|
|
|
65
63
|
const res = await axios_1.default.post(`${remoteUrl.replace(/\/$/, '')}/api/manager/publish`, { artifacts }, { headers: { 'x-api-key': apiKey }, timeout: 30_000 });
|
|
66
64
|
return { backend: 'fraim-cloud', version: String(res.data?.version ?? '') };
|
|
67
65
|
}
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
66
|
+
const change = (0, pack_git_publish_1.describePackChange)('manager', artifacts, deletions);
|
|
67
|
+
const published = await (0, pack_git_publish_1.publishPackToGitRepo)({
|
|
68
|
+
gitUrl: managerStorage.gitUrl,
|
|
69
|
+
artifacts,
|
|
70
|
+
deletions,
|
|
71
|
+
branchSuffix: opts?.branchSuffix,
|
|
72
|
+
branchPrefix: 'fraim-manager-update-',
|
|
73
|
+
commitMessage: change.title,
|
|
74
|
+
prTitle: change.title,
|
|
75
|
+
prBody: change.body,
|
|
76
|
+
openPullRequest: opts?.openPullRequest,
|
|
77
|
+
// Publish from the durable pack home, not a throwaway clone.
|
|
78
|
+
cloneDir: (0, pack_home_1.resolvePackHome)('manager').root,
|
|
79
|
+
});
|
|
80
|
+
return {
|
|
81
|
+
backend: 'git',
|
|
82
|
+
branch: published.branch,
|
|
83
|
+
prUrl: published.prUrl,
|
|
84
|
+
prCreated: published.prCreated,
|
|
85
|
+
prBlockedReason: published.prBlockedReason,
|
|
86
|
+
credentialWarning: published.credentialWarning,
|
|
87
|
+
deletedPaths: deletions,
|
|
88
|
+
};
|
|
91
89
|
}
|
|
@@ -3,12 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.ORG_MANAGED_HEADER = exports.ORG_SYNC_METADATA_FILE = exports.ORG_HOME_DIRNAME = exports.shouldDecorateAsMarkdown = void 0;
|
|
7
7
|
exports.isSafePackPath = isSafePackPath;
|
|
8
8
|
exports.isSafeOrgCapabilityPackPath = isSafeOrgCapabilityPackPath;
|
|
9
|
-
exports.
|
|
10
|
-
exports.
|
|
11
|
-
exports.
|
|
9
|
+
exports.getOrgHomeDir = getOrgHomeDir;
|
|
10
|
+
exports.readOrgSyncMetadata = readOrgSyncMetadata;
|
|
11
|
+
exports.getOrgSyncAgeHours = getOrgSyncAgeHours;
|
|
12
12
|
exports.syncOrgCache = syncOrgCache;
|
|
13
13
|
/**
|
|
14
14
|
* Org cache sync (issue #563).
|
|
@@ -27,16 +27,20 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
27
27
|
const path_1 = __importDefault(require("path"));
|
|
28
28
|
const project_fraim_paths_1 = require("../../core/utils/project-fraim-paths");
|
|
29
29
|
const user_config_1 = require("./user-config");
|
|
30
|
-
const
|
|
30
|
+
const pack_home_1 = require("./pack-home");
|
|
31
31
|
const local_folder_sync_1 = require("./local-folder-sync");
|
|
32
32
|
const capability_pack_1 = require("../../core/capability-pack");
|
|
33
33
|
var capability_pack_2 = require("../../core/capability-pack");
|
|
34
34
|
Object.defineProperty(exports, "shouldDecorateAsMarkdown", { enumerable: true, get: function () { return capability_pack_2.shouldDecorateAsMarkdown; } });
|
|
35
|
-
exports.
|
|
35
|
+
exports.ORG_HOME_DIRNAME = 'org';
|
|
36
36
|
exports.ORG_SYNC_METADATA_FILE = '.org-sync-metadata.json';
|
|
37
|
-
exports.
|
|
38
|
-
/**
|
|
39
|
-
|
|
37
|
+
exports.ORG_MANAGED_HEADER = '<!-- FRAIM_ORG_SYNC_MANAGED_CONTENT -->';
|
|
38
|
+
/**
|
|
39
|
+
* Subdirectories of the org pack that sync into the cache (spec R7.1).
|
|
40
|
+
* Issue #1043 adds 'employees' so an org-shared employee record reaches the
|
|
41
|
+
* cache that custom-employees.ts reads.
|
|
42
|
+
*/
|
|
43
|
+
const ORG_PACK_DIRS = ['context', 'rules', 'learnings', 'jobs', 'skills', 'templates', 'employees'];
|
|
40
44
|
/**
|
|
41
45
|
* Pack files must stay inside the three org pack directories. Applied to
|
|
42
46
|
* every relativePath before it touches the filesystem, so a compromised
|
|
@@ -70,22 +74,51 @@ function isSafeOrgCapabilityPackPath(relativePath) {
|
|
|
70
74
|
return false;
|
|
71
75
|
return true;
|
|
72
76
|
}
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
/**
|
|
78
|
+
* The layer's single home. Named `getOrgHomeDir` for backward compatibility with
|
|
79
|
+
* existing callers; issue #1043 round 2 removed the separate cache it used to
|
|
80
|
+
* point at, so this now resolves the one place the layer lives.
|
|
81
|
+
*/
|
|
82
|
+
function getOrgHomeDir() {
|
|
83
|
+
return (0, pack_home_1.resolvePackHome)('org').root;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Where sync provenance is recorded.
|
|
87
|
+
*
|
|
88
|
+
* Deliberately NOT inside the home. The home is the user's own content: for a
|
|
89
|
+
* git backend it is a real working tree, so a metadata file there shows up as
|
|
90
|
+
* an untracked change in their pack repo, and for a synced folder it would
|
|
91
|
+
* replicate machine-local bookkeeping to every other machine. Provenance is
|
|
92
|
+
* local state, so it belongs in ~/.fraim beside the config.
|
|
93
|
+
*/
|
|
94
|
+
function syncMetadataPath() {
|
|
95
|
+
return path_1.default.join((0, project_fraim_paths_1.getUserFraimDirPath)(), exports.ORG_SYNC_METADATA_FILE);
|
|
96
|
+
}
|
|
97
|
+
/** Record when and from where this machine last synced. Never touches the home. */
|
|
98
|
+
function writeHomeMetadata(metadata) {
|
|
99
|
+
try {
|
|
100
|
+
fs_1.default.mkdirSync((0, project_fraim_paths_1.getUserFraimDirPath)(), { recursive: true });
|
|
101
|
+
fs_1.default.writeFileSync(syncMetadataPath(), JSON.stringify(metadata, null, 2));
|
|
102
|
+
}
|
|
103
|
+
catch { /* provenance is best-effort; never fail a sync over it */ }
|
|
75
104
|
}
|
|
76
|
-
function
|
|
105
|
+
function readOrgSyncMetadata() {
|
|
77
106
|
try {
|
|
78
|
-
const metadataPath =
|
|
79
|
-
if (
|
|
107
|
+
const metadataPath = syncMetadataPath();
|
|
108
|
+
if (fs_1.default.existsSync(metadataPath))
|
|
109
|
+
return JSON.parse(fs_1.default.readFileSync(metadataPath, 'utf8'));
|
|
110
|
+
// A machine that last synced before provenance moved out of the home.
|
|
111
|
+
const legacy = path_1.default.join(getOrgHomeDir(), exports.ORG_SYNC_METADATA_FILE);
|
|
112
|
+
if (!fs_1.default.existsSync(legacy))
|
|
80
113
|
return null;
|
|
81
|
-
return JSON.parse(fs_1.default.readFileSync(
|
|
114
|
+
return JSON.parse(fs_1.default.readFileSync(legacy, 'utf8'));
|
|
82
115
|
}
|
|
83
116
|
catch {
|
|
84
117
|
return null;
|
|
85
118
|
}
|
|
86
119
|
}
|
|
87
|
-
function
|
|
88
|
-
const metadata =
|
|
120
|
+
function getOrgSyncAgeHours() {
|
|
121
|
+
const metadata = readOrgSyncMetadata();
|
|
89
122
|
if (!metadata?.syncedAt)
|
|
90
123
|
return null;
|
|
91
124
|
const syncedAt = Date.parse(metadata.syncedAt);
|
|
@@ -95,7 +128,7 @@ function getOrgCacheAgeHours() {
|
|
|
95
128
|
}
|
|
96
129
|
function decorateManagedOrgFile(content, backend) {
|
|
97
130
|
const normalized = content.replace(/^/, '');
|
|
98
|
-
if (normalized.startsWith(exports.
|
|
131
|
+
if (normalized.startsWith(exports.ORG_MANAGED_HEADER))
|
|
99
132
|
return normalized;
|
|
100
133
|
const writePath = backend === 'git'
|
|
101
134
|
? 'open a pull request against your organization repo'
|
|
@@ -103,7 +136,7 @@ function decorateManagedOrgFile(content, backend) {
|
|
|
103
136
|
? 'edit the file in your synced folder and let the sync client upload it'
|
|
104
137
|
: 'update it through the organization-onboarding flow';
|
|
105
138
|
const marker = [
|
|
106
|
-
exports.
|
|
139
|
+
exports.ORG_MANAGED_HEADER,
|
|
107
140
|
'> [!IMPORTANT]',
|
|
108
141
|
'> Synced from your organization\'s shared context. Local edits are overwritten on the next sync.',
|
|
109
142
|
`> To change this content, ${writePath}.`,
|
|
@@ -145,8 +178,8 @@ async function fetchCloudPack(remoteUrl, apiKey) {
|
|
|
145
178
|
};
|
|
146
179
|
}
|
|
147
180
|
/** Replace the cache contents atomically: stage fully, then swap. */
|
|
148
|
-
function
|
|
149
|
-
const cacheDir =
|
|
181
|
+
function materializeCloudHome(files, metadata) {
|
|
182
|
+
const cacheDir = getOrgHomeDir();
|
|
150
183
|
const stagingDir = `${cacheDir}.staging-${process.pid}`;
|
|
151
184
|
fs_1.default.rmSync(stagingDir, { recursive: true, force: true });
|
|
152
185
|
fs_1.default.mkdirSync(stagingDir, { recursive: true });
|
|
@@ -162,7 +195,7 @@ function materializeCache(files, metadata) {
|
|
|
162
195
|
: file.content;
|
|
163
196
|
fs_1.default.writeFileSync(destination, content);
|
|
164
197
|
}
|
|
165
|
-
|
|
198
|
+
// Provenance is written outside the home by writeHomeMetadata.
|
|
166
199
|
fs_1.default.rmSync(cacheDir, { recursive: true, force: true });
|
|
167
200
|
fs_1.default.renameSync(stagingDir, cacheDir);
|
|
168
201
|
}
|
|
@@ -191,12 +224,12 @@ async function discoverCloudOrganization(options) {
|
|
|
191
224
|
}
|
|
192
225
|
function failureOutcome(error) {
|
|
193
226
|
const message = error instanceof Error ? error.message : String(error);
|
|
194
|
-
const existing =
|
|
227
|
+
const existing = readOrgSyncMetadata();
|
|
195
228
|
if (existing) {
|
|
196
229
|
return {
|
|
197
230
|
status: 'stale',
|
|
198
231
|
metadata: existing,
|
|
199
|
-
ageHours:
|
|
232
|
+
ageHours: getOrgSyncAgeHours() ?? 0,
|
|
200
233
|
error: message
|
|
201
234
|
};
|
|
202
235
|
}
|
|
@@ -221,32 +254,35 @@ async function syncOrgCache(options) {
|
|
|
221
254
|
}
|
|
222
255
|
try {
|
|
223
256
|
if (organization.backend === 'local-folder') {
|
|
257
|
+
// Issue #1043 round 2: the configured folder IS the home. There is
|
|
258
|
+
// no cache to materialize into; the OS sync client is the transport
|
|
259
|
+
// and the files are already the single place FRAIM reads.
|
|
224
260
|
const localPath = organization.localPath;
|
|
225
|
-
const files = (0, local_folder_sync_1.collectLocalFolderFiles)(localPath, (rel) => isSafePackPath(rel) || isSafeOrgCapabilityPackPath(rel));
|
|
226
261
|
const metadata = {
|
|
227
262
|
version: (0, local_folder_sync_1.localFolderVersion)(localPath),
|
|
228
263
|
backend: 'local-folder',
|
|
229
264
|
source: localPath,
|
|
230
265
|
syncedAt: new Date().toISOString(),
|
|
231
266
|
};
|
|
232
|
-
|
|
267
|
+
writeHomeMetadata(metadata);
|
|
233
268
|
return { status: 'synced', metadata };
|
|
234
269
|
}
|
|
235
270
|
if (organization.backend === 'git') {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
271
|
+
// Issue #1043 round 2: the durable clone IS the home. ensurePackClone
|
|
272
|
+
// already fast-forwarded it, so syncing is that pull, not a copy into
|
|
273
|
+
// a second location.
|
|
274
|
+
const home = (0, pack_home_1.resolvePackHome)('org');
|
|
275
|
+
const clone = (0, pack_home_1.ensurePackClone)(organization.gitUrl, home.root);
|
|
276
|
+
if (clone.sha === null)
|
|
277
|
+
throw new Error(clone.offlineReason ?? 'Pack clone unavailable.');
|
|
278
|
+
const metadata = {
|
|
279
|
+
version: clone.sha,
|
|
280
|
+
backend: 'git',
|
|
281
|
+
source: organization.gitUrl,
|
|
282
|
+
syncedAt: new Date().toISOString()
|
|
283
|
+
};
|
|
284
|
+
writeHomeMetadata(metadata);
|
|
285
|
+
return { status: 'synced', metadata };
|
|
250
286
|
}
|
|
251
287
|
const remoteUrl = options?.remoteUrl || process.env.FRAIM_REMOTE_URL || 'https://fraim.wellnessatwork.me';
|
|
252
288
|
const apiKey = options?.apiKey || (0, user_config_1.readUserFraimConfig)().apiKey;
|
|
@@ -259,7 +295,10 @@ async function syncOrgCache(options) {
|
|
|
259
295
|
source: remoteUrl,
|
|
260
296
|
syncedAt: new Date().toISOString()
|
|
261
297
|
};
|
|
262
|
-
|
|
298
|
+
// The cloud has no user-visible folder, so this managed directory is the
|
|
299
|
+
// home for that backend, not a cache beside one.
|
|
300
|
+
materializeCloudHome(pack.files, metadata);
|
|
301
|
+
writeHomeMetadata(metadata);
|
|
263
302
|
return { status: 'synced', metadata };
|
|
264
303
|
}
|
|
265
304
|
catch (error) {
|
|
@@ -13,24 +13,22 @@ exports.publishOrgArtifacts = publishOrgArtifacts;
|
|
|
13
13
|
* call: the read side is the synced `~/.fraim/org/` cache, the write side is
|
|
14
14
|
* here. Supports both backends:
|
|
15
15
|
* - fraim-cloud: POST /api/org/publish (authenticated by the user's API key)
|
|
16
|
-
* - git: shallow-clone the org repo,
|
|
17
|
-
* and
|
|
16
|
+
* - git: shallow-clone the org repo, apply the writes and deletions on a
|
|
17
|
+
* branch as one commit, push it, and open the pull request for the team.
|
|
18
18
|
*/
|
|
19
19
|
const axios_1 = __importDefault(require("axios"));
|
|
20
|
-
const child_process_1 = require("child_process");
|
|
21
|
-
const fs_1 = __importDefault(require("fs"));
|
|
22
|
-
const os_1 = __importDefault(require("os"));
|
|
23
20
|
const path_1 = __importDefault(require("path"));
|
|
24
21
|
const user_config_1 = require("./user-config");
|
|
25
22
|
const local_folder_sync_1 = require("./local-folder-sync");
|
|
26
23
|
const capability_pack_1 = require("../../core/capability-pack");
|
|
24
|
+
const pack_git_publish_1 = require("./pack-git-publish");
|
|
25
|
+
const pack_home_1 = require("./pack-home");
|
|
27
26
|
const PACK_RELATIVE_PATH = /^(context|rules|learnings)\/[\w.-]+\.md$/;
|
|
28
27
|
// #868: the company brand descriptor is JSON stored beside org_context.md. It
|
|
29
28
|
// publishes through the same backends as org markdown but is delivered verbatim
|
|
30
29
|
// (no managed-content header — that decoration is markdown-only, added on sync).
|
|
31
30
|
// Mirrors org-pack-sync.isSafePackPath and fraim-mcp-server.isOrgPackPublishRelativePath.
|
|
32
31
|
const ORG_BRAND_PACK_PATH = 'context/org_brand.json';
|
|
33
|
-
const ALLOWED_GIT_URL = /^(https?:\/\/|ssh:\/\/|git:\/\/|file:\/\/|[\w.-]+@[\w.-]+:)/;
|
|
34
32
|
/**
|
|
35
33
|
* Infer the org-pack location for a local file by its name or path:
|
|
36
34
|
* org_context.md -> context/org_context.md
|
|
@@ -56,12 +54,6 @@ function packRelativePathFor(filePath) {
|
|
|
56
54
|
return `learnings/${base}`;
|
|
57
55
|
throw new Error(`Cannot infer org-pack location for '${base}' (expected org_context.md, org_rules.md, org_brand.json, org-*.md, or a capability path like jobs/<cat>/<name>.md)`);
|
|
58
56
|
}
|
|
59
|
-
function gitCompareUrl(gitUrl, branch) {
|
|
60
|
-
const httpUrl = gitUrl.replace(/\.git$/, '').replace(/^git@([^:]+):/, 'https://$1/');
|
|
61
|
-
if (/^https?:\/\//.test(httpUrl))
|
|
62
|
-
return `${httpUrl}/compare/${branch}?expand=1`;
|
|
63
|
-
return undefined;
|
|
64
|
-
}
|
|
65
57
|
/**
|
|
66
58
|
* Publish a set of org artifacts to the configured backend. Throws with a clear
|
|
67
59
|
* message when no backend is configured, a path is outside the pack layout, or
|
|
@@ -74,13 +66,17 @@ async function publishOrgArtifacts(artifacts, opts) {
|
|
|
74
66
|
}
|
|
75
67
|
if (artifacts.length === 0)
|
|
76
68
|
throw new Error('No artifacts to publish.');
|
|
69
|
+
const isValidOrgPackPath = (rel) => PACK_RELATIVE_PATH.test(rel) || rel === ORG_BRAND_PACK_PATH || (0, capability_pack_1.isCapabilityPackPath)(rel);
|
|
77
70
|
for (const a of artifacts) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (!isLegacyPath && !isCapabilityPath) {
|
|
81
|
-
throw new Error(`Invalid org-pack path '${a.relativePath}' (must be context|rules|learnings/<name>.md, context/org_brand.json, or a capability path like jobs/<cat>/<name>.md).`);
|
|
71
|
+
if (!isValidOrgPackPath(a.relativePath)) {
|
|
72
|
+
throw new Error(`Invalid org-pack path '${a.relativePath}' (must be context|rules|learnings/<name>.md, context/org_brand.json, or a capability path like jobs/<cat>/<name>.md or employees/<slug>.json).`);
|
|
82
73
|
}
|
|
83
74
|
}
|
|
75
|
+
const deletions = opts?.deletions ?? [];
|
|
76
|
+
for (const rel of deletions) {
|
|
77
|
+
if (!isValidOrgPackPath(rel))
|
|
78
|
+
throw new Error(`Invalid org-pack deletion path '${rel}'.`);
|
|
79
|
+
}
|
|
84
80
|
if (organization.backend === 'local-folder') {
|
|
85
81
|
const localPath = organization.localPath;
|
|
86
82
|
const writtenPaths = [];
|
|
@@ -91,7 +87,8 @@ async function publishOrgArtifacts(artifacts, opts) {
|
|
|
91
87
|
}
|
|
92
88
|
writtenPaths.push(path_1.default.join(localPath, a.relativePath));
|
|
93
89
|
}
|
|
94
|
-
|
|
90
|
+
const deletedPaths = (0, local_folder_sync_1.removeLocalFolderFiles)(localPath, deletions, artifacts.map((a) => a.relativePath));
|
|
91
|
+
return { backend: 'local-folder', writtenPaths, deletedPaths };
|
|
95
92
|
}
|
|
96
93
|
if (organization.backend === 'fraim-cloud') {
|
|
97
94
|
const remoteUrl = opts?.remoteUrl || process.env.FRAIM_REMOTE_URL || 'https://fraim.wellnessatwork.me';
|
|
@@ -102,27 +99,27 @@ async function publishOrgArtifacts(artifacts, opts) {
|
|
|
102
99
|
return { backend: 'fraim-cloud', version: String(res.data?.version ?? '') };
|
|
103
100
|
}
|
|
104
101
|
// git backend
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
102
|
+
const change = (0, pack_git_publish_1.describePackChange)('organization', artifacts, deletions);
|
|
103
|
+
const published = await (0, pack_git_publish_1.publishPackToGitRepo)({
|
|
104
|
+
gitUrl: organization.gitUrl,
|
|
105
|
+
artifacts,
|
|
106
|
+
deletions,
|
|
107
|
+
branchSuffix: opts?.branchSuffix,
|
|
108
|
+
branchPrefix: 'fraim-org-update-',
|
|
109
|
+
commitMessage: change.title,
|
|
110
|
+
prTitle: change.title,
|
|
111
|
+
prBody: change.body,
|
|
112
|
+
openPullRequest: opts?.openPullRequest,
|
|
113
|
+
// Publish from the durable pack home, not a throwaway clone.
|
|
114
|
+
cloneDir: (0, pack_home_1.resolvePackHome)('org').root,
|
|
115
|
+
});
|
|
116
|
+
return {
|
|
117
|
+
backend: 'git',
|
|
118
|
+
branch: published.branch,
|
|
119
|
+
prUrl: published.prUrl,
|
|
120
|
+
prCreated: published.prCreated,
|
|
121
|
+
prBlockedReason: published.prBlockedReason,
|
|
122
|
+
credentialWarning: published.credentialWarning,
|
|
123
|
+
deletedPaths: deletions,
|
|
124
|
+
};
|
|
128
125
|
}
|