@jungjaehoon/mama-os 0.8.3 → 0.9.0
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/CHANGELOG.md +10 -0
- package/dist/agent/agent-loop.d.ts +1 -8
- package/dist/agent/agent-loop.d.ts.map +1 -1
- package/dist/agent/agent-loop.js +44 -159
- package/dist/agent/agent-loop.js.map +1 -1
- package/dist/agent/claude-cli-wrapper.d.ts +6 -0
- package/dist/agent/claude-cli-wrapper.d.ts.map +1 -1
- package/dist/agent/claude-cli-wrapper.js +6 -0
- package/dist/agent/claude-cli-wrapper.js.map +1 -1
- package/dist/agent/codex-mcp-process.d.ts +85 -0
- package/dist/agent/codex-mcp-process.d.ts.map +1 -0
- package/dist/agent/codex-mcp-process.js +357 -0
- package/dist/agent/codex-mcp-process.js.map +1 -0
- package/dist/agent/session-pool.d.ts +17 -2
- package/dist/agent/session-pool.d.ts.map +1 -1
- package/dist/agent/session-pool.js +51 -26
- package/dist/agent/session-pool.js.map +1 -1
- package/dist/agent/types.d.ts +9 -24
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/api/graph-api.d.ts.map +1 -1
- package/dist/api/graph-api.js +133 -45
- package/dist/api/graph-api.js.map +1 -1
- package/dist/cli/commands/init.d.ts +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +14 -25
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +3 -10
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +143 -54
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +2 -7
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/config/config-manager.d.ts.map +1 -1
- package/dist/cli/config/config-manager.js +9 -17
- package/dist/cli/config/config-manager.js.map +1 -1
- package/dist/cli/config/types.d.ts +19 -25
- package/dist/cli/config/types.d.ts.map +1 -1
- package/dist/cli/config/types.js.map +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/gateways/context-injector.d.ts.map +1 -1
- package/dist/gateways/context-injector.js +6 -3
- package/dist/gateways/context-injector.js.map +1 -1
- package/dist/gateways/discord.d.ts +4 -0
- package/dist/gateways/discord.d.ts.map +1 -1
- package/dist/gateways/discord.js +39 -16
- package/dist/gateways/discord.js.map +1 -1
- package/dist/gateways/message-router.d.ts +6 -1
- package/dist/gateways/message-router.d.ts.map +1 -1
- package/dist/gateways/message-router.js +92 -7
- package/dist/gateways/message-router.js.map +1 -1
- package/dist/multi-agent/agent-process-manager.d.ts.map +1 -1
- package/dist/multi-agent/agent-process-manager.js +36 -9
- package/dist/multi-agent/agent-process-manager.js.map +1 -1
- package/dist/multi-agent/runtime-process.d.ts +4 -4
- package/dist/multi-agent/runtime-process.d.ts.map +1 -1
- package/dist/multi-agent/runtime-process.js +9 -20
- package/dist/multi-agent/runtime-process.js.map +1 -1
- package/dist/multi-agent/types.d.ts +13 -8
- package/dist/multi-agent/types.d.ts.map +1 -1
- package/dist/multi-agent/types.js.map +1 -1
- package/dist/setup/setup-prompt.d.ts +1 -1
- package/dist/setup/setup-prompt.d.ts.map +1 -1
- package/dist/setup/setup-prompt.js +19 -0
- package/dist/setup/setup-prompt.js.map +1 -1
- package/dist/setup/setup-server.d.ts.map +1 -1
- package/dist/setup/setup-server.js +39 -16
- package/dist/setup/setup-server.js.map +1 -1
- package/dist/skills/skill-registry.d.ts.map +1 -1
- package/dist/skills/skill-registry.js +5 -2
- package/dist/skills/skill-registry.js.map +1 -1
- package/package.json +5 -3
- package/public/setup.html +12 -1
- package/public/viewer/js/modules/chat.js +1760 -1976
- package/public/viewer/js/modules/dashboard.js +613 -695
- package/public/viewer/js/modules/graph.js +857 -970
- package/public/viewer/js/modules/memory.js +357 -312
- package/public/viewer/js/modules/settings.js +1009 -1026
- package/public/viewer/js/modules/skills.js +336 -355
- package/public/viewer/js/utils/api.js +255 -255
- package/public/viewer/js/utils/debug-logger.js +20 -26
- package/public/viewer/js/utils/dom.js +73 -60
- package/public/viewer/js/utils/format.js +182 -228
- package/public/viewer/js/utils/markdown.js +40 -0
- package/public/viewer/src/modules/chat.ts +2258 -0
- package/public/viewer/src/modules/dashboard.ts +1052 -0
- package/public/viewer/src/modules/graph.ts +1080 -0
- package/public/viewer/src/modules/memory.ts +453 -0
- package/public/viewer/src/modules/settings.ts +1398 -0
- package/public/viewer/src/modules/skills.ts +457 -0
- package/public/viewer/src/types/global.d.ts +168 -0
- package/public/viewer/src/utils/api.ts +650 -0
- package/public/viewer/src/utils/debug-logger.ts +36 -0
- package/public/viewer/src/utils/dom.ts +138 -0
- package/public/viewer/src/utils/format.ts +331 -0
- package/public/viewer/src/utils/markdown.ts +46 -0
- package/public/viewer/tsconfig.viewer.json +18 -0
- package/public/viewer/viewer.html +214 -311
- package/dist/agent/codex-cli-wrapper.d.ts +0 -85
- package/dist/agent/codex-cli-wrapper.d.ts.map +0 -1
- package/dist/agent/codex-cli-wrapper.js +0 -295
- package/dist/agent/codex-cli-wrapper.js.map +0 -1
|
@@ -8,356 +8,401 @@
|
|
|
8
8
|
* - Related decision suggestions for chat messages
|
|
9
9
|
* - Save decision form modal
|
|
10
10
|
*/
|
|
11
|
-
|
|
12
11
|
/* eslint-env browser */
|
|
13
12
|
/* global lucide */
|
|
14
|
-
|
|
15
|
-
import { escapeHtml, debounce, showToast } from '../utils/dom.js';
|
|
13
|
+
import { escapeHtml, debounce, showToast, getElementByIdOrNull } from '../utils/dom.js';
|
|
16
14
|
import { formatRelativeTime, truncateText } from '../utils/format.js';
|
|
17
15
|
import { API } from '../utils/api.js';
|
|
18
|
-
|
|
16
|
+
import { DebugLogger } from '../utils/debug-logger.js';
|
|
17
|
+
const logger = new DebugLogger('Memory');
|
|
19
18
|
/**
|
|
20
19
|
* Memory Module Class
|
|
21
20
|
*/
|
|
22
21
|
export class MemoryModule {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
this.initEventListeners();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Initialize all event listeners
|
|
34
|
-
*/
|
|
35
|
-
initEventListeners() {
|
|
36
|
-
// Modal click outside to close
|
|
37
|
-
document.addEventListener('click', (e) => {
|
|
38
|
-
const modal = document.getElementById('save-decision-modal');
|
|
39
|
-
if (modal && e.target === modal) {
|
|
40
|
-
this.hideSaveForm();
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// Escape key to close modal
|
|
45
|
-
document.addEventListener('keydown', (e) => {
|
|
46
|
-
if (e.key === 'Escape') {
|
|
47
|
-
const modal = document.getElementById('save-decision-modal');
|
|
48
|
-
if (modal && modal.classList.contains('visible')) {
|
|
49
|
-
this.hideSaveForm();
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Handle memory search input event
|
|
57
|
-
* @param {KeyboardEvent} event - Keyboard event
|
|
58
|
-
*/
|
|
59
|
-
handleSearchInput(event) {
|
|
60
|
-
if (event.key === 'Enter') {
|
|
61
|
-
this.search();
|
|
62
|
-
} else {
|
|
63
|
-
this.debouncedSearch();
|
|
22
|
+
searchData = [];
|
|
23
|
+
debouncedSearch = debounce(() => this.performSearch(), 300);
|
|
24
|
+
currentQuery = '';
|
|
25
|
+
constructor() {
|
|
26
|
+
// Initialize event listeners
|
|
27
|
+
this.initEventListeners();
|
|
64
28
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Initialize all event listeners
|
|
31
|
+
*/
|
|
32
|
+
initEventListeners() {
|
|
33
|
+
// Memory card click handler (event delegation)
|
|
34
|
+
const resultsContainer = getElementByIdOrNull('memory-results');
|
|
35
|
+
if (resultsContainer) {
|
|
36
|
+
resultsContainer.addEventListener('click', (e) => {
|
|
37
|
+
const card = e.target?.closest('[data-memory-card]');
|
|
38
|
+
if (card) {
|
|
39
|
+
const idx = parseInt(card.dataset.memoryCard || '', 10);
|
|
40
|
+
if (!Number.isNaN(idx)) {
|
|
41
|
+
this.toggleCard(idx);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
// Modal click outside to close
|
|
47
|
+
document.addEventListener('click', (e) => {
|
|
48
|
+
const modal = getElementByIdOrNull('save-decision-modal');
|
|
49
|
+
if (modal && e.target === modal) {
|
|
50
|
+
this.hideSaveForm();
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
// Escape key to close modal
|
|
54
|
+
document.addEventListener('keydown', (e) => {
|
|
55
|
+
if (e.key === 'Escape') {
|
|
56
|
+
const modal = getElementByIdOrNull('save-decision-modal');
|
|
57
|
+
if (modal && modal.classList.contains('visible')) {
|
|
58
|
+
this.hideSaveForm();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
92
62
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Handle memory search input event
|
|
65
|
+
* @param {KeyboardEvent} event - Keyboard event
|
|
66
|
+
*/
|
|
67
|
+
handleSearchInput(event) {
|
|
68
|
+
if (event.key === 'Enter') {
|
|
69
|
+
this.search();
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
this.debouncedSearch();
|
|
73
|
+
}
|
|
104
74
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Perform search (internal, debounced)
|
|
77
|
+
*/
|
|
78
|
+
async performSearch() {
|
|
79
|
+
const input = getElementByIdOrNull('memory-search-input');
|
|
80
|
+
if (!input) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const query = input.value.trim();
|
|
84
|
+
if (!query) {
|
|
85
|
+
this.showPlaceholder();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
await this.search();
|
|
115
89
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Search memory decisions via API
|
|
92
|
+
*/
|
|
93
|
+
async search() {
|
|
94
|
+
const input = getElementByIdOrNull('memory-search-input');
|
|
95
|
+
if (!input) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const query = input.value.trim();
|
|
99
|
+
if (!query) {
|
|
100
|
+
this.showPlaceholder();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
this.setStatus('Searching...', 'loading');
|
|
104
|
+
try {
|
|
105
|
+
const data = await API.searchMemory(query, 10);
|
|
106
|
+
this.searchData = data.results || [];
|
|
107
|
+
this.renderResults(this.searchData, query);
|
|
108
|
+
this.setStatus(`Found ${this.searchData.length} decision(s)`, '');
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
112
|
+
logger.error('Search error:', message);
|
|
113
|
+
this.setStatus(`Error: ${message}`, 'error');
|
|
114
|
+
}
|
|
123
115
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
// Render results
|
|
143
|
-
this.renderResults(results, message);
|
|
144
|
-
this.setStatus(`${results.length} related decision(s) found`, '');
|
|
145
|
-
|
|
146
|
-
// Show notification
|
|
147
|
-
showToast(`🧠 ${results.length} related MAMA decision(s) found`);
|
|
116
|
+
/**
|
|
117
|
+
* Search for related decisions (called automatically for chat messages)
|
|
118
|
+
* @param {string} message - Chat message text
|
|
119
|
+
* @returns {Promise<Array>} Related decisions
|
|
120
|
+
*/
|
|
121
|
+
async searchRelated(message) {
|
|
122
|
+
if (!message || message.length < 3) {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
const data = await API.searchMemory(message, 5);
|
|
127
|
+
return data.results || [];
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
131
|
+
logger.error('Related search error:', message);
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
148
134
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
135
|
+
/**
|
|
136
|
+
* Show related decisions for a chat message
|
|
137
|
+
* @param {string} message - Chat message text
|
|
138
|
+
*/
|
|
139
|
+
async showRelatedForMessage(message) {
|
|
140
|
+
const results = await this.searchRelated(message);
|
|
141
|
+
if (results.length > 0) {
|
|
142
|
+
this.searchData = results;
|
|
143
|
+
// Update search input with the query (if element exists)
|
|
144
|
+
const input = getElementByIdOrNull('memory-search-input');
|
|
145
|
+
if (input) {
|
|
146
|
+
input.value = message.substring(0, 50) + (message.length > 50 ? '...' : '');
|
|
147
|
+
}
|
|
148
|
+
// Render results
|
|
149
|
+
this.renderResults(results, message);
|
|
150
|
+
this.setStatus(`${results.length} related decision(s) found`, '');
|
|
151
|
+
// Show notification
|
|
152
|
+
showToast(`🧠 ${results.length} related MAMA decision(s) found`);
|
|
153
|
+
}
|
|
162
154
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
155
|
+
/**
|
|
156
|
+
* Render search results
|
|
157
|
+
* @param {Array} results - Search results
|
|
158
|
+
* @param {string} query - Search query
|
|
159
|
+
*/
|
|
160
|
+
renderResults(results, query) {
|
|
161
|
+
const container = getElementByIdOrNull('memory-results');
|
|
162
|
+
// Guard: element may not exist if not on Memory tab
|
|
163
|
+
if (!container) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (!results || results.length === 0) {
|
|
167
|
+
container.innerHTML = `
|
|
166
168
|
<div class="memory-placeholder">
|
|
167
169
|
<p>No decisions found for "${escapeHtml(query)}"</p>
|
|
168
170
|
<p class="memory-hint">Try different keywords or check if you have saved decisions</p>
|
|
169
171
|
</div>
|
|
170
172
|
`;
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const html = results
|
|
176
|
+
.map((item, idx) => {
|
|
177
|
+
const rawOutcome = String(item.outcome || 'PENDING');
|
|
178
|
+
const normalizedOutcome = rawOutcome.toLowerCase();
|
|
179
|
+
const outcomeClass = ['success', 'failed', 'partial', 'pending'].includes(normalizedOutcome)
|
|
180
|
+
? normalizedOutcome
|
|
181
|
+
: 'pending';
|
|
182
|
+
return `
|
|
183
|
+
<div class="memory-card" data-memory-card="${idx}">
|
|
178
184
|
<div class="memory-card-header">
|
|
179
185
|
<span class="memory-card-topic">${escapeHtml(item.topic || 'Unknown')}</span>
|
|
180
186
|
${item.similarity ? `<span class="memory-card-score">${Math.round(item.similarity * 100)}%</span>` : ''}
|
|
181
187
|
</div>
|
|
182
188
|
<div class="memory-card-decision">${escapeHtml(truncateText(item.decision, 150))}</div>
|
|
183
189
|
<div class="memory-card-meta">
|
|
184
|
-
<span class="memory-card-outcome ${
|
|
190
|
+
<span class="memory-card-outcome ${outcomeClass}">${escapeHtml(rawOutcome)}</span>
|
|
185
191
|
<span>${formatRelativeTime(item.created_at)}</span>
|
|
186
192
|
</div>
|
|
187
193
|
<div class="memory-card-reasoning">${escapeHtml(item.reasoning || 'No reasoning provided')}</div>
|
|
188
194
|
</div>
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
195
|
+
`;
|
|
196
|
+
})
|
|
197
|
+
.join('');
|
|
198
|
+
container.innerHTML = html;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Toggle memory card expand/collapse
|
|
202
|
+
* @param {number} idx - Card index
|
|
203
|
+
*/
|
|
204
|
+
toggleCard(idx) {
|
|
205
|
+
const cards = document.querySelectorAll('.memory-card');
|
|
206
|
+
cards.forEach((card, i) => {
|
|
207
|
+
if (i === idx) {
|
|
208
|
+
card.classList.toggle('expanded');
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
card.classList.remove('expanded');
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Show memory placeholder
|
|
217
|
+
*/
|
|
218
|
+
showPlaceholder() {
|
|
219
|
+
const container = getElementByIdOrNull('memory-results');
|
|
220
|
+
if (!container) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
container.innerHTML = `
|
|
217
224
|
<div class="memory-placeholder">
|
|
218
225
|
<p><i data-lucide="brain"></i> Search your MAMA decisions</p>
|
|
219
226
|
<p class="memory-hint">Type a keyword or send a chat message to see related decisions</p>
|
|
220
227
|
</div>
|
|
221
228
|
`;
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
229
|
+
this.setStatus('', '');
|
|
230
|
+
// Reinitialize Lucide icons for dynamic content
|
|
231
|
+
if (typeof lucide !== 'undefined' && typeof window.lucideConfig !== 'undefined') {
|
|
232
|
+
lucide.createIcons(window.lucideConfig);
|
|
233
|
+
}
|
|
226
234
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
status.textContent = message;
|
|
240
|
-
status.className = 'memory-status ' + (type || '');
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Show save decision form modal
|
|
245
|
-
*/
|
|
246
|
-
showSaveForm() {
|
|
247
|
-
const modal = document.getElementById('save-decision-modal');
|
|
248
|
-
modal.classList.add('visible');
|
|
249
|
-
|
|
250
|
-
// Clear form
|
|
251
|
-
document.getElementById('save-topic').value = '';
|
|
252
|
-
document.getElementById('save-decision').value = '';
|
|
253
|
-
document.getElementById('save-reasoning').value = '';
|
|
254
|
-
document.getElementById('save-confidence').value = '0.8';
|
|
255
|
-
document.getElementById('save-form-status').textContent = '';
|
|
256
|
-
document.getElementById('save-form-status').className = 'save-form-status';
|
|
257
|
-
|
|
258
|
-
// Focus on topic field
|
|
259
|
-
setTimeout(() => {
|
|
260
|
-
document.getElementById('save-topic').focus();
|
|
261
|
-
}, 100);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Show save form with pre-filled text (for /save command)
|
|
266
|
-
*/
|
|
267
|
-
showSaveFormWithText(text) {
|
|
268
|
-
const modal = document.getElementById('save-decision-modal');
|
|
269
|
-
modal.classList.add('visible');
|
|
270
|
-
|
|
271
|
-
// Pre-fill decision field
|
|
272
|
-
document.getElementById('save-topic').value = '';
|
|
273
|
-
document.getElementById('save-decision').value = text;
|
|
274
|
-
document.getElementById('save-reasoning').value = '';
|
|
275
|
-
document.getElementById('save-confidence').value = '0.8';
|
|
276
|
-
document.getElementById('save-form-status').textContent = '';
|
|
277
|
-
document.getElementById('save-form-status').className = 'save-form-status';
|
|
278
|
-
|
|
279
|
-
// Focus on topic field
|
|
280
|
-
setTimeout(() => {
|
|
281
|
-
document.getElementById('save-topic').focus();
|
|
282
|
-
}, 100);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Hide save decision form modal
|
|
287
|
-
*/
|
|
288
|
-
hideSaveForm() {
|
|
289
|
-
const modal = document.getElementById('save-decision-modal');
|
|
290
|
-
modal.classList.remove('visible');
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Execute search with query (for /search command)
|
|
295
|
-
*/
|
|
296
|
-
async searchWithQuery(query) {
|
|
297
|
-
const searchInput = document.getElementById('memory-search');
|
|
298
|
-
if (searchInput) {
|
|
299
|
-
searchInput.value = query;
|
|
235
|
+
/**
|
|
236
|
+
* Set memory status message
|
|
237
|
+
* @param {string} message - Status message
|
|
238
|
+
* @param {string} type - Status type (loading, error, success, '')
|
|
239
|
+
*/
|
|
240
|
+
setStatus(message, type = '') {
|
|
241
|
+
const status = getElementByIdOrNull('memory-status');
|
|
242
|
+
if (!status) {
|
|
243
|
+
return;
|
|
244
|
+
} // Guard: element may not exist if not on Memory tab
|
|
245
|
+
status.textContent = message;
|
|
246
|
+
status.className = 'memory-status ' + (type || '');
|
|
300
247
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
248
|
+
/**
|
|
249
|
+
* Show save decision form modal
|
|
250
|
+
*/
|
|
251
|
+
showSaveForm() {
|
|
252
|
+
const modal = getElementByIdOrNull('save-decision-modal');
|
|
253
|
+
if (!modal) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
modal.classList.add('visible');
|
|
257
|
+
// Clear form
|
|
258
|
+
const topicInput = getElementByIdOrNull('save-topic');
|
|
259
|
+
const decisionInput = getElementByIdOrNull('save-decision');
|
|
260
|
+
const reasoningInput = getElementByIdOrNull('save-reasoning');
|
|
261
|
+
const confidenceInput = getElementByIdOrNull('save-confidence');
|
|
262
|
+
const statusEl = getElementByIdOrNull('save-form-status');
|
|
263
|
+
if (topicInput) {
|
|
264
|
+
topicInput.value = '';
|
|
265
|
+
}
|
|
266
|
+
if (decisionInput) {
|
|
267
|
+
decisionInput.value = '';
|
|
268
|
+
}
|
|
269
|
+
if (reasoningInput) {
|
|
270
|
+
reasoningInput.value = '';
|
|
271
|
+
}
|
|
272
|
+
if (confidenceInput) {
|
|
273
|
+
confidenceInput.value = '0.8';
|
|
274
|
+
}
|
|
275
|
+
if (statusEl) {
|
|
276
|
+
statusEl.textContent = '';
|
|
277
|
+
statusEl.className = 'save-form-status';
|
|
278
|
+
}
|
|
279
|
+
// Focus on topic field
|
|
280
|
+
setTimeout(() => {
|
|
281
|
+
const focusTarget = getElementByIdOrNull('save-topic');
|
|
282
|
+
focusTarget?.focus();
|
|
283
|
+
}, 100);
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Show save form with pre-filled text (for /save command)
|
|
287
|
+
*/
|
|
288
|
+
showSaveFormWithText(text) {
|
|
289
|
+
const modal = getElementByIdOrNull('save-decision-modal');
|
|
290
|
+
if (!modal) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
modal.classList.add('visible');
|
|
294
|
+
// Pre-fill decision field
|
|
295
|
+
const topicInput = getElementByIdOrNull('save-topic');
|
|
296
|
+
const decisionInput = getElementByIdOrNull('save-decision');
|
|
297
|
+
const reasoningInput = getElementByIdOrNull('save-reasoning');
|
|
298
|
+
const confidenceInput = getElementByIdOrNull('save-confidence');
|
|
299
|
+
const statusEl = getElementByIdOrNull('save-form-status');
|
|
300
|
+
if (topicInput) {
|
|
301
|
+
topicInput.value = '';
|
|
302
|
+
}
|
|
303
|
+
if (decisionInput) {
|
|
304
|
+
decisionInput.value = text;
|
|
305
|
+
}
|
|
306
|
+
if (reasoningInput) {
|
|
307
|
+
reasoningInput.value = '';
|
|
308
|
+
}
|
|
309
|
+
if (confidenceInput) {
|
|
310
|
+
confidenceInput.value = '0.8';
|
|
311
|
+
}
|
|
312
|
+
if (statusEl) {
|
|
313
|
+
statusEl.textContent = '';
|
|
314
|
+
statusEl.className = 'save-form-status';
|
|
315
|
+
}
|
|
316
|
+
// Focus on topic field
|
|
317
|
+
setTimeout(() => {
|
|
318
|
+
const focusTarget = getElementByIdOrNull('save-topic');
|
|
319
|
+
focusTarget?.focus();
|
|
320
|
+
}, 100);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Hide save decision form modal
|
|
324
|
+
*/
|
|
325
|
+
hideSaveForm() {
|
|
326
|
+
const modal = getElementByIdOrNull('save-decision-modal');
|
|
327
|
+
if (!modal) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
modal.classList.remove('visible');
|
|
322
331
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
332
|
+
/**
|
|
333
|
+
* Execute search with query (for /search command)
|
|
334
|
+
*/
|
|
335
|
+
async searchWithQuery(query) {
|
|
336
|
+
const searchInput = getElementByIdOrNull('memory-search-input');
|
|
337
|
+
if (searchInput) {
|
|
338
|
+
searchInput.value = query;
|
|
339
|
+
}
|
|
340
|
+
this.currentQuery = query;
|
|
341
|
+
await this.search();
|
|
328
342
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
const
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
343
|
+
/**
|
|
344
|
+
* Submit save decision form
|
|
345
|
+
*/
|
|
346
|
+
async submitSaveForm() {
|
|
347
|
+
const topicInput = getElementByIdOrNull('save-topic');
|
|
348
|
+
const decisionInput = getElementByIdOrNull('save-decision');
|
|
349
|
+
const reasoningInput = getElementByIdOrNull('save-reasoning');
|
|
350
|
+
const confidenceInput = getElementByIdOrNull('save-confidence');
|
|
351
|
+
const statusEl = getElementByIdOrNull('save-form-status');
|
|
352
|
+
// Select the Save button (last button in the modal actions)
|
|
353
|
+
const submitBtn = getElementByIdOrNull('save-form-submit');
|
|
354
|
+
if (!topicInput ||
|
|
355
|
+
!decisionInput ||
|
|
356
|
+
!reasoningInput ||
|
|
357
|
+
!confidenceInput ||
|
|
358
|
+
!statusEl ||
|
|
359
|
+
!submitBtn) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
const topic = topicInput.value.trim();
|
|
363
|
+
const decision = decisionInput.value.trim();
|
|
364
|
+
const reasoning = reasoningInput.value.trim();
|
|
365
|
+
const confidence = parseFloat(confidenceInput.value);
|
|
366
|
+
// Validation
|
|
367
|
+
if (!topic || !decision || !reasoning) {
|
|
368
|
+
statusEl.textContent = 'Please fill in all required fields';
|
|
369
|
+
statusEl.className = 'save-form-status error';
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
if (isNaN(confidence) || confidence < 0 || confidence > 1) {
|
|
373
|
+
statusEl.textContent = 'Confidence must be between 0.0 and 1.0';
|
|
374
|
+
statusEl.className = 'save-form-status error';
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
// Disable submit button
|
|
378
|
+
submitBtn.disabled = true;
|
|
379
|
+
statusEl.textContent = 'Saving...';
|
|
380
|
+
statusEl.className = 'save-form-status';
|
|
381
|
+
try {
|
|
382
|
+
await API.saveDecision({ topic, decision, reasoning, confidence });
|
|
383
|
+
// Success
|
|
384
|
+
statusEl.textContent = '✓ Decision saved successfully!';
|
|
385
|
+
statusEl.className = 'save-form-status success';
|
|
386
|
+
// Show toast notification
|
|
387
|
+
showToast('✓ Decision saved to MAMA memory');
|
|
388
|
+
// Close modal after 1.5 seconds
|
|
389
|
+
setTimeout(() => {
|
|
390
|
+
this.hideSaveForm();
|
|
391
|
+
// Refresh memory search if there's a query
|
|
392
|
+
const searchInput = getElementByIdOrNull('memory-search-input');
|
|
393
|
+
if (searchInput?.value.trim()) {
|
|
394
|
+
this.search();
|
|
395
|
+
}
|
|
396
|
+
}, 1500);
|
|
397
|
+
}
|
|
398
|
+
catch (error) {
|
|
399
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
400
|
+
logger.error('Save error:', message);
|
|
401
|
+
statusEl.textContent = `Error: ${message}`;
|
|
402
|
+
statusEl.className = 'save-form-status error';
|
|
403
|
+
}
|
|
404
|
+
finally {
|
|
405
|
+
submitBtn.disabled = false;
|
|
406
|
+
}
|
|
361
407
|
}
|
|
362
|
-
}
|
|
363
408
|
}
|