@jungjaehoon/mama-os 0.62.0 → 0.64.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 +66 -0
- package/README.md +1 -1
- package/dist/api/attachment-actions.d.ts.map +1 -1
- package/dist/api/attachment-actions.js +6 -2
- package/dist/api/attachment-actions.js.map +1 -1
- package/dist/api/drive-actions.d.ts +2 -1
- package/dist/api/drive-actions.d.ts.map +1 -1
- package/dist/api/drive-actions.js +1 -0
- package/dist/api/drive-actions.js.map +1 -1
- package/dist/api/drive-delivery.d.ts +16 -0
- package/dist/api/drive-delivery.d.ts.map +1 -0
- package/dist/api/drive-delivery.js +190 -0
- package/dist/api/drive-delivery.js.map +1 -0
- package/dist/api/file-delivery.d.ts +2 -2
- package/dist/api/file-delivery.d.ts.map +1 -1
- package/dist/api/file-delivery.js +5 -5
- package/dist/api/file-delivery.js.map +1 -1
- package/dist/api/security-events.d.ts +5 -4
- package/dist/api/security-events.d.ts.map +1 -1
- package/dist/api/security-events.js +25 -3
- package/dist/api/security-events.js.map +1 -1
- package/dist/api/viewer-data.d.ts +82 -1
- package/dist/api/viewer-data.d.ts.map +1 -1
- package/dist/api/viewer-data.js +116 -0
- package/dist/api/viewer-data.js.map +1 -1
- package/dist/api/viewer-server.d.ts +2 -2
- package/dist/api/viewer-server.d.ts.map +1 -1
- package/dist/api/viewer-server.js +154 -5
- package/dist/api/viewer-server.js.map +1 -1
- package/dist/api/wiki-actions.d.ts.map +1 -1
- package/dist/api/wiki-actions.js +44 -0
- package/dist/api/wiki-actions.js.map +1 -1
- package/dist/api/work-actions.d.ts +2 -0
- package/dist/api/work-actions.d.ts.map +1 -1
- package/dist/api/work-actions.js +4 -5
- package/dist/api/work-actions.js.map +1 -1
- package/dist/cli/commands/daemon.d.ts.map +1 -1
- package/dist/cli/commands/daemon.js +14 -7
- package/dist/cli/commands/daemon.js.map +1 -1
- package/dist/gateways/discord.d.ts.map +1 -1
- package/dist/gateways/discord.js +1 -1
- package/dist/gateways/discord.js.map +1 -1
- package/dist/gateways/slack.d.ts.map +1 -1
- package/dist/gateways/slack.js +1 -1
- package/dist/gateways/slack.js.map +1 -1
- package/dist/gateways/telegram.d.ts.map +1 -1
- package/dist/gateways/telegram.js +1 -1
- package/dist/gateways/telegram.js.map +1 -1
- package/dist/replay/replay-source-catalog.js +1 -1
- package/dist/replay/replay-source-catalog.js.map +1 -1
- package/dist/runtime/action-surface.d.ts +4 -1
- package/dist/runtime/action-surface.d.ts.map +1 -1
- package/dist/runtime/action-surface.js +19 -1
- package/dist/runtime/action-surface.js.map +1 -1
- package/dist/runtime/config.d.ts +20 -0
- package/dist/runtime/config.d.ts.map +1 -1
- package/dist/runtime/config.js +48 -3
- package/dist/runtime/config.js.map +1 -1
- package/dist/runtime/outbound-attempts.d.ts +4 -2
- package/dist/runtime/outbound-attempts.d.ts.map +1 -1
- package/dist/runtime/outbound-attempts.js +17 -1
- package/dist/runtime/outbound-attempts.js.map +1 -1
- package/dist/runtime/owner-runtime.d.ts +6 -1
- package/dist/runtime/owner-runtime.d.ts.map +1 -1
- package/dist/runtime/owner-runtime.js +4 -1
- package/dist/runtime/owner-runtime.js.map +1 -1
- package/dist/runtime/owner-system-prompt.d.ts +1 -1
- package/dist/runtime/owner-system-prompt.d.ts.map +1 -1
- package/dist/runtime/owner-system-prompt.js +10 -4
- package/dist/runtime/owner-system-prompt.js.map +1 -1
- package/dist/runtime/report-scheduler.d.ts +2 -1
- package/dist/runtime/report-scheduler.d.ts.map +1 -1
- package/dist/runtime/report-scheduler.js +1 -1
- package/dist/runtime/report-scheduler.js.map +1 -1
- package/dist/runtime/stimulus-delivery.js +1 -1
- package/dist/runtime/stimulus-delivery.js.map +1 -1
- package/dist/runtime/turn-orders.d.ts.map +1 -1
- package/dist/runtime/turn-orders.js +7 -3
- package/dist/runtime/turn-orders.js.map +1 -1
- package/dist/wiki/obsidian-writer.d.ts +0 -3
- package/dist/wiki/obsidian-writer.d.ts.map +1 -1
- package/dist/wiki/obsidian-writer.js +8 -108
- package/dist/wiki/obsidian-writer.js.map +1 -1
- package/dist/wiki/path-safety.d.ts +1 -1
- package/dist/wiki/path-safety.d.ts.map +1 -1
- package/dist/wiki/path-safety.js +2 -2
- package/dist/wiki/path-safety.js.map +1 -1
- package/dist/wiki/wiki-move.d.ts +12 -0
- package/dist/wiki/wiki-move.d.ts.map +1 -0
- package/dist/wiki/wiki-move.js +95 -0
- package/dist/wiki/wiki-move.js.map +1 -0
- package/dist/wiki/wiki-read.d.ts +7 -0
- package/dist/wiki/wiki-read.d.ts.map +1 -1
- package/dist/wiki/wiki-read.js +38 -17
- package/dist/wiki/wiki-read.js.map +1 -1
- package/package.json +2 -2
- package/public/viewer/js/modules/graph.js +266 -992
- package/public/viewer/js/modules/memory-timeline.js +216 -0
- package/public/viewer/js/modules/wiki.js +4 -4
- package/public/viewer/js/utils/api.js +7 -26
- package/public/viewer/src/modules/graph.ts +307 -1185
- package/public/viewer/src/modules/memory-timeline.ts +280 -0
- package/public/viewer/src/modules/wiki.ts +4 -4
- package/public/viewer/src/utils/api.ts +48 -47
- package/public/viewer/viewer.css +257 -7
- package/public/viewer/viewer.html +68 -292
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Timeline Module - what was saved, and when
|
|
3
|
+
* @module modules/memory-timeline
|
|
4
|
+
*
|
|
5
|
+
* The memory view's list: a period (today, 7 days, 30 days or one day), then by day, then by
|
|
6
|
+
* kind, then by work item and its updates. Every filter is a server read, so the list and the
|
|
7
|
+
* counts on the kind chips always describe the same records.
|
|
8
|
+
*/
|
|
9
|
+
/* eslint-env browser */
|
|
10
|
+
import { escapeAttr, escapeHtml, debounce, getElementByIdOrNull } from '../utils/dom.js';
|
|
11
|
+
import { API, } from '../utils/api.js';
|
|
12
|
+
/** The groups the server names first, in its order, with the words and colours the list shows. */
|
|
13
|
+
const GROUPS = {
|
|
14
|
+
owner_rule: {
|
|
15
|
+
label: 'Owner rules',
|
|
16
|
+
hint: 'Rules the owner set in their own chat',
|
|
17
|
+
color: '#FB7185',
|
|
18
|
+
},
|
|
19
|
+
learned: {
|
|
20
|
+
label: 'Learned rules',
|
|
21
|
+
hint: 'Lessons, preferences, constraints and workflows learned in other turns',
|
|
22
|
+
color: '#FBBF24',
|
|
23
|
+
},
|
|
24
|
+
decision: { label: 'Decisions', hint: 'Decisions recorded', color: '#60A5FA' },
|
|
25
|
+
fact: { label: 'Facts', hint: 'Facts recorded', color: '#2DD4BF' },
|
|
26
|
+
work: { label: 'Work updates', hint: 'Work items opened or updated', color: '#FB923C' },
|
|
27
|
+
};
|
|
28
|
+
const VIA_LABELS = {
|
|
29
|
+
owner_chat: 'owner chat',
|
|
30
|
+
source_delta: 'source update',
|
|
31
|
+
report: 'report',
|
|
32
|
+
};
|
|
33
|
+
const OPERATION_LABELS = {
|
|
34
|
+
create: 'opened',
|
|
35
|
+
revise: 'updated',
|
|
36
|
+
withdraw: 'withdrawn',
|
|
37
|
+
};
|
|
38
|
+
export function groupInfo(group) {
|
|
39
|
+
return GROUPS[group] ?? { label: group, hint: `Records of kind ${group}`, color: '#CBD5E1' };
|
|
40
|
+
}
|
|
41
|
+
function dayLabel(day) {
|
|
42
|
+
return new Intl.DateTimeFormat(undefined, {
|
|
43
|
+
weekday: 'short',
|
|
44
|
+
year: 'numeric',
|
|
45
|
+
month: 'short',
|
|
46
|
+
day: 'numeric',
|
|
47
|
+
timeZone: 'UTC',
|
|
48
|
+
}).format(new Date(`${day}T00:00:00Z`));
|
|
49
|
+
}
|
|
50
|
+
export class MemoryTimelineModule {
|
|
51
|
+
hooks;
|
|
52
|
+
period = '7d';
|
|
53
|
+
day = null;
|
|
54
|
+
query = '';
|
|
55
|
+
groups = new Set();
|
|
56
|
+
selectedId = null;
|
|
57
|
+
request = 0;
|
|
58
|
+
bound = false;
|
|
59
|
+
debouncedLoad = debounce(() => void this.load(), 300);
|
|
60
|
+
constructor(hooks) {
|
|
61
|
+
this.hooks = hooks;
|
|
62
|
+
}
|
|
63
|
+
/** Wire the controls once, then read the current period. */
|
|
64
|
+
async init() {
|
|
65
|
+
if (!this.bound) {
|
|
66
|
+
this.bind();
|
|
67
|
+
this.bound = true;
|
|
68
|
+
}
|
|
69
|
+
await this.load();
|
|
70
|
+
}
|
|
71
|
+
bind() {
|
|
72
|
+
document.querySelectorAll('[data-memory-period]').forEach((button) => {
|
|
73
|
+
button.addEventListener('click', () => {
|
|
74
|
+
this.period = button.dataset.memoryPeriod ?? '7d';
|
|
75
|
+
this.day = null;
|
|
76
|
+
const dayInput = getElementByIdOrNull('memory-day');
|
|
77
|
+
if (dayInput)
|
|
78
|
+
dayInput.value = '';
|
|
79
|
+
void this.load();
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
getElementByIdOrNull('memory-day')?.addEventListener('change', (event) => {
|
|
83
|
+
const value = event.target.value;
|
|
84
|
+
this.day = value === '' ? null : value;
|
|
85
|
+
void this.load();
|
|
86
|
+
});
|
|
87
|
+
getElementByIdOrNull('memory-timeline-search')?.addEventListener('input', (event) => {
|
|
88
|
+
this.query = event.target.value.trim();
|
|
89
|
+
this.debouncedLoad();
|
|
90
|
+
});
|
|
91
|
+
getElementByIdOrNull('memory-group-chips')?.addEventListener('click', (event) => {
|
|
92
|
+
const chip = event.target.closest('[data-group]');
|
|
93
|
+
if (!chip?.dataset.group)
|
|
94
|
+
return;
|
|
95
|
+
const group = chip.dataset.group;
|
|
96
|
+
if (this.groups.has(group))
|
|
97
|
+
this.groups.delete(group);
|
|
98
|
+
else
|
|
99
|
+
this.groups.add(group);
|
|
100
|
+
void this.load();
|
|
101
|
+
});
|
|
102
|
+
getElementByIdOrNull('memory-timeline')?.addEventListener('click', (event) => {
|
|
103
|
+
const row = event.target.closest('[data-record-id]');
|
|
104
|
+
if (!row?.dataset.recordId)
|
|
105
|
+
return;
|
|
106
|
+
this.select(row.dataset.recordId);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
select(id) {
|
|
110
|
+
this.selectedId = id;
|
|
111
|
+
document.querySelectorAll('#memory-timeline .mt-row.selected').forEach((row) => {
|
|
112
|
+
row.classList.remove('selected');
|
|
113
|
+
});
|
|
114
|
+
document
|
|
115
|
+
.querySelector(`#memory-timeline [data-record-id="${CSS.escape(id)}"]`)
|
|
116
|
+
?.classList.add('selected');
|
|
117
|
+
this.hooks.onSelect(id);
|
|
118
|
+
}
|
|
119
|
+
params() {
|
|
120
|
+
return {
|
|
121
|
+
...(this.day === null ? { period: this.period } : { from: this.day, to: this.day }),
|
|
122
|
+
...(this.query === '' ? {} : { q: this.query }),
|
|
123
|
+
...(this.groups.size === 0 ? {} : { groups: [...this.groups].join(',') }),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
async load() {
|
|
127
|
+
const list = getElementByIdOrNull('memory-timeline');
|
|
128
|
+
if (!list)
|
|
129
|
+
return;
|
|
130
|
+
const request = ++this.request;
|
|
131
|
+
list.setAttribute('aria-busy', 'true');
|
|
132
|
+
try {
|
|
133
|
+
const data = await API.getMemoryTimeline(this.params());
|
|
134
|
+
// A slower earlier read must not overwrite the answer to the latest filter.
|
|
135
|
+
if (request !== this.request)
|
|
136
|
+
return;
|
|
137
|
+
this.render(data);
|
|
138
|
+
this.hooks.onRender(data);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
if (request !== this.request)
|
|
142
|
+
return;
|
|
143
|
+
list.innerHTML = `<div class="mt-empty mt-error">Could not read what was saved: ${escapeHtml(error instanceof Error ? error.message : String(error))}</div>`;
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
if (request === this.request)
|
|
147
|
+
list.removeAttribute('aria-busy');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
render(data) {
|
|
151
|
+
document.querySelectorAll('[data-memory-period]').forEach((button) => {
|
|
152
|
+
button.setAttribute('aria-pressed', String(this.day === null && button.dataset.memoryPeriod === this.period));
|
|
153
|
+
});
|
|
154
|
+
const range = getElementByIdOrNull('memory-timeline-range');
|
|
155
|
+
if (range) {
|
|
156
|
+
range.textContent =
|
|
157
|
+
data.from === data.to
|
|
158
|
+
? dayLabel(data.from)
|
|
159
|
+
: `${dayLabel(data.from)} – ${dayLabel(data.to)}`;
|
|
160
|
+
}
|
|
161
|
+
const count = getElementByIdOrNull('memory-timeline-count');
|
|
162
|
+
if (count)
|
|
163
|
+
count.textContent = `${data.total} saved`;
|
|
164
|
+
this.renderChips(data.counts);
|
|
165
|
+
const list = getElementByIdOrNull('memory-timeline');
|
|
166
|
+
if (!list)
|
|
167
|
+
return;
|
|
168
|
+
if (data.days.length === 0) {
|
|
169
|
+
list.innerHTML = `<div class="mt-empty">Nothing saved${this.query === '' ? '' : ` matching “${escapeHtml(this.query)}”`} in this period.</div>`;
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
list.innerHTML = data.days
|
|
173
|
+
.map((day) => `<section class="mt-day"><h3 class="mt-day-head"><span>${escapeHtml(dayLabel(day.day))}</span><span class="mt-count">${day.total}</span></h3>${day.groups
|
|
174
|
+
.map((group) => this.renderGroup(group))
|
|
175
|
+
.join('')}</section>`)
|
|
176
|
+
.join('');
|
|
177
|
+
if (this.selectedId !== null) {
|
|
178
|
+
document
|
|
179
|
+
.querySelector(`#memory-timeline [data-record-id="${CSS.escape(this.selectedId)}"]`)
|
|
180
|
+
?.classList.add('selected');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
renderChips(counts) {
|
|
184
|
+
const container = getElementByIdOrNull('memory-group-chips');
|
|
185
|
+
if (!container)
|
|
186
|
+
return;
|
|
187
|
+
container.innerHTML = Object.entries(counts)
|
|
188
|
+
.filter(([group, count]) => count > 0 || this.groups.has(group))
|
|
189
|
+
.map(([group, count]) => {
|
|
190
|
+
const info = groupInfo(group);
|
|
191
|
+
return `<button type="button" class="memory-chip" data-group="${escapeAttr(group)}" aria-pressed="${this.groups.has(group)}" title="${escapeAttr(info.hint)}"><span class="mt-dot" style="background:${info.color}"></span>${escapeHtml(info.label)} <span class="mt-count">${count}</span></button>`;
|
|
192
|
+
})
|
|
193
|
+
.join('');
|
|
194
|
+
}
|
|
195
|
+
renderGroup(group) {
|
|
196
|
+
const info = groupInfo(group.group);
|
|
197
|
+
const body = group.items !== undefined
|
|
198
|
+
? group.items.map((item) => this.renderItem(item)).join('')
|
|
199
|
+
: (group.records ?? []).map((record) => this.renderRecord(record)).join('');
|
|
200
|
+
return `<details class="mt-group" open><summary class="mt-group-head" title="${escapeAttr(info.hint)}"><span class="mt-dot" style="background:${info.color}"></span>${escapeHtml(info.label)}<span class="mt-count">${group.count}</span></summary>${body}</details>`;
|
|
201
|
+
}
|
|
202
|
+
renderRecord(record) {
|
|
203
|
+
const via = record.via === null ? '' : (VIA_LABELS[record.via] ?? record.via);
|
|
204
|
+
const status = record.status === null || record.status === 'active'
|
|
205
|
+
? ''
|
|
206
|
+
: `<span class="mt-badge">${escapeHtml(record.status)}</span>`;
|
|
207
|
+
return `<button type="button" class="mt-row" data-record-id="${escapeAttr(record.id)}"><span class="mt-time">${escapeHtml(record.time)}</span><span class="mt-body"><span class="mt-topic">${escapeHtml(record.topic)}${status}</span><span class="mt-summary">${escapeHtml(record.summary)}</span>${via === '' ? '' : `<span class="mt-via">from ${escapeHtml(via)}</span>`}</span></button>`;
|
|
208
|
+
}
|
|
209
|
+
renderItem(item) {
|
|
210
|
+
const latest = item.revisions[0];
|
|
211
|
+
const updates = item.revisions.length;
|
|
212
|
+
return `<details class="mt-item"><summary class="mt-item-head"><span class="mt-time">${escapeHtml(latest?.time ?? '')}</span><span class="mt-body"><span class="mt-topic">${escapeHtml(item.title ?? item.topic)}</span><span class="mt-summary">${escapeHtml(latest?.summary ?? '')}</span></span><span class="mt-count">${updates} ${updates === 1 ? 'update' : 'updates'}</span></summary>${item.revisions
|
|
213
|
+
.map((revision) => `<button type="button" class="mt-row mt-revision" data-record-id="${escapeAttr(revision.id)}"><span class="mt-time">${escapeHtml(revision.time)}</span><span class="mt-body"><span class="mt-op">${escapeHtml(OPERATION_LABELS[revision.operation ?? ''] ?? revision.operation ?? '')}${revision.revision === null ? '' : ` · revision ${revision.revision}`}</span><span class="mt-summary">${escapeHtml(revision.summary)}</span></span></button>`)
|
|
214
|
+
.join('')}</details>`;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -154,11 +154,11 @@ export class WikiModule {
|
|
|
154
154
|
});
|
|
155
155
|
});
|
|
156
156
|
document.getElementById('wiki-new-btn')?.addEventListener('click', () => this.promptNewPage());
|
|
157
|
-
// Auto-open
|
|
157
|
+
// Auto-open the agent's table of contents only on initial load (no page selected yet)
|
|
158
158
|
if (!this.currentPath) {
|
|
159
|
-
const
|
|
160
|
-
if (!mobile &&
|
|
161
|
-
this.openPage(
|
|
159
|
+
const homeNode = tree.find((n) => n.name === 'Home.md');
|
|
160
|
+
if (!mobile && homeNode) {
|
|
161
|
+
this.openPage(homeNode.path);
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
}
|
|
@@ -124,36 +124,17 @@ export class API {
|
|
|
124
124
|
// =============================================
|
|
125
125
|
// Graph API
|
|
126
126
|
// =============================================
|
|
127
|
-
/**
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
static async
|
|
133
|
-
|
|
134
|
-
return this.get('/graph', { cluster: 'false', ...params });
|
|
127
|
+
/** Every link between records, with each end's kind, label and work item. */
|
|
128
|
+
static async getMemoryLinks() {
|
|
129
|
+
return this.get('/api/memory/links');
|
|
130
|
+
}
|
|
131
|
+
/** What was saved in a period, by day, kind and item. */
|
|
132
|
+
static async getMemoryTimeline(params) {
|
|
133
|
+
return this.get('/api/memory/timeline', params);
|
|
135
134
|
}
|
|
136
135
|
static async getGraphDetail(nodeId) {
|
|
137
136
|
return this.get('/graph/detail', { id: nodeId });
|
|
138
137
|
}
|
|
139
|
-
/**
|
|
140
|
-
* Get similar decisions for a node
|
|
141
|
-
* @param {string} nodeId - Node ID
|
|
142
|
-
* @returns {Promise<Object>} Similar decisions
|
|
143
|
-
*/
|
|
144
|
-
static async getSimilarDecisions(nodeId) {
|
|
145
|
-
return this.get('/graph/similar', { id: nodeId });
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Update decision outcome
|
|
149
|
-
* @param {string} id - Decision ID
|
|
150
|
-
* @param {string} outcome - Outcome value
|
|
151
|
-
* @param {string} reason - Optional reason
|
|
152
|
-
* @returns {Promise<Object>} Update result
|
|
153
|
-
*/
|
|
154
|
-
static async updateOutcome(id, outcome, reason = null) {
|
|
155
|
-
return this.post('/graph/update', { id, outcome, reason });
|
|
156
|
-
}
|
|
157
138
|
// =============================================
|
|
158
139
|
// Checkpoint API
|
|
159
140
|
// =============================================
|