fraim-hub 2.0.228 → 2.0.229
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.
|
@@ -757,7 +757,7 @@ class AiHubConversationStore {
|
|
|
757
757
|
}
|
|
758
758
|
// Update the index header for one conversation and return the (header-shaped) project state.
|
|
759
759
|
reindexAfterUpsert(bucketDir, bucketKey, conv, activeId) {
|
|
760
|
-
const idx = this.
|
|
760
|
+
const idx = this.loadIndex(bucketDir, bucketKey);
|
|
761
761
|
const headers = idx.headers.filter((h) => h.id !== conv.id);
|
|
762
762
|
headers.push(toHeader(conv));
|
|
763
763
|
headers.sort(newestFirst);
|
|
@@ -2927,19 +2927,30 @@ class AiHubServer {
|
|
|
2927
2927
|
return res.status(400).json({ error: 'projectPath required for project conversations' });
|
|
2928
2928
|
}
|
|
2929
2929
|
const projectPath = scope ? (0, conversation_store_1.conversationScopeKey)(scope, '') : ensureDirectoryPath(body.projectPath);
|
|
2930
|
-
const
|
|
2930
|
+
const patch = { ...body };
|
|
2931
|
+
delete patch.projectPath;
|
|
2932
|
+
delete patch.scope;
|
|
2933
|
+
delete patch.activeId;
|
|
2934
|
+
const patchFields = Object.keys(patch);
|
|
2935
|
+
let saved = null;
|
|
2931
2936
|
if (patchFields.length > 0) {
|
|
2932
|
-
this.conversationStore.patchConversation(projectPath, req.params.conversationId,
|
|
2937
|
+
saved = this.conversationStore.patchConversation(projectPath, req.params.conversationId, patch);
|
|
2933
2938
|
}
|
|
2934
2939
|
if (body.activeId !== undefined) {
|
|
2935
2940
|
// Body-safe: set activeId via the index, never by rewriting conversation bodies (#820).
|
|
2936
|
-
this.conversationStore.setActiveId(projectPath, body.activeId);
|
|
2941
|
+
saved = this.conversationStore.setActiveId(projectPath, body.activeId);
|
|
2937
2942
|
}
|
|
2938
2943
|
if (patchFields.length === 0 && body.activeId !== undefined) {
|
|
2939
2944
|
return res.json({ projectPath, scope: scope ?? 'project', activeId: body.activeId, source: 'disk' });
|
|
2940
2945
|
}
|
|
2941
|
-
const
|
|
2942
|
-
return res.json({
|
|
2946
|
+
const conversation = saved?.conversations.find((entry) => entry.id === req.params.conversationId) ?? null;
|
|
2947
|
+
return res.json({
|
|
2948
|
+
projectPath,
|
|
2949
|
+
scope: scope ?? 'project',
|
|
2950
|
+
activeId: saved?.activeId ?? null,
|
|
2951
|
+
conversation,
|
|
2952
|
+
source: 'disk',
|
|
2953
|
+
});
|
|
2943
2954
|
}
|
|
2944
2955
|
catch (error) {
|
|
2945
2956
|
return res.status(400).json({ error: error instanceof Error ? error.message : 'Could not persist conversation.' });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fraim-hub",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.229",
|
|
4
4
|
"description": "FRAIM Hub local companion package.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"fraim-hub": "bin/fraim-hub.js"
|
|
@@ -158,7 +158,7 @@
|
|
|
158
158
|
"electron": "^41.2.2",
|
|
159
159
|
"electron-updater": "^6.8.9",
|
|
160
160
|
"express": "^5.2.1",
|
|
161
|
-
"fraim": "2.0.
|
|
161
|
+
"fraim": "2.0.229",
|
|
162
162
|
"mongodb": "^7.0.0",
|
|
163
163
|
"node-cron": "4.2.1",
|
|
164
164
|
"node-edge-tts": "^1.2.10",
|
package/public/ai-hub/script.js
CHANGED
|
@@ -728,6 +728,29 @@ function persistActiveConversationSelection(id) {
|
|
|
728
728
|
});
|
|
729
729
|
}
|
|
730
730
|
|
|
731
|
+
function persistConversation(conv) {
|
|
732
|
+
if (!conv || !conv.id) return;
|
|
733
|
+
const body = slimConversationForPersist(conv);
|
|
734
|
+
if (!body || typeof body !== 'object') return;
|
|
735
|
+
const scope = convScope(conv);
|
|
736
|
+
if (scope === 'manager' || scope === 'company') body.scope = scope;
|
|
737
|
+
else {
|
|
738
|
+
body.projectPath = conv.projectPath || state.projectPath || '';
|
|
739
|
+
if (!body.projectPath) return;
|
|
740
|
+
}
|
|
741
|
+
if (state.activeId === conv.id) body.activeId = conv.id;
|
|
742
|
+
requestJson(`/api/ai-hub/conversations/${encodeURIComponent(conv.id)}`, {
|
|
743
|
+
method: 'PATCH',
|
|
744
|
+
headers: { 'Content-Type': 'application/json' },
|
|
745
|
+
body: JSON.stringify(body),
|
|
746
|
+
}).then(() => {
|
|
747
|
+
state.conversationDiskAvailable = true;
|
|
748
|
+
}).catch((error) => {
|
|
749
|
+
state.conversationDiskAvailable = false;
|
|
750
|
+
console.warn('Could not persist conversation to local disk:', error);
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
|
|
731
754
|
function projectConversationPayload() {
|
|
732
755
|
return {
|
|
733
756
|
projectPath: state.projectPath || '',
|
|
@@ -1260,7 +1283,7 @@ function upsertConversation(conv, options) {
|
|
|
1260
1283
|
else list.unshift(conv);
|
|
1261
1284
|
state.conversations[key] = list;
|
|
1262
1285
|
const opts = options || {};
|
|
1263
|
-
if (opts.disk !== false)
|
|
1286
|
+
if (opts.disk !== false) persistConversation(conv);
|
|
1264
1287
|
}
|
|
1265
1288
|
|
|
1266
1289
|
function newConversationId() {
|
|
@@ -4834,10 +4857,10 @@ function isTaughtJob(jobId) {
|
|
|
4834
4857
|
// Start the evolve-employee job, optionally seeded from a completed run or a
|
|
4835
4858
|
// document. This is the single entry point shared by the rail teach button,
|
|
4836
4859
|
// roster chip, and the "+ New job" palette teach entries.
|
|
4837
|
-
function startTeachFlow(opts) {
|
|
4838
|
-
const options = opts || {};
|
|
4839
|
-
const employeeId = (state.bootstrap && state.bootstrap.preferences && state.bootstrap.preferences.employeeId) || 'claude';
|
|
4840
|
-
const seedConv = options.seedConv || null;
|
|
4860
|
+
function startTeachFlow(opts) {
|
|
4861
|
+
const options = opts || {};
|
|
4862
|
+
const employeeId = (state.bootstrap && state.bootstrap.preferences && state.bootstrap.preferences.employeeId) || 'claude';
|
|
4863
|
+
const seedConv = options.seedConv || null;
|
|
4841
4864
|
let instructions = '';
|
|
4842
4865
|
if (options.seedSource === 'run' && seedConv) {
|
|
4843
4866
|
const transcript = (seedConv.messages || [])
|
|
@@ -4854,9 +4877,13 @@ function startTeachFlow(opts) {
|
|
|
4854
4877
|
} else {
|
|
4855
4878
|
instructions = 'Teach yourself a new job. I will describe the capability I want. Pre-fill the plan, check for an existing job first, and recommend which employee should own it.';
|
|
4856
4879
|
}
|
|
4857
|
-
const job = {
|
|
4858
|
-
|
|
4859
|
-
|
|
4880
|
+
const job = {
|
|
4881
|
+
id: 'evolve-employee',
|
|
4882
|
+
title: options.mode === 'customize' ? 'Improve a job' : 'Teach a new job',
|
|
4883
|
+
requiredPersonaKey: 'mandy',
|
|
4884
|
+
};
|
|
4885
|
+
startRun(job, instructions, employeeId);
|
|
4886
|
+
}
|
|
4860
4887
|
|
|
4861
4888
|
// Comments follow the artifact (R7.7): a PR opens GitHub; local artifacts open
|
|
4862
4889
|
// from disk; reports view inline. Nothing new is invented - these surface what
|
|
@@ -6027,10 +6054,10 @@ async function startRun(job, instructions, employeeId, preassignedConvId, invoke
|
|
|
6027
6054
|
};
|
|
6028
6055
|
upsertConversation(conv);
|
|
6029
6056
|
state.activeId = conv.id;
|
|
6057
|
+
persistActiveConversationSelection(conv.id);
|
|
6030
6058
|
// Issue #539: make Cmd/Ctrl+Shift+R available as soon as the run is queued,
|
|
6031
6059
|
// not only after the server responds with the run id.
|
|
6032
6060
|
state.lastRun = { job, instructions, employeeId };
|
|
6033
|
-
persistConversations();
|
|
6034
6061
|
renderRail();
|
|
6035
6062
|
renderActive();
|
|
6036
6063
|
|
|
@@ -6907,14 +6934,12 @@ function renderDelegateButton(personaKey) {
|
|
|
6907
6934
|
|
|
6908
6935
|
function wireEvents() {
|
|
6909
6936
|
els['project-button'].addEventListener('click', pickProject);
|
|
6910
|
-
els['new-conv-btn'].addEventListener('click', openModal);
|
|
6911
|
-
if (els['teach-btn']) {
|
|
6912
|
-
els['teach-btn'].addEventListener('click', () => {
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
});
|
|
6917
|
-
}
|
|
6937
|
+
els['new-conv-btn'].addEventListener('click', openModal);
|
|
6938
|
+
if (els['teach-btn']) {
|
|
6939
|
+
els['teach-btn'].addEventListener('click', () => {
|
|
6940
|
+
startTeachFlow({ seedSource: 'description' });
|
|
6941
|
+
});
|
|
6942
|
+
}
|
|
6918
6943
|
els['cancel1'].addEventListener('click', closeModal);
|
|
6919
6944
|
// Issue #385: hire-required notice back button.
|
|
6920
6945
|
if (els['hire-notice-back']) {
|
|
@@ -7471,7 +7496,7 @@ async function autoOnboardProject() {
|
|
|
7471
7496
|
foldRunIntoConversation(conv, run);
|
|
7472
7497
|
upsertConversation(conv);
|
|
7473
7498
|
state.activeId = conv.id;
|
|
7474
|
-
|
|
7499
|
+
persistActiveConversationSelection(conv.id);
|
|
7475
7500
|
renderRail();
|
|
7476
7501
|
renderActive();
|
|
7477
7502
|
startPolling();
|
|
@@ -7629,7 +7654,7 @@ function renderFirstRunLanding(mode) {
|
|
|
7629
7654
|
foldRunIntoConversation(conv, run);
|
|
7630
7655
|
upsertConversation(conv);
|
|
7631
7656
|
state.activeId = conv.id;
|
|
7632
|
-
|
|
7657
|
+
persistActiveConversationSelection(conv.id);
|
|
7633
7658
|
renderRail();
|
|
7634
7659
|
renderActive();
|
|
7635
7660
|
startPolling();
|