omnimem 0.1.5 → 0.1.7
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/omnimem/__init__.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
__all__ = ["__version__"]
|
|
2
|
-
__version__ = "0.1.
|
|
2
|
+
__version__ = "0.1.7"
|
package/omnimem/webui.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
+
import os
|
|
4
5
|
import sqlite3
|
|
5
6
|
import threading
|
|
6
7
|
import time
|
|
@@ -74,6 +75,7 @@ HTML_PAGE = """<!doctype html>
|
|
|
74
75
|
<div class=\"tabs\">
|
|
75
76
|
<button class=\"tab-btn active\" data-tab=\"statusTab\" data-i18n=\"tab_status\">Status & Actions</button>
|
|
76
77
|
<button class=\"tab-btn\" data-tab=\"configTab\" data-i18n=\"tab_config\">Configuration</button>
|
|
78
|
+
<button class=\"tab-btn\" data-tab=\"projectTab\" data-i18n=\"tab_project\">Project Integration</button>
|
|
77
79
|
<button class=\"tab-btn\" data-tab=\"memoryTab\" data-i18n=\"tab_memory\">Memory</button>
|
|
78
80
|
</div>
|
|
79
81
|
</div>
|
|
@@ -121,6 +123,36 @@ HTML_PAGE = """<!doctype html>
|
|
|
121
123
|
</div>
|
|
122
124
|
</div>
|
|
123
125
|
|
|
126
|
+
<div id=\"projectTab\" class=\"panel\">
|
|
127
|
+
<div class=\"grid\">
|
|
128
|
+
<div class=\"card wide\">
|
|
129
|
+
<h3 data-i18n=\"project_title\">Project Integration</h3>
|
|
130
|
+
<label><span data-i18n=\"project_path\">Project Path</span><input id=\"projectPath\" placeholder=\"/path/to/your/project\" /></label>
|
|
131
|
+
<div class=\"row-btn\">
|
|
132
|
+
<button id=\"btnBrowseProject\" data-i18n=\"btn_browse_project\">Browse Directory</button>
|
|
133
|
+
<button id=\"btnUseCwd\" data-i18n=\"btn_use_cwd\">Use Server CWD</button>
|
|
134
|
+
</div>
|
|
135
|
+
<div id=\"browserPanel\" class=\"card\" style=\"margin-top:10px; display:none;\">
|
|
136
|
+
<div class=\"small\" data-i18n=\"browser_title\">Directory Browser</div>
|
|
137
|
+
<div id=\"browserPath\" class=\"small\" style=\"margin:8px 0\"></div>
|
|
138
|
+
<div class=\"row-btn\">
|
|
139
|
+
<button id=\"btnBrowserUp\" data-i18n=\"btn_browser_up\">Up</button>
|
|
140
|
+
<button id=\"btnBrowserSelect\" data-i18n=\"btn_browser_select\">Select This Directory</button>
|
|
141
|
+
<button id=\"btnBrowserClose\" data-i18n=\"btn_browser_close\">Close</button>
|
|
142
|
+
</div>
|
|
143
|
+
<div id=\"browserList\" class=\"small\" style=\"margin-top:8px\"></div>
|
|
144
|
+
</div>
|
|
145
|
+
<label><span data-i18n=\"project_id\">Project ID</span><input id=\"projectId\" placeholder=\"my-project\" /></label>
|
|
146
|
+
<div class=\"row-btn\">
|
|
147
|
+
<button id=\"btnProjectAttach\" data-i18n=\"btn_project_attach\">Attach Project + Install Agent Rules</button>
|
|
148
|
+
<button id=\"btnProjectDetach\" data-i18n=\"btn_project_detach\">Detach Project</button>
|
|
149
|
+
</div>
|
|
150
|
+
<div class=\"small\" data-i18n=\"project_hint\">Attach will create .omnimem files and inject managed memory protocol blocks into AGENTS.md / CLAUDE.md / .cursorrules.</div>
|
|
151
|
+
<pre id=\"projectOut\" class=\"small\"></pre>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
|
|
124
156
|
<div id=\"memoryTab\" class=\"panel\">
|
|
125
157
|
<div class=\"grid\">
|
|
126
158
|
<div class=\"card wide\">
|
|
@@ -151,14 +183,20 @@ HTML_PAGE = """<!doctype html>
|
|
|
151
183
|
const I18N = {
|
|
152
184
|
en: {
|
|
153
185
|
title: 'OmniMem WebUI', subtitle: 'Simple mode: Status & Actions / Configuration / Memory', language: 'Language',
|
|
154
|
-
tab_status: 'Status & Actions', tab_config: 'Configuration', tab_memory: 'Memory',
|
|
186
|
+
tab_status: 'Status & Actions', tab_config: 'Configuration', tab_project: 'Project Integration', tab_memory: 'Memory',
|
|
155
187
|
system_status: 'System Status', actions: 'Actions',
|
|
156
188
|
btn_status: 'Check Sync Status', btn_bootstrap: 'Bootstrap Device Sync', btn_push: 'Push', btn_pull: 'Pull',
|
|
157
189
|
btn_daemon_on: 'Enable Daemon', btn_daemon_off: 'Disable Daemon',
|
|
158
190
|
config_title: 'Configuration', cfg_path: 'Config Path', cfg_home: 'Home', cfg_markdown: 'Markdown Path', cfg_jsonl: 'JSONL Path', cfg_sqlite: 'SQLite Path', cfg_remote_name: 'Git Remote Name', cfg_remote_url: 'Git Remote URL', cfg_branch: 'Git Branch', btn_save: 'Save Configuration',
|
|
159
191
|
mem_recent: 'Recent Memories', mem_hint: 'Click an ID to open full content', mem_content: 'Memory Content',
|
|
160
192
|
th_id: 'ID', th_layer: 'Layer', th_kind: 'Kind', th_summary: 'Summary', th_updated: 'Updated At',
|
|
193
|
+
project_title: 'Project Integration', project_path: 'Project Path', project_id: 'Project ID',
|
|
194
|
+
btn_browse_project: 'Browse Directory', btn_use_cwd: 'Use Server CWD',
|
|
195
|
+
browser_title: 'Directory Browser', btn_browser_up: 'Up', btn_browser_select: 'Select This Directory', btn_browser_close: 'Close',
|
|
196
|
+
btn_project_attach: 'Attach Project + Install Agent Rules', btn_project_detach: 'Detach Project',
|
|
197
|
+
project_hint: 'Attach will create .omnimem files and inject managed memory protocol blocks into AGENTS.md / CLAUDE.md / .cursorrules.',
|
|
161
198
|
cfg_saved: 'Configuration saved', cfg_failed: 'Save failed',
|
|
199
|
+
project_attach_ok: 'Project attached', project_detach_ok: 'Project detached', project_failed: 'Project action failed',
|
|
162
200
|
init_ok: 'Config state: initialized', init_hint_ok: 'Daemon runs quasi-realtime sync in background (can be disabled).',
|
|
163
201
|
init_missing: 'Config state: not initialized (save configuration first)', init_hint_missing: 'Daemon is disabled until configuration is initialized.',
|
|
164
202
|
daemon_state: (d) => `Daemon: ${d.running ? 'running' : 'stopped'}, enabled=${d.enabled}, initialized=${d.initialized}`
|
|
@@ -272,6 +310,7 @@ HTML_PAGE = """<!doctype html>
|
|
|
272
310
|
let currentLang = safeGetLang();
|
|
273
311
|
if (!I18N[currentLang]) currentLang = 'en';
|
|
274
312
|
let daemonCache = { running:false, enabled:false, initialized:false };
|
|
313
|
+
let browserPath = '';
|
|
275
314
|
|
|
276
315
|
function t(key) {
|
|
277
316
|
const dict = I18N[currentLang] || I18N.en;
|
|
@@ -363,6 +402,47 @@ HTML_PAGE = """<!doctype html>
|
|
|
363
402
|
await loadDaemon();
|
|
364
403
|
}
|
|
365
404
|
|
|
405
|
+
async function attachProject() {
|
|
406
|
+
const project_path = document.getElementById('projectPath').value.trim();
|
|
407
|
+
const project_id = document.getElementById('projectId').value.trim();
|
|
408
|
+
const out = document.getElementById('projectOut');
|
|
409
|
+
const d = await jpost('/api/project/attach', {project_path, project_id});
|
|
410
|
+
out.textContent = JSON.stringify(d, null, 2);
|
|
411
|
+
document.getElementById('status').innerHTML = d.ok ? `<span class=\"ok\">${t('project_attach_ok')}</span>` : `<span class=\"err\">${t('project_failed')}</span>`;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
async function detachProject() {
|
|
415
|
+
const project_path = document.getElementById('projectPath').value.trim();
|
|
416
|
+
const out = document.getElementById('projectOut');
|
|
417
|
+
const d = await jpost('/api/project/detach', {project_path});
|
|
418
|
+
out.textContent = JSON.stringify(d, null, 2);
|
|
419
|
+
document.getElementById('status').innerHTML = d.ok ? `<span class=\"ok\">${t('project_detach_ok')}</span>` : `<span class=\"err\">${t('project_failed')}</span>`;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function escHtml(v) {
|
|
423
|
+
return String(v).replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('\"', '"');
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
async function listDirs(path) {
|
|
427
|
+
const d = await jget('/api/fs/list?path=' + encodeURIComponent(path || ''));
|
|
428
|
+
if (!d.ok) {
|
|
429
|
+
document.getElementById('browserList').innerHTML = `<span class=\"err\">${escHtml(d.error || 'list failed')}</span>`;
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
browserPath = d.path || '';
|
|
433
|
+
document.getElementById('browserPath').textContent = browserPath;
|
|
434
|
+
const rows = (d.items || [])
|
|
435
|
+
.map(x => `<div><a href=\"#\" data-path=\"${escHtml(x.path)}\">${escHtml(x.name)}/</a></div>`)
|
|
436
|
+
.join('');
|
|
437
|
+
document.getElementById('browserList').innerHTML = rows || '<span class=\"small\">(empty)</span>';
|
|
438
|
+
document.querySelectorAll('#browserList a').forEach(a => {
|
|
439
|
+
a.onclick = (e) => {
|
|
440
|
+
e.preventDefault();
|
|
441
|
+
listDirs(a.dataset.path || '');
|
|
442
|
+
};
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
|
|
366
446
|
function bindTabs() {
|
|
367
447
|
const btns = document.querySelectorAll('.tab-btn');
|
|
368
448
|
btns.forEach(btn => {
|
|
@@ -389,6 +469,41 @@ HTML_PAGE = """<!doctype html>
|
|
|
389
469
|
document.getElementById('btnSyncPull').onclick = () => runSync('github-pull');
|
|
390
470
|
document.getElementById('btnDaemonOn').onclick = () => toggleDaemon(true);
|
|
391
471
|
document.getElementById('btnDaemonOff').onclick = () => toggleDaemon(false);
|
|
472
|
+
document.getElementById('btnProjectAttach').onclick = () => attachProject();
|
|
473
|
+
document.getElementById('btnProjectDetach').onclick = () => detachProject();
|
|
474
|
+
document.getElementById('btnBrowseProject').onclick = async () => {
|
|
475
|
+
document.getElementById('browserPanel').style.display = 'block';
|
|
476
|
+
await listDirs(document.getElementById('projectPath').value.trim() || '');
|
|
477
|
+
};
|
|
478
|
+
document.getElementById('btnBrowserUp').onclick = async () => {
|
|
479
|
+
if (!browserPath) return;
|
|
480
|
+
const p = browserPath.replace(/\/+$/, '');
|
|
481
|
+
const i = p.lastIndexOf('/');
|
|
482
|
+
const up = i > 0 ? p.slice(0, i) : '/';
|
|
483
|
+
await listDirs(up);
|
|
484
|
+
};
|
|
485
|
+
document.getElementById('btnBrowserSelect').onclick = () => {
|
|
486
|
+
document.getElementById('projectPath').value = browserPath;
|
|
487
|
+
const pid = document.getElementById('projectId');
|
|
488
|
+
if (!pid.value.trim() && browserPath) {
|
|
489
|
+
const s = browserPath.replace(/\/+$/, '').split('/');
|
|
490
|
+
pid.value = s[s.length - 1] || 'project';
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
document.getElementById('btnBrowserClose').onclick = () => {
|
|
494
|
+
document.getElementById('browserPanel').style.display = 'none';
|
|
495
|
+
};
|
|
496
|
+
document.getElementById('btnUseCwd').onclick = async () => {
|
|
497
|
+
const d = await jget('/api/fs/cwd');
|
|
498
|
+
if (d.ok) {
|
|
499
|
+
document.getElementById('projectPath').value = d.cwd;
|
|
500
|
+
const pid = document.getElementById('projectId');
|
|
501
|
+
if (!pid.value.trim()) {
|
|
502
|
+
const s = d.cwd.replace(/\/+$/, '').split('/');
|
|
503
|
+
pid.value = s[s.length - 1] || 'project';
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
};
|
|
392
507
|
}
|
|
393
508
|
|
|
394
509
|
window.addEventListener('error', (e) => {
|
|
@@ -425,6 +540,137 @@ def _cfg_to_ui(cfg: dict[str, Any], cfg_path: Path) -> dict[str, Any]:
|
|
|
425
540
|
}
|
|
426
541
|
|
|
427
542
|
|
|
543
|
+
def _upsert_managed_block(path: Path, block: str) -> None:
|
|
544
|
+
start = "<!-- OMNIMEM:START -->"
|
|
545
|
+
end = "<!-- OMNIMEM:END -->"
|
|
546
|
+
managed = f"{start}\n{block.rstrip()}\n{end}\n"
|
|
547
|
+
if path.exists():
|
|
548
|
+
old = path.read_text(encoding="utf-8")
|
|
549
|
+
if start in old and end in old:
|
|
550
|
+
left = old.split(start, 1)[0].rstrip()
|
|
551
|
+
right = old.split(end, 1)[1].lstrip()
|
|
552
|
+
new_text = f"{left}\n\n{managed}"
|
|
553
|
+
if right:
|
|
554
|
+
new_text += f"\n{right}"
|
|
555
|
+
path.write_text(new_text, encoding="utf-8")
|
|
556
|
+
return
|
|
557
|
+
sep = "\n\n" if old and not old.endswith("\n\n") else ""
|
|
558
|
+
path.write_text(old + sep + managed, encoding="utf-8")
|
|
559
|
+
return
|
|
560
|
+
path.write_text(managed, encoding="utf-8")
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
def _agent_protocol_block(project_id: str) -> str:
|
|
564
|
+
return (
|
|
565
|
+
"# OmniMem Memory Protocol\n"
|
|
566
|
+
"\n"
|
|
567
|
+
f"- Project ID: `{project_id}`\n"
|
|
568
|
+
"- Session start: run `omnimem brief --project-id <PROJECT_ID> --limit 8` and use it as active context.\n"
|
|
569
|
+
"- During task: when a stable decision/fact appears, run `omnimem write` with concise summary + evidence.\n"
|
|
570
|
+
"- Phase end: run `omnimem checkpoint` with goal/result/next-step/risks.\n"
|
|
571
|
+
"- If confidence is low or info is temporary, store in `instant`/`short`; promote to `long` only when repeated and stable.\n"
|
|
572
|
+
"- Never write raw secrets. Use credential references only (for example `op://...` or `env://...`).\n"
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
def _attach_project_in_webui(project_path: str, project_id: str, cfg_home: str) -> dict[str, Any]:
|
|
577
|
+
if not project_path:
|
|
578
|
+
return {"ok": False, "error": "project_path is required"}
|
|
579
|
+
project = Path(project_path).expanduser().resolve()
|
|
580
|
+
if not project.exists() or not project.is_dir():
|
|
581
|
+
return {"ok": False, "error": f"project path not found: {project}"}
|
|
582
|
+
if not project_id:
|
|
583
|
+
project_id = project.name
|
|
584
|
+
|
|
585
|
+
repo_root = Path(__file__).resolve().parent.parent
|
|
586
|
+
tpl = repo_root / "templates" / "project-minimal"
|
|
587
|
+
created: list[str] = []
|
|
588
|
+
updated: list[str] = []
|
|
589
|
+
|
|
590
|
+
files = [
|
|
591
|
+
(tpl / ".omnimem.json", project / ".omnimem.json"),
|
|
592
|
+
(tpl / ".omnimem-session.md", project / ".omnimem-session.md"),
|
|
593
|
+
(tpl / ".omnimem-ignore", project / ".omnimem-ignore"),
|
|
594
|
+
]
|
|
595
|
+
for src, dst in files:
|
|
596
|
+
text = src.read_text(encoding="utf-8")
|
|
597
|
+
text = text.replace("replace-with-project-id", project_id)
|
|
598
|
+
text = text.replace("~/.omnimem", cfg_home or "~/.omnimem")
|
|
599
|
+
exists = dst.exists()
|
|
600
|
+
dst.write_text(text, encoding="utf-8")
|
|
601
|
+
(updated if exists else created).append(str(dst))
|
|
602
|
+
|
|
603
|
+
block = _agent_protocol_block(project_id=project_id)
|
|
604
|
+
managed_targets = [
|
|
605
|
+
project / "AGENTS.md",
|
|
606
|
+
project / "CLAUDE.md",
|
|
607
|
+
project / ".cursorrules",
|
|
608
|
+
]
|
|
609
|
+
for fp in managed_targets:
|
|
610
|
+
exists = fp.exists()
|
|
611
|
+
_upsert_managed_block(fp, block)
|
|
612
|
+
(updated if exists else created).append(str(fp))
|
|
613
|
+
|
|
614
|
+
cursor_rule = project / ".cursor" / "rules" / "omnimem.mdc"
|
|
615
|
+
cursor_exists = cursor_rule.exists()
|
|
616
|
+
cursor_rule.parent.mkdir(parents=True, exist_ok=True)
|
|
617
|
+
cursor_rule.write_text(
|
|
618
|
+
(
|
|
619
|
+
"---\n"
|
|
620
|
+
"description: OmniMem project memory protocol\n"
|
|
621
|
+
"alwaysApply: true\n"
|
|
622
|
+
"---\n\n"
|
|
623
|
+
+ block
|
|
624
|
+
),
|
|
625
|
+
encoding="utf-8",
|
|
626
|
+
)
|
|
627
|
+
(updated if cursor_exists else created).append(str(cursor_rule))
|
|
628
|
+
|
|
629
|
+
return {
|
|
630
|
+
"ok": True,
|
|
631
|
+
"project_path": str(project),
|
|
632
|
+
"project_id": project_id,
|
|
633
|
+
"created": created,
|
|
634
|
+
"updated": updated,
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
def _detach_project_in_webui(project_path: str) -> dict[str, Any]:
|
|
639
|
+
if not project_path:
|
|
640
|
+
return {"ok": False, "error": "project_path is required"}
|
|
641
|
+
project = Path(project_path).expanduser().resolve()
|
|
642
|
+
if not project.exists() or not project.is_dir():
|
|
643
|
+
return {"ok": False, "error": f"project path not found: {project}"}
|
|
644
|
+
|
|
645
|
+
removed: list[str] = []
|
|
646
|
+
for name in [
|
|
647
|
+
".omnimem.json",
|
|
648
|
+
".omnimem-session.md",
|
|
649
|
+
".omnimem-ignore",
|
|
650
|
+
".cursorrules",
|
|
651
|
+
"CLAUDE.md",
|
|
652
|
+
"AGENTS.md",
|
|
653
|
+
".cursor/rules/omnimem.mdc",
|
|
654
|
+
]:
|
|
655
|
+
fp = project / name
|
|
656
|
+
if fp.exists():
|
|
657
|
+
txt = fp.read_text(encoding="utf-8", errors="ignore")
|
|
658
|
+
if "<!-- OMNIMEM:START -->" in txt and "<!-- OMNIMEM:END -->" in txt:
|
|
659
|
+
start = txt.index("<!-- OMNIMEM:START -->")
|
|
660
|
+
end = txt.index("<!-- OMNIMEM:END -->") + len("<!-- OMNIMEM:END -->")
|
|
661
|
+
new_txt = (txt[:start] + txt[end:]).strip()
|
|
662
|
+
if new_txt:
|
|
663
|
+
fp.write_text(new_txt + "\n", encoding="utf-8")
|
|
664
|
+
else:
|
|
665
|
+
fp.unlink()
|
|
666
|
+
removed.append(str(fp))
|
|
667
|
+
continue
|
|
668
|
+
if fp.name in {".omnimem.json", ".omnimem-session.md", ".omnimem-ignore", "omnimem.mdc"}:
|
|
669
|
+
fp.unlink()
|
|
670
|
+
removed.append(str(fp))
|
|
671
|
+
return {"ok": True, "project_path": str(project), "removed": removed}
|
|
672
|
+
|
|
673
|
+
|
|
428
674
|
def run_webui(
|
|
429
675
|
*,
|
|
430
676
|
host: str,
|
|
@@ -516,6 +762,40 @@ def run_webui(
|
|
|
516
762
|
self._send_json({"ok": True, **daemon_state})
|
|
517
763
|
return
|
|
518
764
|
|
|
765
|
+
if parsed.path == "/api/fs/cwd":
|
|
766
|
+
self._send_json({"ok": True, "cwd": str(Path.cwd())})
|
|
767
|
+
return
|
|
768
|
+
|
|
769
|
+
if parsed.path == "/api/fs/list":
|
|
770
|
+
q = parse_qs(parsed.query)
|
|
771
|
+
raw_path = q.get("path", [""])[0].strip()
|
|
772
|
+
base = Path(raw_path).expanduser() if raw_path else Path.home()
|
|
773
|
+
try:
|
|
774
|
+
p = base.resolve()
|
|
775
|
+
if not p.exists() or not p.is_dir():
|
|
776
|
+
self._send_json({"ok": False, "error": f"not a directory: {p}"}, 400)
|
|
777
|
+
return
|
|
778
|
+
items = []
|
|
779
|
+
for child in sorted(p.iterdir(), key=lambda x: x.name.lower()):
|
|
780
|
+
if child.is_dir() and not child.name.startswith("."):
|
|
781
|
+
items.append({"name": child.name, "path": str(child)})
|
|
782
|
+
if len(items) >= 200:
|
|
783
|
+
break
|
|
784
|
+
self._send_json({"ok": True, "path": str(p), "items": items})
|
|
785
|
+
except Exception as exc: # pragma: no cover
|
|
786
|
+
self._send_json({"ok": False, "error": str(exc)}, 500)
|
|
787
|
+
return
|
|
788
|
+
|
|
789
|
+
if parsed.path == "/api/project/defaults":
|
|
790
|
+
self._send_json(
|
|
791
|
+
{
|
|
792
|
+
"ok": True,
|
|
793
|
+
"project_path": "",
|
|
794
|
+
"project_id": "",
|
|
795
|
+
}
|
|
796
|
+
)
|
|
797
|
+
return
|
|
798
|
+
|
|
519
799
|
if parsed.path == "/api/memories":
|
|
520
800
|
q = parse_qs(parsed.query)
|
|
521
801
|
limit = int(q.get("limit", ["20"])[0])
|
|
@@ -612,6 +892,26 @@ def run_webui(
|
|
|
612
892
|
)
|
|
613
893
|
return
|
|
614
894
|
|
|
895
|
+
if parsed.path == "/api/project/attach":
|
|
896
|
+
try:
|
|
897
|
+
out = _attach_project_in_webui(
|
|
898
|
+
project_path=str(data.get("project_path", "")).strip(),
|
|
899
|
+
project_id=str(data.get("project_id", "")).strip(),
|
|
900
|
+
cfg_home=str(cfg.get("home", "")).strip(),
|
|
901
|
+
)
|
|
902
|
+
self._send_json(out, 200 if out.get("ok") else 400)
|
|
903
|
+
except Exception as exc: # pragma: no cover
|
|
904
|
+
self._send_json({"ok": False, "error": str(exc)}, 500)
|
|
905
|
+
return
|
|
906
|
+
|
|
907
|
+
if parsed.path == "/api/project/detach":
|
|
908
|
+
try:
|
|
909
|
+
out = _detach_project_in_webui(str(data.get("project_path", "")).strip())
|
|
910
|
+
self._send_json(out, 200 if out.get("ok") else 400)
|
|
911
|
+
except Exception as exc: # pragma: no cover
|
|
912
|
+
self._send_json({"ok": False, "error": str(exc)}, 500)
|
|
913
|
+
return
|
|
914
|
+
|
|
615
915
|
self._send_json({"ok": False, "error": "not found"}, 404)
|
|
616
916
|
|
|
617
917
|
server = ThreadingHTTPServer((host, port), Handler)
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# OmniMem Session Entry
|
|
2
2
|
|
|
3
3
|
- Current phase:
|
|
4
4
|
- Current objective:
|
|
@@ -8,6 +8,6 @@
|
|
|
8
8
|
|
|
9
9
|
## Quick start
|
|
10
10
|
|
|
11
|
-
1. Run `
|
|
11
|
+
1. Run `omnimem brief --project-id <project_id>`
|
|
12
12
|
2. Review top 3 recent checkpoints
|
|
13
13
|
3. Continue task or start a new session
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "0.1.0",
|
|
3
3
|
"project_id": "replace-with-project-id",
|
|
4
|
-
"memory_home": "~/.
|
|
4
|
+
"memory_home": "~/.omnimem",
|
|
5
5
|
"default_tags": ["project:replace-with-project-id"],
|
|
6
6
|
"collect": {
|
|
7
7
|
"enabled": true,
|
|
8
|
-
"respect_ignore_file": ".
|
|
8
|
+
"respect_ignore_file": ".omnimem-ignore"
|
|
9
9
|
}
|
|
10
10
|
}
|