mop-agent 0.1.12 → 0.1.14
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/README.md +3 -2
- package/apps/web/app/assistant/page.tsx +136 -49
- package/apps/web/app/globals.css +170 -133
- package/apps/web/components/AppShell.tsx +31 -80
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,8 +5,9 @@ through MOP-FLOW. It stores project memory, performs semantic recall and
|
|
|
5
5
|
consolidation, serves grounded chat, and can request approved actions from a
|
|
6
6
|
linked FLOW node.
|
|
7
7
|
|
|
8
|
-
> **Release status:**
|
|
9
|
-
> installer, one-time Admin setup/login flow, and shared
|
|
8
|
+
> **Release status:** release candidate `mop-agent@0.1.14` contains the corrected VPS
|
|
9
|
+
> installer, one-time Admin setup/login flow, and simplified shared application shell
|
|
10
|
+
> with centered page titles and ChatGPT-inspired navigation.
|
|
10
11
|
> The canonical installation command is exactly `npx mop-agent`.
|
|
11
12
|
|
|
12
13
|
## Current status
|
|
@@ -5,14 +5,20 @@ import { useEffect, useRef, useState } from "react";
|
|
|
5
5
|
import { useMemoryCore } from "@/components/AppShell";
|
|
6
6
|
|
|
7
7
|
type Turn = { role: "user" | "assistant"; content: string };
|
|
8
|
+
type SavedChat = { id: string; title: string; turns: Turn[]; updatedAt: number };
|
|
9
|
+
|
|
10
|
+
const CHAT_HISTORY_KEY = "mop-agent-chat-history-v1";
|
|
8
11
|
|
|
9
12
|
export default function AssistantPage() {
|
|
10
|
-
const {
|
|
13
|
+
const { projects } = useMemoryCore();
|
|
11
14
|
const [turns, setTurns] = useState<Turn[]>([]);
|
|
12
15
|
const [name, setName] = useState("Admin");
|
|
13
16
|
const [input, setInput] = useState("");
|
|
14
17
|
const [busy, setBusy] = useState(false);
|
|
15
18
|
const [providerUsed, setProviderUsed] = useState("");
|
|
19
|
+
const [history, setHistory] = useState<SavedChat[]>([]);
|
|
20
|
+
const [historyReady, setHistoryReady] = useState(false);
|
|
21
|
+
const [activeChatId, setActiveChatId] = useState("");
|
|
16
22
|
const endRef = useRef<HTMLDivElement>(null);
|
|
17
23
|
|
|
18
24
|
useEffect(() => {
|
|
@@ -21,10 +27,61 @@ export default function AssistantPage() {
|
|
|
21
27
|
}).catch(() => {});
|
|
22
28
|
}, []);
|
|
23
29
|
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
try {
|
|
32
|
+
const stored = JSON.parse(window.localStorage.getItem(CHAT_HISTORY_KEY) ?? "[]");
|
|
33
|
+
if (Array.isArray(stored)) setHistory(stored.slice(0, 30));
|
|
34
|
+
} catch {
|
|
35
|
+
window.localStorage.removeItem(CHAT_HISTORY_KEY);
|
|
36
|
+
} finally {
|
|
37
|
+
setHistoryReady(true);
|
|
38
|
+
}
|
|
39
|
+
}, []);
|
|
40
|
+
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (!historyReady) return;
|
|
43
|
+
window.localStorage.setItem(CHAT_HISTORY_KEY, JSON.stringify(history.slice(0, 30)));
|
|
44
|
+
}, [history, historyReady]);
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (!activeChatId || turns.length === 0) return;
|
|
48
|
+
const firstMessage = turns.find((turn) => turn.role === "user")?.content ?? "New conversation";
|
|
49
|
+
setHistory((current) => {
|
|
50
|
+
const updated: SavedChat = {
|
|
51
|
+
id: activeChatId,
|
|
52
|
+
title: firstMessage.slice(0, 54),
|
|
53
|
+
turns,
|
|
54
|
+
updatedAt: Date.now(),
|
|
55
|
+
};
|
|
56
|
+
return [updated, ...current.filter((chat) => chat.id !== activeChatId)].slice(0, 30);
|
|
57
|
+
});
|
|
58
|
+
}, [activeChatId, turns]);
|
|
59
|
+
|
|
60
|
+
function startNewChat() {
|
|
61
|
+
if (busy) return;
|
|
62
|
+
setActiveChatId("");
|
|
63
|
+
setTurns([]);
|
|
64
|
+
setProviderUsed("");
|
|
65
|
+
setInput("");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function openChat(chat: SavedChat) {
|
|
69
|
+
if (busy) return;
|
|
70
|
+
setActiveChatId(chat.id);
|
|
71
|
+
setTurns(chat.turns);
|
|
72
|
+
setProviderUsed("");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function deleteChat(id: string) {
|
|
76
|
+
if (busy) return;
|
|
77
|
+
setHistory((current) => current.filter((chat) => chat.id !== id));
|
|
78
|
+
if (activeChatId === id) startNewChat();
|
|
79
|
+
}
|
|
24
80
|
|
|
25
81
|
async function send(prefill?: string) {
|
|
26
82
|
const message = (prefill ?? input).trim();
|
|
27
83
|
if (!message || busy) return;
|
|
84
|
+
if (!activeChatId) setActiveChatId(`chat-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
|
|
28
85
|
setInput("");
|
|
29
86
|
setBusy(true);
|
|
30
87
|
setTurns((current) => [...current, { role: "user", content: message }, { role: "assistant", content: "" }]);
|
|
@@ -34,8 +91,7 @@ export default function AssistantPage() {
|
|
|
34
91
|
headers: { "content-type": "application/json" },
|
|
35
92
|
body: JSON.stringify({
|
|
36
93
|
message,
|
|
37
|
-
|
|
38
|
-
allowCrossProject: !selectedProject,
|
|
94
|
+
allowCrossProject: true,
|
|
39
95
|
}),
|
|
40
96
|
});
|
|
41
97
|
|
|
@@ -69,64 +125,95 @@ export default function AssistantPage() {
|
|
|
69
125
|
|
|
70
126
|
return (
|
|
71
127
|
<section className="mop-assistant-page">
|
|
72
|
-
<div className="mop-assistant-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
<div
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
128
|
+
<div className="mop-assistant-workspace">
|
|
129
|
+
<div className="mop-assistant-conversation">
|
|
130
|
+
{turns.length === 0 ? (
|
|
131
|
+
<div className="mop-assistant-welcome">
|
|
132
|
+
<div style={assistantLogo}><img src="/icon.svg" alt="MOP-AGENT" /></div>
|
|
133
|
+
<p style={{ color: "#742220", fontSize: 11, fontWeight: 900, letterSpacing: ".16em" }}>MOP-AGENT IS READY</p>
|
|
134
|
+
<h1 style={{ fontFamily: '"SFMono-Regular", Consolas, monospace', fontSize: "clamp(26px, 4vw, 40px)", margin: "8px 0 12px" }}>
|
|
135
|
+
What are we working on, {name.split(" ")[0]}?
|
|
136
|
+
</h1>
|
|
137
|
+
<p style={{ color: "rgba(45,74,62,.7)", maxWidth: 610, lineHeight: 1.65 }}>
|
|
138
|
+
Start talking immediately. Link projects when you want MOP-AGENT to remember their state and work across them.
|
|
139
|
+
</p>
|
|
140
|
+
<div className="mop-prompt-grid" style={promptGrid}>
|
|
141
|
+
{["Help me plan today’s work", "What can MOP-AGENT do?", "Summarize what you remember", "Plan a new software project"].map((prompt) => (
|
|
142
|
+
<button key={prompt} onClick={() => send(prompt)} style={promptCard}>{prompt}<span>→</span></button>
|
|
143
|
+
))}
|
|
144
|
+
</div>
|
|
145
|
+
{projects.length === 0 && (
|
|
146
|
+
<p style={{ fontSize: 13, color: "rgba(45,74,62,.68)", marginTop: 24 }}>
|
|
147
|
+
No project linked yet—this does not block chat. <a href="/brain" style={{ color: "#742220" }}>Link one from Brain →</a>
|
|
148
|
+
</p>
|
|
149
|
+
)}
|
|
150
|
+
</div>
|
|
151
|
+
) : (
|
|
152
|
+
<div style={{ width: "min(100%, 820px)", margin: "0 auto", padding: "28px 0 160px" }}>
|
|
153
|
+
{turns.map((turn, index) => (
|
|
154
|
+
<article key={index} style={{ display: "grid", gridTemplateColumns: "34px 1fr", gap: 13, marginBottom: 26 }}>
|
|
155
|
+
<span style={turn.role === "assistant" ? botAvatar : userAvatar}>{turn.role === "assistant" ? "✦" : name.slice(0, 1).toUpperCase()}</span>
|
|
156
|
+
<div>
|
|
157
|
+
<strong style={{ fontSize: 13, color: turn.role === "assistant" ? "#742220" : "#2d4a3e" }}>{turn.role === "assistant" ? "MOP-AGENT" : "You"}</strong>
|
|
158
|
+
<div style={{ whiteSpace: "pre-wrap", lineHeight: 1.7, marginTop: 6, color: "#2d4a3e" }}>{turn.content || "Thinking…"}</div>
|
|
159
|
+
</div>
|
|
160
|
+
</article>
|
|
86
161
|
))}
|
|
162
|
+
<div ref={endRef} />
|
|
87
163
|
</div>
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
164
|
+
)}
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
<div className="mop-assistant-composer-wrap">
|
|
168
|
+
<div style={composer}>
|
|
169
|
+
<textarea
|
|
170
|
+
value={input}
|
|
171
|
+
onChange={(e) => setInput(e.target.value)}
|
|
172
|
+
onKeyDown={(e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); send(); } }}
|
|
173
|
+
placeholder="Message MOP-AGENT…"
|
|
174
|
+
rows={1}
|
|
175
|
+
style={textarea}
|
|
176
|
+
/>
|
|
177
|
+
<button onClick={() => send()} disabled={busy || !input.trim()} style={{ ...sendButton, opacity: busy || !input.trim() ? .45 : 1 }}>↑</button>
|
|
93
178
|
</div>
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
{turns.map((turn, index) => (
|
|
97
|
-
<article key={index} style={{ display: "grid", gridTemplateColumns: "34px 1fr", gap: 13, marginBottom: 26 }}>
|
|
98
|
-
<span style={turn.role === "assistant" ? botAvatar : userAvatar}>{turn.role === "assistant" ? "✦" : name.slice(0, 1).toUpperCase()}</span>
|
|
99
|
-
<div>
|
|
100
|
-
<strong style={{ fontSize: 13, color: turn.role === "assistant" ? "#742220" : "#2d4a3e" }}>{turn.role === "assistant" ? "MOP-AGENT" : "You"}</strong>
|
|
101
|
-
<div style={{ whiteSpace: "pre-wrap", lineHeight: 1.7, marginTop: 6, color: "#2d4a3e" }}>{turn.content || "Thinking…"}</div>
|
|
102
|
-
</div>
|
|
103
|
-
</article>
|
|
104
|
-
))}
|
|
105
|
-
<div ref={endRef} />
|
|
179
|
+
<div style={{ textAlign: "center", color: "rgba(45,74,62,.62)", fontSize: 11, marginTop: 8 }}>
|
|
180
|
+
{providerUsed ? `Answered by ${providerUsed} · ` : ""}Cross-project memory
|
|
106
181
|
</div>
|
|
107
|
-
|
|
182
|
+
</div>
|
|
108
183
|
</div>
|
|
109
184
|
|
|
110
|
-
<
|
|
111
|
-
<div
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
rows={1}
|
|
118
|
-
style={textarea}
|
|
119
|
-
/>
|
|
120
|
-
<button onClick={() => send()} disabled={busy || !input.trim()} style={{ ...sendButton, opacity: busy || !input.trim() ? .45 : 1 }}>↑</button>
|
|
185
|
+
<aside className="mop-chat-history" aria-label="Chat history">
|
|
186
|
+
<div className="mop-chat-history-header">
|
|
187
|
+
<div>
|
|
188
|
+
<span>MEMORY LOG</span>
|
|
189
|
+
<strong>Chat history</strong>
|
|
190
|
+
</div>
|
|
191
|
+
<button type="button" onClick={startNewChat} disabled={busy} title="Start a new chat">+</button>
|
|
121
192
|
</div>
|
|
122
|
-
<div
|
|
123
|
-
{
|
|
193
|
+
<div className="mop-chat-history-list">
|
|
194
|
+
{history.length === 0 ? (
|
|
195
|
+
<p className="mop-chat-history-empty">Your conversations will appear here.</p>
|
|
196
|
+
) : history.map((chat) => (
|
|
197
|
+
<div className={`mop-chat-history-item${chat.id === activeChatId ? " is-active" : ""}`} key={chat.id}>
|
|
198
|
+
<button type="button" className="mop-chat-history-open" onClick={() => openChat(chat)} disabled={busy}>
|
|
199
|
+
<strong>{chat.title}</strong>
|
|
200
|
+
<span>{formatChatDate(chat.updatedAt)}</span>
|
|
201
|
+
</button>
|
|
202
|
+
<button type="button" className="mop-chat-history-delete" onClick={() => deleteChat(chat.id)} disabled={busy} aria-label={`Delete ${chat.title}`}>×</button>
|
|
203
|
+
</div>
|
|
204
|
+
))}
|
|
124
205
|
</div>
|
|
125
|
-
</
|
|
206
|
+
</aside>
|
|
126
207
|
</section>
|
|
127
208
|
);
|
|
128
209
|
}
|
|
129
210
|
|
|
211
|
+
function formatChatDate(timestamp: number) {
|
|
212
|
+
const date = new Date(timestamp);
|
|
213
|
+
if (Number.isNaN(date.getTime())) return "Saved conversation";
|
|
214
|
+
return new Intl.DateTimeFormat(undefined, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" }).format(date);
|
|
215
|
+
}
|
|
216
|
+
|
|
130
217
|
const assistantLogo: CSSProperties = { width: 86, height: 86, display: "grid", placeItems: "center" };
|
|
131
218
|
const promptGrid: CSSProperties = { width: "min(100%, 650px)", display: "grid", gridTemplateColumns: "repeat(2,minmax(0,1fr))", gap: 10, marginTop: 28 };
|
|
132
219
|
const promptCard: CSSProperties = { display: "flex", justifyContent: "space-between", padding: "14px 15px", border: "1px solid rgba(45,74,62,.38)", borderBottomWidth: 3, background: "#fffdf2", color: "#2d4a3e", cursor: "pointer", textAlign: "left" };
|
package/apps/web/app/globals.css
CHANGED
|
@@ -97,7 +97,7 @@ button {
|
|
|
97
97
|
.mop-app-frame {
|
|
98
98
|
min-height: 100vh;
|
|
99
99
|
display: grid;
|
|
100
|
-
grid-template-columns:
|
|
100
|
+
grid-template-columns: 260px minmax(0, 1fr);
|
|
101
101
|
grid-template-rows: 70px minmax(0, 1fr);
|
|
102
102
|
grid-template-areas:
|
|
103
103
|
"topbar topbar"
|
|
@@ -111,7 +111,7 @@ button {
|
|
|
111
111
|
top: 0;
|
|
112
112
|
z-index: 50;
|
|
113
113
|
display: grid;
|
|
114
|
-
grid-template-columns:
|
|
114
|
+
grid-template-columns: 260px minmax(0, 1fr);
|
|
115
115
|
min-width: 0;
|
|
116
116
|
color: var(--mop-cream);
|
|
117
117
|
background:
|
|
@@ -153,6 +153,7 @@ button {
|
|
|
153
153
|
min-width: 0;
|
|
154
154
|
display: flex;
|
|
155
155
|
align-items: center;
|
|
156
|
+
justify-content: center;
|
|
156
157
|
gap: 14px;
|
|
157
158
|
padding: 0 18px;
|
|
158
159
|
}
|
|
@@ -167,18 +168,8 @@ button {
|
|
|
167
168
|
cursor: pointer;
|
|
168
169
|
}
|
|
169
170
|
|
|
170
|
-
.mop-topbar-title {
|
|
171
|
-
display: flex;
|
|
172
|
-
align-items: center;
|
|
173
|
-
gap: 8px;
|
|
174
|
-
min-width: 130px;
|
|
175
|
-
font-family: "SFMono-Regular", Consolas, monospace;
|
|
176
|
-
font-size: 13px;
|
|
177
|
-
letter-spacing: .08em;
|
|
178
|
-
text-transform: uppercase;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
171
|
.mop-live-dot {
|
|
172
|
+
flex: 0 0 auto;
|
|
182
173
|
width: 8px;
|
|
183
174
|
height: 8px;
|
|
184
175
|
background: #78e19b;
|
|
@@ -186,37 +177,21 @@ button {
|
|
|
186
177
|
}
|
|
187
178
|
|
|
188
179
|
.mop-topbar-center {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
180
|
+
min-width: 240px;
|
|
181
|
+
display: flex;
|
|
182
|
+
align-items: center;
|
|
183
|
+
justify-content: center;
|
|
184
|
+
gap: 10px;
|
|
194
185
|
padding: 9px 28px;
|
|
195
186
|
text-align: center;
|
|
196
187
|
color: rgba(254, 249, 225, .86);
|
|
197
188
|
border: 1px solid rgba(254, 249, 225, .12);
|
|
198
189
|
background: rgba(254, 249, 225, .07);
|
|
199
190
|
font-family: "SFMono-Regular", Consolas, monospace;
|
|
200
|
-
font-size:
|
|
201
|
-
font-weight: 800;
|
|
202
|
-
letter-spacing: .18em;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
.mop-topbar-meta {
|
|
206
|
-
display: flex;
|
|
207
|
-
align-items: center;
|
|
208
|
-
gap: 9px;
|
|
209
|
-
margin-left: auto;
|
|
210
|
-
font-family: "SFMono-Regular", Consolas, monospace;
|
|
211
|
-
font-size: 10px;
|
|
191
|
+
font-size: 12px;
|
|
212
192
|
font-weight: 800;
|
|
213
|
-
letter-spacing: .
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
.mop-version {
|
|
217
|
-
padding: 4px 6px;
|
|
218
|
-
border: 1px solid rgba(254, 249, 225, .22);
|
|
219
|
-
background: rgba(254, 249, 225, .07);
|
|
193
|
+
letter-spacing: .14em;
|
|
194
|
+
text-transform: uppercase;
|
|
220
195
|
}
|
|
221
196
|
|
|
222
197
|
.mop-app-sidebar {
|
|
@@ -228,60 +203,68 @@ button {
|
|
|
228
203
|
display: flex;
|
|
229
204
|
flex-direction: column;
|
|
230
205
|
overflow-y: auto;
|
|
231
|
-
padding:
|
|
206
|
+
padding: 10px 9px 9px;
|
|
232
207
|
color: var(--mop-cream);
|
|
233
208
|
background:
|
|
234
|
-
linear-gradient(rgba(255,255,255,.
|
|
209
|
+
linear-gradient(rgba(255,255,255,.028), rgba(0,0,0,.035)),
|
|
235
210
|
var(--mop-green);
|
|
236
211
|
border-right: 2px solid #20362e;
|
|
237
212
|
}
|
|
238
213
|
|
|
239
|
-
.mop-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
font-family: "SFMono-Regular", Consolas, monospace;
|
|
244
|
-
font-size: 9px;
|
|
245
|
-
font-weight: 900;
|
|
246
|
-
letter-spacing: .22em;
|
|
214
|
+
.mop-sidebar-primary {
|
|
215
|
+
display: grid;
|
|
216
|
+
gap: 3px;
|
|
217
|
+
margin-bottom: 22px;
|
|
247
218
|
}
|
|
248
219
|
|
|
249
|
-
.mop-
|
|
220
|
+
.mop-sidebar-primary a,
|
|
250
221
|
.mop-nav-section a,
|
|
251
222
|
.mop-nav-section button {
|
|
252
223
|
display: flex;
|
|
253
224
|
align-items: center;
|
|
254
225
|
gap: 11px;
|
|
255
226
|
width: 100%;
|
|
256
|
-
min-height:
|
|
257
|
-
padding: 8px
|
|
258
|
-
color: rgba(254, 249, 225, .
|
|
227
|
+
min-height: 40px;
|
|
228
|
+
padding: 8px 11px;
|
|
229
|
+
color: rgba(254, 249, 225, .82);
|
|
259
230
|
border: 1px solid transparent;
|
|
260
231
|
background: transparent;
|
|
261
232
|
text-align: left;
|
|
262
233
|
text-decoration: none;
|
|
263
|
-
font-
|
|
264
|
-
font-
|
|
265
|
-
|
|
266
|
-
letter-spacing: .055em;
|
|
267
|
-
text-transform: uppercase;
|
|
234
|
+
font-size: 14px;
|
|
235
|
+
font-weight: 540;
|
|
236
|
+
letter-spacing: 0;
|
|
268
237
|
cursor: pointer;
|
|
269
238
|
}
|
|
270
239
|
|
|
240
|
+
.mop-sidebar-primary a:hover,
|
|
271
241
|
.mop-nav-section a:hover,
|
|
272
242
|
.mop-nav-section button:hover {
|
|
273
243
|
color: var(--mop-cream);
|
|
274
|
-
background: rgba(254, 249, 225, .
|
|
244
|
+
background: rgba(254, 249, 225, .075);
|
|
275
245
|
}
|
|
276
246
|
|
|
247
|
+
.mop-sidebar-primary a.is-active,
|
|
277
248
|
.mop-nav-section a.is-active,
|
|
278
249
|
.mop-nav-section button.is-active {
|
|
279
|
-
color:
|
|
280
|
-
border-color: rgba(254, 249, 225, .
|
|
281
|
-
background: rgba(254, 249, 225, .
|
|
282
|
-
box-shadow:
|
|
250
|
+
color: var(--mop-cream);
|
|
251
|
+
border-color: rgba(254, 249, 225, .12);
|
|
252
|
+
background: rgba(254, 249, 225, .1);
|
|
253
|
+
box-shadow: 2px 2px 0 rgba(18, 38, 30, .22);
|
|
283
254
|
}
|
|
284
255
|
|
|
256
|
+
.mop-nav-section { margin-bottom: 18px; }
|
|
257
|
+
.mop-nav-section > p {
|
|
258
|
+
margin: 0 11px 7px;
|
|
259
|
+
color: rgba(254, 249, 225, .46);
|
|
260
|
+
font-family: "SFMono-Regular", Consolas, monospace;
|
|
261
|
+
font-size: 10px;
|
|
262
|
+
font-weight: 750;
|
|
263
|
+
letter-spacing: .11em;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.mop-nav-section nav { display: grid; gap: 2px; }
|
|
267
|
+
|
|
285
268
|
.mop-nav-icon {
|
|
286
269
|
width: 21px;
|
|
287
270
|
text-align: center;
|
|
@@ -289,6 +272,8 @@ button {
|
|
|
289
272
|
font-size: 16px;
|
|
290
273
|
}
|
|
291
274
|
|
|
275
|
+
.mop-admin-nav { margin-top: 2px; }
|
|
276
|
+
|
|
292
277
|
.mop-sidebar-spacer { flex: 1; }
|
|
293
278
|
.mop-account-card {
|
|
294
279
|
width: 100%;
|
|
@@ -297,11 +282,12 @@ button {
|
|
|
297
282
|
gap: 9px;
|
|
298
283
|
padding: 10px 8px;
|
|
299
284
|
color: var(--mop-cream);
|
|
300
|
-
border: 1px solid
|
|
301
|
-
background:
|
|
285
|
+
border: 1px solid transparent;
|
|
286
|
+
background: transparent;
|
|
302
287
|
text-align: left;
|
|
303
288
|
cursor: pointer;
|
|
304
289
|
}
|
|
290
|
+
.mop-account-card:hover { border-color: rgba(254, 249, 225, .1); background: rgba(254, 249, 225, .07); }
|
|
305
291
|
|
|
306
292
|
.mop-account-avatar {
|
|
307
293
|
flex: 0 0 auto;
|
|
@@ -379,69 +365,32 @@ button {
|
|
|
379
365
|
|
|
380
366
|
/* Assistant content now lives inside the shared shell. */
|
|
381
367
|
.mop-assistant-page {
|
|
382
|
-
|
|
368
|
+
height: calc(100vh - 70px);
|
|
369
|
+
min-height: 560px;
|
|
383
370
|
position: relative;
|
|
384
|
-
display:
|
|
385
|
-
|
|
371
|
+
display: grid;
|
|
372
|
+
grid-template-columns: minmax(0, 1fr) 290px;
|
|
373
|
+
overflow: hidden;
|
|
386
374
|
}
|
|
387
375
|
|
|
388
|
-
|
|
389
|
-
.mop-assistant-toolbar {
|
|
390
|
-
width: 100%;
|
|
391
|
-
display: flex;
|
|
392
|
-
align-items: center;
|
|
393
|
-
justify-content: space-between;
|
|
394
|
-
gap: 16px;
|
|
395
|
-
}
|
|
396
|
-
.mop-assistant-status {
|
|
397
|
-
display: flex;
|
|
398
|
-
align-items: center;
|
|
399
|
-
gap: 9px;
|
|
376
|
+
.mop-assistant-workspace {
|
|
400
377
|
min-width: 0;
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
font-family: "SFMono-Regular", Consolas, monospace;
|
|
404
|
-
font-size: 13px;
|
|
405
|
-
letter-spacing: .08em;
|
|
406
|
-
text-transform: uppercase;
|
|
407
|
-
color: var(--mop-cream);
|
|
408
|
-
}
|
|
409
|
-
.mop-assistant-provider {
|
|
410
|
-
overflow: hidden;
|
|
411
|
-
text-overflow: ellipsis;
|
|
412
|
-
white-space: nowrap;
|
|
413
|
-
color: rgba(254, 249, 225, .66);
|
|
414
|
-
font-size: 12px;
|
|
415
|
-
}
|
|
416
|
-
.mop-assistant-scope {
|
|
378
|
+
min-height: 0;
|
|
379
|
+
position: relative;
|
|
417
380
|
display: flex;
|
|
418
|
-
|
|
419
|
-
gap: 8px;
|
|
420
|
-
flex: 0 0 auto;
|
|
421
|
-
color: rgba(254, 249, 225, .82);
|
|
422
|
-
font-family: "SFMono-Regular", Consolas, monospace;
|
|
423
|
-
font-size: 10px;
|
|
424
|
-
font-weight: 800;
|
|
425
|
-
letter-spacing: .12em;
|
|
426
|
-
text-transform: uppercase;
|
|
427
|
-
}
|
|
428
|
-
.mop-assistant-scope select {
|
|
429
|
-
color: var(--mop-green);
|
|
430
|
-
background: var(--mop-paper);
|
|
431
|
-
border: 1px solid rgba(254, 249, 225, .32);
|
|
432
|
-
padding: 6px 8px;
|
|
433
|
-
font-family: "SFMono-Regular", Consolas, monospace;
|
|
434
|
-
font-size: 12px;
|
|
381
|
+
flex-direction: column;
|
|
435
382
|
}
|
|
436
383
|
|
|
437
|
-
.mop-assistant-conversation { flex: 1; overflow-y: auto; padding: 0
|
|
384
|
+
.mop-assistant-conversation { flex: 1; overflow-y: auto; padding: 0 clamp(18px, 5vw, 64px); }
|
|
438
385
|
.mop-assistant-welcome {
|
|
439
|
-
|
|
386
|
+
width: min(100%, 760px);
|
|
387
|
+
min-height: calc(100vh - 190px);
|
|
388
|
+
margin: 0 auto;
|
|
440
389
|
display: flex;
|
|
441
390
|
flex-direction: column;
|
|
442
391
|
align-items: center;
|
|
443
392
|
justify-content: center;
|
|
444
|
-
padding:
|
|
393
|
+
padding: 38px 0 110px;
|
|
445
394
|
text-align: center;
|
|
446
395
|
}
|
|
447
396
|
|
|
@@ -454,6 +403,104 @@ button {
|
|
|
454
403
|
background: linear-gradient(transparent, var(--mop-cream) 28%);
|
|
455
404
|
}
|
|
456
405
|
|
|
406
|
+
.mop-chat-history {
|
|
407
|
+
min-width: 0;
|
|
408
|
+
min-height: 0;
|
|
409
|
+
display: flex;
|
|
410
|
+
flex-direction: column;
|
|
411
|
+
padding: 17px 13px 13px;
|
|
412
|
+
color: var(--mop-green);
|
|
413
|
+
border-left: 1px solid rgba(45, 74, 62, .3);
|
|
414
|
+
background:
|
|
415
|
+
linear-gradient(rgba(255, 253, 242, .84), rgba(254, 249, 225, .94)),
|
|
416
|
+
repeating-linear-gradient(0deg, transparent 0, transparent 7px, rgba(116, 34, 32, .04) 7px, rgba(116, 34, 32, .04) 8px);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.mop-chat-history-header {
|
|
420
|
+
display: flex;
|
|
421
|
+
align-items: center;
|
|
422
|
+
justify-content: space-between;
|
|
423
|
+
gap: 12px;
|
|
424
|
+
padding: 2px 2px 14px;
|
|
425
|
+
border-bottom: 1px solid rgba(45, 74, 62, .24);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.mop-chat-history-header > div { display: grid; gap: 3px; }
|
|
429
|
+
.mop-chat-history-header span {
|
|
430
|
+
color: var(--mop-red);
|
|
431
|
+
font-family: "SFMono-Regular", Consolas, monospace;
|
|
432
|
+
font-size: 8px;
|
|
433
|
+
font-weight: 900;
|
|
434
|
+
letter-spacing: .16em;
|
|
435
|
+
}
|
|
436
|
+
.mop-chat-history-header strong { font-family: "SFMono-Regular", Consolas, monospace; font-size: 15px; }
|
|
437
|
+
.mop-chat-history-header button {
|
|
438
|
+
width: 34px;
|
|
439
|
+
height: 34px;
|
|
440
|
+
border: 1px solid rgba(45, 74, 62, .38);
|
|
441
|
+
background: var(--mop-red);
|
|
442
|
+
color: var(--mop-cream);
|
|
443
|
+
font-size: 20px;
|
|
444
|
+
cursor: pointer;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.mop-chat-history-list {
|
|
448
|
+
min-height: 0;
|
|
449
|
+
display: grid;
|
|
450
|
+
align-content: start;
|
|
451
|
+
gap: 6px;
|
|
452
|
+
overflow-y: auto;
|
|
453
|
+
padding: 12px 1px;
|
|
454
|
+
scrollbar-width: thin;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
.mop-chat-history-empty {
|
|
458
|
+
margin: 8px 5px;
|
|
459
|
+
color: rgba(45, 74, 62, .58);
|
|
460
|
+
font-size: 12px;
|
|
461
|
+
line-height: 1.55;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.mop-chat-history-item {
|
|
465
|
+
display: grid;
|
|
466
|
+
grid-template-columns: minmax(0, 1fr) 28px;
|
|
467
|
+
align-items: stretch;
|
|
468
|
+
border: 1px solid transparent;
|
|
469
|
+
}
|
|
470
|
+
.mop-chat-history-item:hover,
|
|
471
|
+
.mop-chat-history-item.is-active {
|
|
472
|
+
border-color: rgba(45, 74, 62, .24);
|
|
473
|
+
background: rgba(255, 253, 242, .78);
|
|
474
|
+
}
|
|
475
|
+
.mop-chat-history-item.is-active { border-left: 3px solid var(--mop-red); }
|
|
476
|
+
.mop-chat-history-open,
|
|
477
|
+
.mop-chat-history-delete {
|
|
478
|
+
min-width: 0;
|
|
479
|
+
border: 0;
|
|
480
|
+
box-shadow: none;
|
|
481
|
+
background: transparent;
|
|
482
|
+
color: var(--mop-green);
|
|
483
|
+
cursor: pointer;
|
|
484
|
+
}
|
|
485
|
+
.mop-chat-history-open {
|
|
486
|
+
display: grid;
|
|
487
|
+
gap: 4px;
|
|
488
|
+
padding: 9px 7px 9px 9px;
|
|
489
|
+
text-align: left;
|
|
490
|
+
}
|
|
491
|
+
.mop-chat-history-open strong {
|
|
492
|
+
overflow: hidden;
|
|
493
|
+
text-overflow: ellipsis;
|
|
494
|
+
white-space: nowrap;
|
|
495
|
+
font-size: 12px;
|
|
496
|
+
font-weight: 760;
|
|
497
|
+
}
|
|
498
|
+
.mop-chat-history-open span { color: rgba(45, 74, 62, .5); font-size: 9px; }
|
|
499
|
+
.mop-chat-history-delete { opacity: 0; padding: 0; font-size: 17px; }
|
|
500
|
+
.mop-chat-history-item:hover .mop-chat-history-delete,
|
|
501
|
+
.mop-chat-history-item.is-active .mop-chat-history-delete { opacity: .65; }
|
|
502
|
+
.mop-chat-history-delete:hover { color: var(--mop-red); opacity: 1 !important; }
|
|
503
|
+
|
|
457
504
|
.mop-settings-grid {
|
|
458
505
|
display: grid;
|
|
459
506
|
grid-template-columns: 1fr;
|
|
@@ -497,11 +544,10 @@ button {
|
|
|
497
544
|
.mop-app-topbar { grid-template-columns: 66px minmax(0, 1fr); }
|
|
498
545
|
.mop-app-brand { justify-content: center; padding: 5px; }
|
|
499
546
|
.mop-app-brand img { width: 49px; height: 49px; }
|
|
500
|
-
.mop-app-brand span
|
|
547
|
+
.mop-app-brand span { display: none; }
|
|
501
548
|
.mop-app-topbar-main { padding: 0 10px; gap: 9px; }
|
|
502
549
|
.mop-menu-toggle { display: block; }
|
|
503
|
-
.mop-topbar-
|
|
504
|
-
.mop-topbar-meta > span:first-child { display: none; }
|
|
550
|
+
.mop-topbar-center { min-width: 0; flex: 1; padding: 8px 12px; font-size: 10px; }
|
|
505
551
|
.mop-app-sidebar {
|
|
506
552
|
position: fixed;
|
|
507
553
|
top: 62px;
|
|
@@ -522,9 +568,8 @@ button {
|
|
|
522
568
|
background: rgba(20, 34, 29, .56);
|
|
523
569
|
}
|
|
524
570
|
.mop-app-main { min-height: calc(100vh - 62px); }
|
|
525
|
-
.mop-assistant-page {
|
|
526
|
-
.mop-
|
|
527
|
-
.mop-assistant-status { display: none; }
|
|
571
|
+
.mop-assistant-page { height: calc(100vh - 62px); min-height: 520px; grid-template-columns: minmax(0, 1fr); }
|
|
572
|
+
.mop-chat-history { display: none; }
|
|
528
573
|
.mop-assistant-conversation { padding: 0 16px; }
|
|
529
574
|
.mop-assistant-composer-wrap { padding: 26px 12px 12px; }
|
|
530
575
|
.mop-settings-grid { grid-template-columns: 1fr; }
|
|
@@ -535,7 +580,6 @@ button {
|
|
|
535
580
|
display: flex;
|
|
536
581
|
align-items: center;
|
|
537
582
|
justify-content: center;
|
|
538
|
-
gap: 8px;
|
|
539
583
|
width: 100%;
|
|
540
584
|
min-height: 40px;
|
|
541
585
|
margin-bottom: 9px;
|
|
@@ -547,19 +591,12 @@ button {
|
|
|
547
591
|
font-size: 11px;
|
|
548
592
|
font-weight: 900;
|
|
549
593
|
text-decoration: none;
|
|
550
|
-
|
|
551
|
-
transition: transform 80ms steps(2, end), box-shadow 80ms steps(2, end);
|
|
552
|
-
box-shadow: 2px 2px 0 rgba(45, 74, 62, .17);
|
|
594
|
+
box-shadow: 2px 2px 0 rgba(18, 38, 30, .28);
|
|
553
595
|
}
|
|
554
596
|
|
|
555
|
-
.mop-back-workspace-btn:hover {
|
|
556
|
-
transform: translate(-1px, -1px);
|
|
557
|
-
box-shadow: 3px 3px 0 rgba(45, 74, 62, .24);
|
|
558
|
-
color: var(--mop-cream);
|
|
559
|
-
}
|
|
597
|
+
.mop-back-workspace-btn:hover { color: var(--mop-cream); transform: translate(-1px, -1px); }
|
|
560
598
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
599
|
+
@media (min-width: 761px) and (max-width: 1050px) {
|
|
600
|
+
.mop-assistant-page { grid-template-columns: minmax(0, 1fr) 235px; }
|
|
601
|
+
.mop-chat-history { padding-inline: 9px; }
|
|
564
602
|
}
|
|
565
|
-
|
|
@@ -12,13 +12,9 @@ export type AppViewer = {
|
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
export type Project = { id: string; name: string; status: string };
|
|
15
|
-
export type ProviderState = { configured: boolean; provider?: string; model?: string | null };
|
|
16
15
|
|
|
17
16
|
interface MemoryCoreContextType {
|
|
18
|
-
selectedProject: string;
|
|
19
|
-
setSelectedProject: (id: string) => void;
|
|
20
17
|
projects: Project[];
|
|
21
|
-
provider: ProviderState;
|
|
22
18
|
settingsSection: "providers" | "users";
|
|
23
19
|
setSettingsSection: (section: "providers" | "users") => void;
|
|
24
20
|
}
|
|
@@ -27,9 +23,7 @@ const MemoryCoreContext = createContext<MemoryCoreContextType | undefined>(undef
|
|
|
27
23
|
|
|
28
24
|
export function useMemoryCore() {
|
|
29
25
|
const context = useContext(MemoryCoreContext);
|
|
30
|
-
if (!context)
|
|
31
|
-
throw new Error("useMemoryCore must be used within a MemoryCoreProvider");
|
|
32
|
-
}
|
|
26
|
+
if (!context) throw new Error("useMemoryCore must be used within a MemoryCoreProvider");
|
|
33
27
|
return context;
|
|
34
28
|
}
|
|
35
29
|
|
|
@@ -46,22 +40,17 @@ function pageTitle(pathname: string): string {
|
|
|
46
40
|
export function AppShell({ viewer, children }: { viewer: AppViewer; children: ReactNode }) {
|
|
47
41
|
const pathname = usePathname();
|
|
48
42
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
49
|
-
const isAdmin = viewer.role === "owner";
|
|
50
|
-
const title = pageTitle(pathname);
|
|
51
|
-
|
|
52
43
|
const [projects, setProjects] = useState<Project[]>([]);
|
|
53
|
-
const [provider, setProvider] = useState<ProviderState>({ configured: false });
|
|
54
|
-
const [selectedProject, setSelectedProject] = useState("");
|
|
55
44
|
const [settingsSection, setSettingsSection] = useState<"providers" | "users">("providers");
|
|
45
|
+
const isAdmin = viewer.role === "owner";
|
|
46
|
+
const isSettings = pathname.startsWith("/settings");
|
|
47
|
+
const title = pageTitle(pathname);
|
|
56
48
|
|
|
57
49
|
useEffect(() => {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
setProjects(projectData.projects ?? []);
|
|
63
|
-
setProvider(providerData.config ?? { configured: false });
|
|
64
|
-
}).catch(() => {});
|
|
50
|
+
fetch("/api/projects")
|
|
51
|
+
.then((response) => response.json())
|
|
52
|
+
.then((data) => setProjects(data.projects ?? []))
|
|
53
|
+
.catch(() => {});
|
|
65
54
|
|
|
66
55
|
const requested = new URLSearchParams(window.location.search).get("section");
|
|
67
56
|
if (requested === "users") setSettingsSection("users");
|
|
@@ -72,21 +61,13 @@ export function AppShell({ viewer, children }: { viewer: AppViewer; children: Re
|
|
|
72
61
|
window.location.replace("/login");
|
|
73
62
|
}
|
|
74
63
|
|
|
75
|
-
|
|
76
|
-
setSettingsSection(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const isSettings = pathname.startsWith("/settings");
|
|
82
|
-
|
|
83
|
-
const nav = [
|
|
84
|
-
{ href: "/assistant", label: "Assistant", icon: "✦", active: pathname.startsWith("/assistant") || pathname.startsWith("/chat/") },
|
|
85
|
-
{ href: "/brain", label: "Brain", icon: "◉", active: pathname.startsWith("/brain") },
|
|
86
|
-
];
|
|
64
|
+
function selectSection(section: "providers" | "users") {
|
|
65
|
+
setSettingsSection(section);
|
|
66
|
+
window.history.replaceState(null, "", section === "providers" ? "/settings" : "/settings?section=users");
|
|
67
|
+
}
|
|
87
68
|
|
|
88
69
|
return (
|
|
89
|
-
<MemoryCoreContext.Provider value={{
|
|
70
|
+
<MemoryCoreContext.Provider value={{ projects, settingsSection, setSettingsSection }}>
|
|
90
71
|
<div className="mop-app-frame">
|
|
91
72
|
<header className="mop-app-topbar">
|
|
92
73
|
<a className="mop-app-brand" href="/assistant" aria-label="MOP-AGENT home">
|
|
@@ -103,36 +84,10 @@ export function AppShell({ viewer, children }: { viewer: AppViewer; children: Re
|
|
|
103
84
|
>
|
|
104
85
|
☰
|
|
105
86
|
</button>
|
|
106
|
-
|
|
107
|
-
<
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
<strong>LIVE ASSISTANT</strong>
|
|
111
|
-
<span className="mop-assistant-provider">
|
|
112
|
-
{provider.configured ? `${provider.provider}${provider.model ? ` · ${provider.model}` : ""}` : "offline demo"}
|
|
113
|
-
</span>
|
|
114
|
-
</div>
|
|
115
|
-
<label className="mop-assistant-scope">
|
|
116
|
-
MEMORY SCOPE
|
|
117
|
-
<select value={selectedProject} onChange={(e) => setSelectedProject(e.target.value)}>
|
|
118
|
-
<option value="">All memory</option>
|
|
119
|
-
{projects.map((project) => <option key={project.id} value={project.id}>{project.name}</option>)}
|
|
120
|
-
</select>
|
|
121
|
-
</label>
|
|
122
|
-
</div>
|
|
123
|
-
) : (
|
|
124
|
-
<>
|
|
125
|
-
<div className="mop-topbar-title">
|
|
126
|
-
<span className="mop-live-dot" />
|
|
127
|
-
<strong>{title}</strong>
|
|
128
|
-
</div>
|
|
129
|
-
<div className="mop-topbar-center">MOP MEMORYCORE</div>
|
|
130
|
-
<div className="mop-topbar-meta">
|
|
131
|
-
<span>{isAdmin ? "ADMIN" : "MEMBER"}</span>
|
|
132
|
-
<span className="mop-version">v0.1.12</span>
|
|
133
|
-
</div>
|
|
134
|
-
</>
|
|
135
|
-
)}
|
|
87
|
+
<div className="mop-topbar-center">
|
|
88
|
+
<span className="mop-live-dot" />
|
|
89
|
+
<strong>{title}</strong>
|
|
90
|
+
</div>
|
|
136
91
|
</div>
|
|
137
92
|
</header>
|
|
138
93
|
|
|
@@ -155,23 +110,22 @@ export function AppShell({ viewer, children }: { viewer: AppViewer; children: Re
|
|
|
155
110
|
</div>
|
|
156
111
|
) : (
|
|
157
112
|
<>
|
|
158
|
-
<
|
|
159
|
-
<
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
</div>
|
|
113
|
+
<nav className="mop-sidebar-primary" aria-label="Workspace">
|
|
114
|
+
<a href="/assistant" className={pathname.startsWith("/assistant") || pathname.startsWith("/chat/") ? "is-active" : ""} onClick={() => setMenuOpen(false)}>
|
|
115
|
+
<span className="mop-nav-icon">✎</span>
|
|
116
|
+
<span>New chat</span>
|
|
117
|
+
</a>
|
|
118
|
+
<a href="/brain" className={pathname.startsWith("/brain") ? "is-active" : ""} onClick={() => setMenuOpen(false)}>
|
|
119
|
+
<span className="mop-nav-icon">◉</span>
|
|
120
|
+
<span>Brain</span>
|
|
121
|
+
</a>
|
|
122
|
+
</nav>
|
|
169
123
|
|
|
170
124
|
{isAdmin && (
|
|
171
|
-
<div className="mop-nav-section">
|
|
125
|
+
<div className="mop-nav-section mop-admin-nav">
|
|
172
126
|
<p>ADMIN</p>
|
|
173
127
|
<nav>
|
|
174
|
-
<a href="/settings"
|
|
128
|
+
<a href="/settings" onClick={() => setMenuOpen(false)}>
|
|
175
129
|
<span className="mop-nav-icon">⚙</span>
|
|
176
130
|
<span>Settings</span>
|
|
177
131
|
</a>
|
|
@@ -182,20 +136,18 @@ export function AppShell({ viewer, children }: { viewer: AppViewer; children: Re
|
|
|
182
136
|
)}
|
|
183
137
|
|
|
184
138
|
<div className="mop-sidebar-spacer" />
|
|
185
|
-
|
|
186
139
|
{isSettings && (
|
|
187
|
-
<a href="/assistant" className="mop-back-workspace-btn">
|
|
140
|
+
<a href="/assistant" className="mop-back-workspace-btn" onClick={() => setMenuOpen(false)}>
|
|
188
141
|
<span>← BACK TO WORKSPACE</span>
|
|
189
142
|
</a>
|
|
190
143
|
)}
|
|
191
|
-
|
|
192
144
|
<button className="mop-account-card" type="button" onClick={logout} title="Sign out">
|
|
193
145
|
<span className="mop-account-avatar">{viewer.name.slice(0, 1).toUpperCase()}</span>
|
|
194
146
|
<span className="mop-account-copy">
|
|
195
147
|
<strong>{viewer.name}</strong>
|
|
196
148
|
<small>{isAdmin ? "Administrator" : "Member"}</small>
|
|
197
149
|
</span>
|
|
198
|
-
<span aria-hidden="true"
|
|
150
|
+
<span aria-hidden="true">•••</span>
|
|
199
151
|
</button>
|
|
200
152
|
</aside>
|
|
201
153
|
|
|
@@ -204,4 +156,3 @@ export function AppShell({ viewer, children }: { viewer: AppViewer; children: Re
|
|
|
204
156
|
</MemoryCoreContext.Provider>
|
|
205
157
|
);
|
|
206
158
|
}
|
|
207
|
-
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mop-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "mop-agent",
|
|
9
|
-
"version": "0.1.
|
|
9
|
+
"version": "0.1.14",
|
|
10
10
|
"license": "UNLICENSED",
|
|
11
11
|
"workspaces": [
|
|
12
12
|
"packages/*",
|
package/package.json
CHANGED