Product layer on top of the pure engine: a wizard to connect the apps that feed the brain, an encrypted credential vault (Fernet/PBKDF2; app logins never enter brain.db), and 3 working connectors. Connector data flows through the same credential-scrub path as the engine. Atlas Corporation proprietary.
86 lines
2.9 KiB
Python
Executable file
86 lines
2.9 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# SecondBrain — (c) 2026 Atlas Corporation. All Rights Reserved. Proprietary; see LICENSE.
|
|
"""SecondBrain setup wizard — connect the apps that feed your brain.
|
|
|
|
python3 setup.py interactive: pick apps, sign in, test, sync
|
|
python3 setup.py sync re-sync every already-connected app (for cron/timer)
|
|
python3 setup.py list show available connectors
|
|
|
|
App credentials go into the encrypted vault (connectors/vault.py), never into brain.db.
|
|
"""
|
|
import sys, os
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
from connectors import base, vault
|
|
|
|
|
|
def _ask(field):
|
|
import getpass
|
|
label = f" {field.label}" + (f" [{field.default}]" if field.default else "") + ": "
|
|
val = getpass.getpass(label) if field.secret else input(label)
|
|
return (val or "").strip() or field.default
|
|
|
|
|
|
def cmd_list():
|
|
base.load_all()
|
|
print("\nAvailable connectors:")
|
|
for c in base.REGISTRY.values():
|
|
print(f" • {c.name:26} {c.blurb}")
|
|
|
|
|
|
def wizard():
|
|
base.load_all()
|
|
conns = list(base.REGISTRY.values())
|
|
print("\n🧠 SecondBrain — connect your apps\n")
|
|
for i, c in enumerate(conns, 1):
|
|
print(f" {i}. {c.name} — {c.blurb}")
|
|
print(" q. done")
|
|
cfgs = vault.load() if os.path.exists(vault.VAULT) else {}
|
|
while True:
|
|
ch = input("\nConnect which? [number/q] ").strip().lower()
|
|
if ch in ("q", ""):
|
|
break
|
|
try:
|
|
c = conns[int(ch) - 1]
|
|
except Exception:
|
|
print(" ?"); continue
|
|
inst = c()
|
|
cfg = {f.key: _ask(f) for f in inst.fields}
|
|
try:
|
|
print(" testing…", inst.test(cfg))
|
|
except Exception as e:
|
|
print(f" ✗ could not connect: {e}"); continue
|
|
cfgs[c.id] = cfg
|
|
vault.save(cfgs)
|
|
print(f" ✓ {c.name} connected + saved to encrypted vault")
|
|
if input(" sync now? [Y/n] ").strip().lower() in ("", "y"):
|
|
try:
|
|
n = inst.sync(cfg); print(f" … ingested {n} new chunks")
|
|
except Exception as e:
|
|
print(f" sync error: {e}")
|
|
print("\nEmbedding new content (local)…")
|
|
try:
|
|
base._brain().embed(limit=20000)
|
|
except Exception as e:
|
|
print(f" embed skipped: {e}")
|
|
print('Done. Ask your brain: python3 brain.py recall "…" --hybrid\n')
|
|
|
|
|
|
def cmd_sync():
|
|
base.load_all()
|
|
cfgs = vault.load()
|
|
if not cfgs:
|
|
print("no connectors configured — run `python3 setup.py` first"); return
|
|
for cid, cfg in cfgs.items():
|
|
c = base.REGISTRY.get(cid)
|
|
if not c:
|
|
print(f"[{cid}] unknown connector, skipped"); continue
|
|
try:
|
|
n = c().sync(cfg); print(f"[{cid}] +{n} chunks")
|
|
except Exception as e:
|
|
print(f"[{cid}] error: {e}")
|
|
base._brain().embed(limit=50000)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
arg = sys.argv[1] if len(sys.argv) > 1 else ""
|
|
{"sync": cmd_sync, "list": cmd_list}.get(arg, wizard)()
|