fraim-hub 2.0.305 → 2.0.306
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.
|
@@ -3,6 +3,7 @@ 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._internal = void 0;
|
|
6
7
|
exports.certPaths = certPaths;
|
|
7
8
|
exports.loadOrCreateCert = loadOrCreateCert;
|
|
8
9
|
exports.trustCert = trustCert;
|
|
@@ -49,6 +50,15 @@ async function loadOrCreateCert() {
|
|
|
49
50
|
// HTTPS loopback certificate to be trusted before it can render the task pane.
|
|
50
51
|
return { key: pem.private, cert: pem.cert };
|
|
51
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Test seam (issue #1589): the real OS command invocation goes through this mutable,
|
|
55
|
+
* module-owned indirection point instead of a bare `spawnSync` call, so a test can swap in
|
|
56
|
+
* a fake implementation and assert on the exact command/arguments `trustCert()`/`untrustCert()`
|
|
57
|
+
* would invoke, without spawning a process, touching PATH, or mutating the real trust store.
|
|
58
|
+
* Swapping the export on Node's built-in `child_process` module itself is not reliable for
|
|
59
|
+
* this (confirmed empirically while fixing this issue) - this repo-owned seam is.
|
|
60
|
+
*/
|
|
61
|
+
exports._internal = { spawnSync: child_process_1.spawnSync };
|
|
52
62
|
/**
|
|
53
63
|
* Installs the cert as a trusted root CA in the user's OS certificate store.
|
|
54
64
|
* ONLY call this for explicit Word-Online support — it prompts a Windows security
|
|
@@ -59,7 +69,7 @@ async function loadOrCreateCert() {
|
|
|
59
69
|
*/
|
|
60
70
|
function trustCert(certPath) {
|
|
61
71
|
if (process.platform === 'win32') {
|
|
62
|
-
const result =
|
|
72
|
+
const result = exports._internal.spawnSync('certutil', ['-addstore', '-user', 'Root', certPath], { encoding: 'utf8' });
|
|
63
73
|
if (result.status !== 0) {
|
|
64
74
|
console.warn('[fraim] could not trust localhost certificate:', result.stderr || result.stdout);
|
|
65
75
|
}
|
|
@@ -67,17 +77,17 @@ function trustCert(certPath) {
|
|
|
67
77
|
}
|
|
68
78
|
if (process.platform === 'darwin') {
|
|
69
79
|
const keychain = path_1.default.join(os_1.default.homedir(), 'Library', 'Keychains', 'login.keychain-db');
|
|
70
|
-
|
|
80
|
+
exports._internal.spawnSync('security', ['add-trusted-cert', '-r', 'trustRoot', '-k', keychain, certPath], { stdio: 'ignore' });
|
|
71
81
|
}
|
|
72
82
|
}
|
|
73
83
|
/** Removes a specific cert from the trust store, by fingerprint. Test-only helper. */
|
|
74
84
|
function untrustCert(fingerprint) {
|
|
75
85
|
if (process.platform === 'win32') {
|
|
76
|
-
|
|
86
|
+
exports._internal.spawnSync('certutil', ['-delstore', '-user', 'Root', fingerprint], { encoding: 'utf8' });
|
|
77
87
|
return;
|
|
78
88
|
}
|
|
79
89
|
if (process.platform === 'darwin') {
|
|
80
|
-
|
|
90
|
+
exports._internal.spawnSync('security', ['delete-certificate', '-Z', fingerprint], { stdio: 'ignore' });
|
|
81
91
|
}
|
|
82
92
|
}
|
|
83
93
|
/**
|
|
@@ -22,6 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
22
22
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
23
|
};
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports._internal = exports.WEF_DEVELOPER_KEY = void 0;
|
|
25
26
|
exports.manifestXmlForPort = manifestXmlForPort;
|
|
26
27
|
exports.shouldSkipSideloadForFlag = shouldSkipSideloadForFlag;
|
|
27
28
|
exports.winDeveloperManifestSubkey = winDeveloperManifestSubkey;
|
|
@@ -32,7 +33,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
32
33
|
const path_1 = __importDefault(require("path"));
|
|
33
34
|
const os_1 = __importDefault(require("os"));
|
|
34
35
|
const child_process_1 = require("child_process");
|
|
35
|
-
|
|
36
|
+
exports.WEF_DEVELOPER_KEY = 'HKCU\\SOFTWARE\\Microsoft\\Office\\16.0\\WEF\\Developer';
|
|
36
37
|
const MANIFESTS = [
|
|
37
38
|
{
|
|
38
39
|
guid: 'd1090951-50cf-4cf2-9d12-b0f8541d265c',
|
|
@@ -93,7 +94,7 @@ function prepareManifestForSideload(entry, sourcePath, options) {
|
|
|
93
94
|
// Windows registry helpers
|
|
94
95
|
// ---------------------------------------------------------------------------
|
|
95
96
|
function winDeveloperManifestSubkey(guid) {
|
|
96
|
-
return `${WEF_DEVELOPER_KEY}\\{${guid}}`;
|
|
97
|
+
return `${exports.WEF_DEVELOPER_KEY}\\{${guid}}`;
|
|
97
98
|
}
|
|
98
99
|
function parseRegSzValue(stdout) {
|
|
99
100
|
const line = stdout.split(/\r?\n/).find(l => l.includes('REG_SZ'));
|
|
@@ -103,7 +104,7 @@ function parseRegSzValue(stdout) {
|
|
|
103
104
|
return line.slice(idx + 'REG_SZ'.length).trim() || null;
|
|
104
105
|
}
|
|
105
106
|
function winRegisteredRootValue(guid) {
|
|
106
|
-
const r = (0, child_process_1.spawnSync)('reg', ['query', WEF_DEVELOPER_KEY, '/v', guid], { encoding: 'utf8' });
|
|
107
|
+
const r = (0, child_process_1.spawnSync)('reg', ['query', exports.WEF_DEVELOPER_KEY, '/v', guid], { encoding: 'utf8' });
|
|
107
108
|
if (r.status !== 0 || !r.stdout.includes('REG_SZ'))
|
|
108
109
|
return null;
|
|
109
110
|
// Output line looks like: " <guid> REG_SZ C:\path\to\manifest.xml"
|
|
@@ -122,14 +123,21 @@ function winRegisteredValue(guid) {
|
|
|
122
123
|
// but treat the root value as the effective discovery registration.
|
|
123
124
|
return winRegisteredRootValue(guid) ?? winRegisteredDefaultValue(guid);
|
|
124
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Test seam (issue #1589): the registry-write invocations go through this mutable,
|
|
128
|
+
* module-owned indirection point instead of a bare `spawnSync` call, so a test can swap in a
|
|
129
|
+
* fake implementation and assert on the exact `reg` command/arguments `sideloadManifest()`
|
|
130
|
+
* would invoke, without spawning a process, touching PATH, or mutating the real registry.
|
|
131
|
+
*/
|
|
132
|
+
exports._internal = { spawnSync: child_process_1.spawnSync };
|
|
125
133
|
function winWriteRegisteredValue(guid, manifestPath) {
|
|
126
|
-
const root =
|
|
127
|
-
'add', WEF_DEVELOPER_KEY,
|
|
134
|
+
const root = exports._internal.spawnSync('reg', [
|
|
135
|
+
'add', exports.WEF_DEVELOPER_KEY,
|
|
128
136
|
'/v', guid, '/t', 'REG_SZ', '/d', manifestPath, '/f',
|
|
129
137
|
], { encoding: 'utf8' });
|
|
130
138
|
if (root.status !== 0)
|
|
131
139
|
return { ok: false, reason: root.stderr || `reg add failed for ${guid}` };
|
|
132
|
-
const r =
|
|
140
|
+
const r = exports._internal.spawnSync('reg', [
|
|
133
141
|
'add', winDeveloperManifestSubkey(guid),
|
|
134
142
|
'/ve', '/t', 'REG_SZ', '/d', manifestPath, '/f',
|
|
135
143
|
], { encoding: 'utf8' });
|
|
@@ -137,7 +145,7 @@ function winWriteRegisteredValue(guid, manifestPath) {
|
|
|
137
145
|
return { ok: false, reason: r.stderr || `reg add failed for ${guid}` };
|
|
138
146
|
// Remove an accidental unbraced subkey left by older debugger settings. This
|
|
139
147
|
// is different from the root named value above, which Word needs.
|
|
140
|
-
|
|
148
|
+
exports._internal.spawnSync('reg', ['delete', `${exports.WEF_DEVELOPER_KEY}\\${guid}`, '/f'], { encoding: 'utf8' });
|
|
141
149
|
return { ok: true };
|
|
142
150
|
}
|
|
143
151
|
// ---------------------------------------------------------------------------
|
|
@@ -195,8 +203,8 @@ function sideloadManifest(projectPath, options = {}) {
|
|
|
195
203
|
function removeSideload() {
|
|
196
204
|
for (const entry of MANIFESTS) {
|
|
197
205
|
if (process.platform === 'win32') {
|
|
198
|
-
(0, child_process_1.spawnSync)('reg', ['delete', WEF_DEVELOPER_KEY, '/v', entry.guid, '/f'], { encoding: 'utf8' });
|
|
199
|
-
(0, child_process_1.spawnSync)('reg', ['delete', `${WEF_DEVELOPER_KEY}\\${entry.guid}`, '/f'], { encoding: 'utf8' });
|
|
206
|
+
(0, child_process_1.spawnSync)('reg', ['delete', exports.WEF_DEVELOPER_KEY, '/v', entry.guid, '/f'], { encoding: 'utf8' });
|
|
207
|
+
(0, child_process_1.spawnSync)('reg', ['delete', `${exports.WEF_DEVELOPER_KEY}\\${entry.guid}`, '/f'], { encoding: 'utf8' });
|
|
200
208
|
(0, child_process_1.spawnSync)('reg', ['delete', winDeveloperManifestSubkey(entry.guid), '/f'], { encoding: 'utf8' });
|
|
201
209
|
}
|
|
202
210
|
else if (process.platform === 'darwin') {
|
|
@@ -69,6 +69,7 @@ const script_sync_utils_1 = require("../utils/script-sync-utils");
|
|
|
69
69
|
*/
|
|
70
70
|
const USER_LEVEL_RUNTIME_DEPS = {
|
|
71
71
|
'node-edge-tts': '*', // used by scripts/author-audio.js
|
|
72
|
+
'adm-zip': '^0.6.0', // used by scripts/communication/*.js (DOCX review layer) — matches root/packages/* manifests
|
|
72
73
|
};
|
|
73
74
|
/**
|
|
74
75
|
* Ensure the user-level FRAIM directory structure exists.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fraim-hub",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.306",
|
|
4
4
|
"description": "FRAIM Hub local companion package.",
|
|
5
5
|
"author": "Sid Mathur <sid.mathur@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/mathursrus/FRAIM#readme",
|
|
@@ -211,7 +211,7 @@
|
|
|
211
211
|
"electron-updater": "^6.8.9",
|
|
212
212
|
"express": "^5.2.1",
|
|
213
213
|
"extract-zip": "^2.0.1",
|
|
214
|
-
"fraim": "2.0.
|
|
214
|
+
"fraim": "2.0.306",
|
|
215
215
|
"mongodb": "^7.0.0",
|
|
216
216
|
"node-cron": "4.2.1",
|
|
217
217
|
"node-edge-tts": "^1.2.10",
|
package/public/ai-hub/script.js
CHANGED
|
@@ -13560,41 +13560,38 @@ function tfMostRecentMatch(convs, predicate) {
|
|
|
13560
13560
|
return convs.filter(predicate).sort((a, b) => (b.lastUpdatedAt || 0) - (a.lastUpdatedAt || 0))[0] || null;
|
|
13561
13561
|
}
|
|
13562
13562
|
|
|
13563
|
-
//
|
|
13564
|
-
//
|
|
13565
|
-
|
|
13566
|
-
|
|
13567
|
-
|
|
13568
|
-
|
|
13563
|
+
// #1601: tfActiveMgrConv() (#1408) and tfActiveOrgConv() (#1124/#1601) both resolve
|
|
13564
|
+
// "the one most-active conversation for this scope" — running > waiting > has real
|
|
13565
|
+
// content — differing only in which scope they select. Shared here instead of two
|
|
13566
|
+
// near-identical copies. convScope() reads an explicit scope/invokedArea tag rather
|
|
13567
|
+
// than jobId or bucket location, so a project-scoped run (no scope field, e.g. a
|
|
13568
|
+
// legacy manager-agreements or organizational-learning-synthesis record) always
|
|
13569
|
+
// resolves to 'project' and is correctly excluded here regardless of which bucket
|
|
13570
|
+
// it lives in — scanning all buckets by scope is safe for both callers.
|
|
13571
|
+
function tfActiveScopedConv(scope) {
|
|
13572
|
+
const convs = Object.values(state.conversations || {}).flat().filter((c) => c && convScope(c) === scope);
|
|
13569
13573
|
return (
|
|
13570
13574
|
tfMostRecentMatch(convs, (c) => c.status === 'running') ||
|
|
13571
13575
|
tfMostRecentMatch(convs, (c) => c.status === 'waiting') ||
|
|
13572
|
-
|
|
13576
|
+
// #782/#1408/#1601: only a conversation with real content should replace the
|
|
13577
|
+
// area's info view. A message-less completed conv (e.g. a provisional freeform
|
|
13578
|
+
// run that emitted nothing) is a phantom, not a conversation to surface.
|
|
13579
|
+
tfMostRecentMatch(convs, (c) => (c.messages || []).length > 0) ||
|
|
13573
13580
|
null
|
|
13574
13581
|
);
|
|
13575
13582
|
}
|
|
13576
13583
|
|
|
13584
|
+
// Issue #1124: return the company-scoped conversation to show in the Company area.
|
|
13585
|
+
function tfActiveOrgConv() {
|
|
13586
|
+
return tfActiveScopedConv('company');
|
|
13587
|
+
}
|
|
13588
|
+
|
|
13577
13589
|
// #594 R2: return the manager-scoped conversation to show in Manager area.
|
|
13578
13590
|
// #702/#1408: manager-tab runs are those invoked from the manager area (any persona job,
|
|
13579
|
-
// including manager-agreements), decided by scope alone.
|
|
13580
|
-
//
|
|
13581
|
-
// default and won't be picked here; it's still reachable, just not as this tab's
|
|
13582
|
-
// single "most active" spotlight. An active manager-invoked run surfaces in the
|
|
13583
|
-
// Manager conversation host (Coach panel included).
|
|
13591
|
+
// including manager-agreements), decided by scope alone. An active manager-invoked run
|
|
13592
|
+
// surfaces in the Manager conversation host (Coach panel included).
|
|
13584
13593
|
function tfActiveMgrConv() {
|
|
13585
|
-
|
|
13586
|
-
// was genuinely invoked from the Manager tab (convScope(c) === 'manager').
|
|
13587
|
-
const convs = Object.values(state.conversations || {}).flat().filter((c) => c && convScope(c) === 'manager');
|
|
13588
|
-
return (
|
|
13589
|
-
tfMostRecentMatch(convs, (c) => c.status === 'running') ||
|
|
13590
|
-
tfMostRecentMatch(convs, (c) => c.status === 'waiting') ||
|
|
13591
|
-
// #782: only a conversation with real content should replace the Manager info
|
|
13592
|
-
// view (Context / Rules / Learnings). A message-less completed conv (e.g. a
|
|
13593
|
-
// provisional __freeform__ run that emitted nothing) is a phantom, not a
|
|
13594
|
-
// conversation to surface — ignoring it keeps the info view as the tab's home.
|
|
13595
|
-
tfMostRecentMatch(convs, (c) => (c.messages || []).length > 0) ||
|
|
13596
|
-
null
|
|
13597
|
-
);
|
|
13594
|
+
return tfActiveScopedConv('manager');
|
|
13598
13595
|
}
|
|
13599
13596
|
|
|
13600
13597
|
// #1397: resolve one stable destination for an area. Polling may refresh the
|