brane 0.0.2 → 0.3.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/AGENTS.md +362 -0
- package/CHANGELOG.md +33 -0
- package/CONTRIBUTING.md +91 -0
- package/DESIGN.md +402 -0
- package/Dockerfile +61 -0
- package/LICENSE +656 -17
- package/README.md +174 -2
- package/SECURITY.md +205 -0
- package/dist/absorb/brane-id.js +11 -0
- package/dist/absorb/chatgpt.js +161 -0
- package/dist/absorb/claude-code.js +504 -0
- package/dist/absorb/index.js +543 -0
- package/dist/absorb/organelle.js +345 -0
- package/dist/absorb/run.js +520 -0
- package/dist/absorb/sources.js +168 -0
- package/dist/absorb/types.js +3 -0
- package/dist/agent-env.js +45 -0
- package/dist/agents.js +1168 -0
- package/dist/claude-live-session.js +124 -0
- package/dist/cli.js +50 -0
- package/dist/codex-tool-log.js +144 -0
- package/dist/commands/absorb.js +291 -0
- package/dist/commands/attach.js +31 -0
- package/dist/commands/certify.js +62 -0
- package/dist/commands/config.js +116 -0
- package/dist/commands/cost.js +126 -0
- package/dist/commands/daemon.js +350 -0
- package/dist/commands/doctor.js +262 -0
- package/dist/commands/fold.js +95 -0
- package/dist/commands/list.js +89 -0
- package/dist/commands/mcp.js +84 -0
- package/dist/commands/meld.js +332 -0
- package/dist/commands/memory.js +215 -0
- package/dist/commands/revive.js +74 -0
- package/dist/commands/run.js +85 -0
- package/dist/commands/spawn.js +1094 -0
- package/dist/commands/token.js +153 -0
- package/dist/copilot-tool-log.js +145 -0
- package/dist/cost/pricing.js +116 -0
- package/dist/cost/reprice.js +136 -0
- package/dist/crush-tool-log.js +293 -0
- package/dist/daemon/agent-scope.js +116 -0
- package/dist/daemon/awaiting.js +54 -0
- package/dist/daemon/cert-manager.js +349 -0
- package/dist/daemon/client.js +262 -0
- package/dist/daemon/gated-routes.js +112 -0
- package/dist/daemon/keep-awake.js +103 -0
- package/dist/daemon/local-socket.js +145 -0
- package/dist/daemon/presence-gate.js +206 -0
- package/dist/daemon/server.js +6349 -0
- package/dist/daemon/signal-source.js +35 -0
- package/dist/daemon/tailscale-rebind.js +58 -0
- package/dist/daemon/token-ring.js +263 -0
- package/dist/daemon/token-routes.js +190 -0
- package/dist/db/events.js +152 -0
- package/dist/db/mentions.js +179 -0
- package/dist/db/schema.js +633 -0
- package/dist/db/tokens.js +583 -0
- package/dist/db/tool-uses.js +647 -0
- package/dist/diagram/index.js +85 -0
- package/dist/diagram/label.js +455 -0
- package/dist/diagram/layout.js +476 -0
- package/dist/diagram/links.js +50 -0
- package/dist/diagram/metrics.js +152 -0
- package/dist/diagram/parse.js +487 -0
- package/dist/diagram/svg.js +389 -0
- package/dist/diagram/types.js +9 -0
- package/dist/export.js +629 -0
- package/dist/files/archive-types.js +2 -0
- package/dist/files/archive.js +182 -0
- package/dist/files/browse.js +327 -0
- package/dist/files/bytes.js +162 -0
- package/dist/files/codecs.js +33 -0
- package/dist/files/find.js +212 -0
- package/dist/files/tar.js +223 -0
- package/dist/files/zip.js +209 -0
- package/dist/folds.js +72 -0
- package/dist/grammars/ebnf.js +92 -0
- package/dist/highlight.js +250 -0
- package/dist/ids.js +24 -0
- package/dist/markdown-diagnostics.js +233 -0
- package/dist/math.js +168 -0
- package/dist/mcp/server.js +886 -0
- package/dist/memory/embedder.js +145 -0
- package/dist/memory/embedding-worker.js +71 -0
- package/dist/memory/embeddings.js +91 -0
- package/dist/memory/index.js +232 -0
- package/dist/memory/storage.js +587 -0
- package/dist/memory/wiki.js +688 -0
- package/dist/memory/wordpiece.js +247 -0
- package/dist/mentions-scan.js +40 -0
- package/dist/presence.js +259 -0
- package/dist/session-affinity.js +185 -0
- package/dist/shared/api-request.js +124 -0
- package/dist/shared/block-glyphs.js +114 -0
- package/dist/shared/diagram-css.js +17 -0
- package/dist/shared/export-selection.js +101 -0
- package/dist/shared/find-in-text.js +110 -0
- package/dist/shared/glow-hues.js +225 -0
- package/dist/shared/hex-dump.js +62 -0
- package/dist/shared/hex-pages.js +52 -0
- package/dist/shared/hit-drum.js +79 -0
- package/dist/shared/known-nids.js +58 -0
- package/dist/shared/list-scroll-keys.js +56 -0
- package/dist/shared/markdown-lists.js +72 -0
- package/dist/shared/markdown-math.js +485 -0
- package/dist/shared/markdown-mentions.js +79 -0
- package/dist/shared/markdown-nids.js +41 -0
- package/dist/shared/markdown-protocols.js +53 -0
- package/dist/shared/markdown-refs.js +123 -0
- package/dist/shared/membrane-invasion.js +342 -0
- package/dist/shared/membrane-motion.js +83 -0
- package/dist/shared/membrane-palette.js +253 -0
- package/dist/shared/membrane-terrain.js +212 -0
- package/dist/shared/message-selection.js +123 -0
- package/dist/shared/mo-glyph.js +57 -0
- package/dist/shared/narrative-format.js +237 -0
- package/dist/shared/narrative-menu.js +82 -0
- package/dist/shared/narrative-sort.js +47 -0
- package/dist/shared/narrative-status.js +52 -0
- package/dist/shared/no-pan.js +85 -0
- package/dist/shared/pane-layout.js +50 -0
- package/dist/shared/payload-inline.js +83 -0
- package/dist/shared/speaker-color.js +61 -0
- package/dist/shared/token-rotation.js +14 -0
- package/dist/shared/view-url.js +197 -0
- package/dist/shared/wiki-links.js +70 -0
- package/dist/shared/wiki-window.js +4 -0
- package/dist/tailscale.js +55 -0
- package/dist/test/absorb-claude.test.js +892 -0
- package/dist/test/agent-scope.test.js +193 -0
- package/dist/test/agents.test.js +55 -0
- package/dist/test/api-request.test.js +122 -0
- package/dist/test/awaiting-glow.test.js +54 -0
- package/dist/test/awaiting.test.js +122 -0
- package/dist/test/bind-token.test.js +88 -0
- package/dist/test/block-glyphs.test.js +68 -0
- package/dist/test/cert-manager.test.js +262 -0
- package/dist/test/claude-live-session.test.js +110 -0
- package/dist/test/codex-tool-log.test.js +568 -0
- package/dist/test/config.test.js +71 -0
- package/dist/test/copilot-tool-log.test.js +93 -0
- package/dist/test/cors-preflight.test.js +49 -0
- package/dist/test/cost-linger.test.js +31 -0
- package/dist/test/cost-pricing.test.js +72 -0
- package/dist/test/cost-reprice.test.js +139 -0
- package/dist/test/cost-sessions.test.js +301 -0
- package/dist/test/crush-tool-log.test.js +289 -0
- package/dist/test/daemon-client.test.js +109 -0
- package/dist/test/daemon-socket.test.js +293 -0
- package/dist/test/diagram-arrows.test.js +205 -0
- package/dist/test/diagram-export.test.js +210 -0
- package/dist/test/diagram-labels.test.js +313 -0
- package/dist/test/diagram-parse.test.js +191 -0
- package/dist/test/diagram-render.test.js +175 -0
- package/dist/test/diagram-review.test.js +288 -0
- package/dist/test/diagram-self-loop-labels.test.js +303 -0
- package/dist/test/embedder.test.js +84 -0
- package/dist/test/events.test.js +123 -0
- package/dist/test/export-selection.test.js +102 -0
- package/dist/test/export.test.js +505 -0
- package/dist/test/files-browse.test.js +393 -0
- package/dist/test/files-find.test.js +272 -0
- package/dist/test/find-in-text.test.js +86 -0
- package/dist/test/first-paint-viewport.test.js +59 -0
- package/dist/test/fixtures/embedding-golden.js +23 -0
- package/dist/test/fixtures/wordpiece-golden.js +167 -0
- package/dist/test/glow-hues.test.js +202 -0
- package/dist/test/harness-cost.test.js +423 -0
- package/dist/test/helpers.js +21 -0
- package/dist/test/hex-pages.test.js +68 -0
- package/dist/test/highlight.test.js +69 -0
- package/dist/test/hit-drum.test.js +71 -0
- package/dist/test/hook-config.test.js +262 -0
- package/dist/test/json-gzip.test.js +70 -0
- package/dist/test/key-routing.test.js +58 -0
- package/dist/test/known-nids.test.js +106 -0
- package/dist/test/link-preview.test.js +67 -0
- package/dist/test/list-scroll-keys.test.js +66 -0
- package/dist/test/listen-own-words.test.js +147 -0
- package/dist/test/listen-timeout.test.js +33 -0
- package/dist/test/markdown-diagnostics.test.js +121 -0
- package/dist/test/markdown-lists.test.js +182 -0
- package/dist/test/markdown-math.test.js +256 -0
- package/dist/test/markdown-nids.test.js +146 -0
- package/dist/test/markdown-protocols.test.js +139 -0
- package/dist/test/mcp-bridge-cancel.test.js +98 -0
- package/dist/test/mcp-bridge-reconnect.test.js +121 -0
- package/dist/test/mcp-narrative.test.js +193 -0
- package/dist/test/mcp.test.js +548 -0
- package/dist/test/meld.test.js +85 -0
- package/dist/test/membrane-invasion.test.js +482 -0
- package/dist/test/membrane-motion.test.js +101 -0
- package/dist/test/membrane-palette.test.js +166 -0
- package/dist/test/membrane-terrain.test.js +170 -0
- package/dist/test/memory-log.test.js +202 -0
- package/dist/test/mentions-e2e.test.js +261 -0
- package/dist/test/mentions-ledger.test.js +265 -0
- package/dist/test/mentions-listen.test.js +265 -0
- package/dist/test/mentions.test.js +238 -0
- package/dist/test/message-selection.test.js +114 -0
- package/dist/test/mo-glyph.test.js +22 -0
- package/dist/test/model-resolution.test.js +166 -0
- package/dist/test/narrate-validate.test.js +77 -0
- package/dist/test/narrate-wait.test.js +160 -0
- package/dist/test/narrative-format.test.js +219 -0
- package/dist/test/narrative-menu.test.js +137 -0
- package/dist/test/narrative-sort.test.js +75 -0
- package/dist/test/no-pan.test.js +60 -0
- package/dist/test/pane-layout.test.js +153 -0
- package/dist/test/paths.test.js +37 -0
- package/dist/test/payload-inline.test.js +91 -0
- package/dist/test/precache-fonts.test.js +72 -0
- package/dist/test/presence-gate.test.js +440 -0
- package/dist/test/presence.test.js +160 -0
- package/dist/test/read-events.test.js +220 -0
- package/dist/test/remote-meld.test.js +115 -0
- package/dist/test/revive-cli.test.js +93 -0
- package/dist/test/search-floor.test.js +206 -0
- package/dist/test/search-fusion.test.js +168 -0
- package/dist/test/search.test.js +205 -0
- package/dist/test/security.test.js +48 -0
- package/dist/test/selection-wiring.test.js +61 -0
- package/dist/test/session-affinity.test.js +295 -0
- package/dist/test/signal-source.test.js +32 -0
- package/dist/test/socket-account.test.js +268 -0
- package/dist/test/spawn-toml.test.js +72 -0
- package/dist/test/speaker-color.test.js +90 -0
- package/dist/test/tailscale-rebind.test.js +79 -0
- package/dist/test/terminal-cursor.test.js +61 -0
- package/dist/test/terminal-resync.test.js +23 -0
- package/dist/test/thin-cli.test.js +382 -0
- package/dist/test/token-bootstrap.test.js +272 -0
- package/dist/test/token-devices.test.js +587 -0
- package/dist/test/token-lapse.test.js +94 -0
- package/dist/test/token-ring.test.js +188 -0
- package/dist/test/token-rotate-cli.test.js +58 -0
- package/dist/test/token-routes.test.js +95 -0
- package/dist/test/tool-uses.test.js +1006 -0
- package/dist/test/usage-ledger.test.js +126 -0
- package/dist/test/view-url.test.js +581 -0
- package/dist/test/wiki-links.test.js +57 -0
- package/dist/test/wiki-sources.test.js +85 -0
- package/dist/test/wiki-window.test.js +31 -0
- package/dist/test/wiki.test.js +399 -0
- package/dist/test/wordpiece.test.js +68 -0
- package/dist/tls.js +148 -0
- package/dist/tmux.js +202 -0
- package/dist/user-agent.js +46 -0
- package/docker-entrypoint.sh +141 -0
- package/docs/README.md +3 -0
- package/docs/absorb.md +231 -0
- package/docs/cost-ledger.md +125 -0
- package/docs/daemon-api.md +189 -0
- package/docs/diagrams.md +163 -0
- package/docs/doctor.md +36 -0
- package/docs/export-scope.md +69 -0
- package/docs/files-view.md +133 -0
- package/docs/link-previews.md +38 -0
- package/docs/math.md +32 -0
- package/docs/mcp.md +69 -0
- package/docs/memory-search.md +75 -0
- package/docs/mentions.md +101 -0
- package/docs/multi-brane.md +14 -0
- package/docs/passkeys.md +165 -0
- package/docs/presence.md +202 -0
- package/docs/releasing.md +53 -0
- package/docs/rendering-warnings.md +22 -0
- package/docs/request-layer.md +72 -0
- package/docs/selection-store.md +50 -0
- package/docs/session-affinity.md +61 -0
- package/docs/terminal-mirroring.md +211 -0
- package/docs/token-rotation.md +413 -0
- package/docs/view-urls.md +114 -0
- package/docs/web-app.md +23 -0
- package/docs/wiki.md +43 -0
- package/expo/dist/_expo/static/js/web/entry-e56efc1291dca7258ea00b8108b033a4.js +1097 -0
- package/expo/dist/apple-touch-icon.png +0 -0
- package/expo/dist/favicon.svg +3 -0
- package/expo/dist/index.html +177 -0
- package/expo/dist/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- package/expo/dist/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- package/expo/dist/katex/katex.min.css +1 -0
- package/expo/dist/manifest.json +16 -0
- package/expo/dist/metadata.json +1 -0
- package/expo/dist/og/membrane.v1.png +0 -0
- package/expo/dist/pdf.min.mjs +28 -0
- package/expo/dist/pdf.worker.min.mjs +28 -0
- package/expo/dist/sw.js +154 -0
- package/package.json +81 -23
- package/protocols/LIVE_loop.md +407 -0
- package/protocols/bebrief.md +41 -0
- package/protocols/digest.md +231 -0
- package/protocols/fly.md +266 -0
- package/protocols/idle.md +81 -0
- package/protocols/keeper.md +829 -0
- package/protocols/markdown.md +80 -0
- package/protocols/memory.md +419 -0
- package/protocols/mentions.md +93 -0
- package/protocols/payloads.md +53 -0
- package/protocols/prelude.md +91 -0
- package/protocols/ramify.md +105 -0
- package/protocols/review.md +356 -0
- package/protocols/rrr.md +232 -0
- package/protocols/scribe.md +429 -0
- package/protocols/summarize.md +203 -0
- package/protocols/twin.md +174 -0
- package/protocols/wiki.md +438 -0
- package/protocols/worker.md +38 -0
- package/wiki/shared/append-only-event-log.md +148 -0
- package/wiki/shared/index.md +48 -0
- package/wiki/shared/owning-your-narratives.md +161 -0
- package/wiki/shared/premature-ontologies.md +435 -0
- package/wiki/shared/sedimentary-superintelligence.md +128 -0
- package/wiki/shared/sequestering-the-narrative.md +143 -0
- package/wiki/shared/why-wikis-work.md +216 -0
- package/.npmignore +0 -2
- package/.travis.yml +0 -5
- package/index.js +0 -8
- package/index.js~ +0 -12
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/** Organelle absorb — imports narratives from organelle's search.db + niche filesystem */
|
|
2
|
+
import { randomBase36 } from "../ids.js";
|
|
3
|
+
import { copyFileSync, existsSync, readdirSync, readFileSync, statSync, } from "node:fs";
|
|
4
|
+
import { join, extname } from "node:path";
|
|
5
|
+
import BetterSqlite3 from "better-sqlite3";
|
|
6
|
+
import { getPayloadsDir } from "../db/schema.js";
|
|
7
|
+
import { spawnedContent } from "../shared/narrative-format.js";
|
|
8
|
+
/**
|
|
9
|
+
* Default search.db location. Assumes a single organelle installation
|
|
10
|
+
* per machine at ~/.organelle/ (the only layout organelle ever used).
|
|
11
|
+
*/
|
|
12
|
+
const SEARCH_DB_PATH = join(process.env.HOME, ".organelle", "index", "search.db");
|
|
13
|
+
/** Find organelle search.db, returns path or undefined */
|
|
14
|
+
export function findSearchDb() {
|
|
15
|
+
return existsSync(SEARCH_DB_PATH) ? SEARCH_DB_PATH : undefined;
|
|
16
|
+
}
|
|
17
|
+
/** Scan a niche's .organelle/narratives/ for narrative directories */
|
|
18
|
+
function scanNicheNarratives(nichePath) {
|
|
19
|
+
const narrativesDir = join(nichePath, ".organelle", "narratives");
|
|
20
|
+
if (!existsSync(narrativesDir))
|
|
21
|
+
return [];
|
|
22
|
+
return readdirSync(narrativesDir).filter((name) => {
|
|
23
|
+
if (name.startsWith("."))
|
|
24
|
+
return false;
|
|
25
|
+
try {
|
|
26
|
+
return statSync(join(narrativesDir, name)).isDirectory();
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/** Read meta.json for a narrative */
|
|
34
|
+
function readNarrativeMeta(nichePath, nid) {
|
|
35
|
+
const metaPath = join(nichePath, ".organelle", "narratives", nid, "meta.json");
|
|
36
|
+
if (!existsSync(metaPath))
|
|
37
|
+
return undefined;
|
|
38
|
+
try {
|
|
39
|
+
return JSON.parse(readFileSync(metaPath, "utf-8"));
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Map organelle event_type → brane event type */
|
|
46
|
+
function mapEventType(eventType, sender, knownNarrativeIds) {
|
|
47
|
+
switch (eventType) {
|
|
48
|
+
case "signal_received":
|
|
49
|
+
// Agent-to-agent signals: sender is a known narrative ID
|
|
50
|
+
if (sender && knownNarrativeIds.has(sender))
|
|
51
|
+
return "agent_signal";
|
|
52
|
+
return "human_signal";
|
|
53
|
+
case "narration":
|
|
54
|
+
return "narration";
|
|
55
|
+
case "started":
|
|
56
|
+
return "started";
|
|
57
|
+
case "stopped":
|
|
58
|
+
return "stopped";
|
|
59
|
+
default:
|
|
60
|
+
return "narration";
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** Event types worth importing (skip terminal_frame, restarted) */
|
|
64
|
+
const IMPORTABLE_TYPES = new Set([
|
|
65
|
+
"narration",
|
|
66
|
+
"signal_received",
|
|
67
|
+
"started",
|
|
68
|
+
"stopped",
|
|
69
|
+
]);
|
|
70
|
+
/** Utility agent types to skip */
|
|
71
|
+
const UTILITY_ROLES = new Set(["utility"]);
|
|
72
|
+
/** Describe a niche for display before import */
|
|
73
|
+
export function describeOrganelleNiche(nichePath) {
|
|
74
|
+
const searchDbPath = findSearchDb();
|
|
75
|
+
const narrativeIds = scanNicheNarratives(nichePath);
|
|
76
|
+
const agentTypes = {};
|
|
77
|
+
let narrativesWithEvents = 0;
|
|
78
|
+
let totalEvents = 0;
|
|
79
|
+
let skippedUtility = 0;
|
|
80
|
+
if (searchDbPath) {
|
|
81
|
+
const orgDb = new BetterSqlite3(searchDbPath, { readonly: true });
|
|
82
|
+
const countEvents = orgDb.prepare("SELECT COUNT(*) as cnt FROM events WHERE narrative_id = ? AND event_type IN ('narration', 'signal_received', 'started', 'stopped')");
|
|
83
|
+
for (const nid of narrativeIds) {
|
|
84
|
+
const meta = readNarrativeMeta(nichePath, nid);
|
|
85
|
+
// Skip utility narratives
|
|
86
|
+
if (meta && UTILITY_ROLES.has(meta.role)) {
|
|
87
|
+
skippedUtility++;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const { cnt } = countEvents.get(nid);
|
|
91
|
+
if (cnt > 0) {
|
|
92
|
+
narrativesWithEvents++;
|
|
93
|
+
totalEvents += cnt;
|
|
94
|
+
const type = meta?.agent_type || nid.replace(/-[a-f0-9]+$/, "");
|
|
95
|
+
agentTypes[type] = (agentTypes[type] || 0) + 1;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
orgDb.close();
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
nichePath,
|
|
102
|
+
narrativeCount: narrativeIds.length - skippedUtility,
|
|
103
|
+
narrativesWithEvents,
|
|
104
|
+
agentTypes,
|
|
105
|
+
searchDbPath,
|
|
106
|
+
totalEvents,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/** Read all niches from ~/.organelle/niches.json (single installation assumed) */
|
|
110
|
+
export function readNichesRegistry() {
|
|
111
|
+
const nichesPath = join(process.env.HOME, ".organelle", "niches.json");
|
|
112
|
+
if (!existsSync(nichesPath))
|
|
113
|
+
return {};
|
|
114
|
+
try {
|
|
115
|
+
const data = JSON.parse(readFileSync(nichesPath, "utf-8"));
|
|
116
|
+
return data.niches || {};
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return {};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** Copy attachment files from organelle receptor to brane payloads */
|
|
123
|
+
function copyAttachments(nichePath, orgNid, evt, braneNid, seq, summary, dryRun) {
|
|
124
|
+
if (!evt.extra)
|
|
125
|
+
return undefined;
|
|
126
|
+
let extra;
|
|
127
|
+
try {
|
|
128
|
+
extra = JSON.parse(evt.extra);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
if (!extra.attachments || extra.attachments.length === 0)
|
|
134
|
+
return undefined;
|
|
135
|
+
const narrativeDir = join(nichePath, ".organelle", "narratives", orgNid);
|
|
136
|
+
const payloadPaths = [];
|
|
137
|
+
for (let i = 0; i < extra.attachments.length; i++) {
|
|
138
|
+
const attachName = extra.attachments[i];
|
|
139
|
+
// Attachments may be in receptor/ (old format) or attachments/ (new format)
|
|
140
|
+
// The attachName itself may include the subdirectory prefix (e.g. "attachments/...")
|
|
141
|
+
const candidates = [
|
|
142
|
+
join(narrativeDir, "receptor", attachName),
|
|
143
|
+
join(narrativeDir, attachName),
|
|
144
|
+
];
|
|
145
|
+
const srcPath = candidates.find((p) => existsSync(p));
|
|
146
|
+
if (!srcPath) {
|
|
147
|
+
summary.unresolvedAssets++;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
const size = statSync(srcPath).size;
|
|
152
|
+
summary.assets++;
|
|
153
|
+
summary.assetsBytes += size;
|
|
154
|
+
if (!dryRun) {
|
|
155
|
+
const dir = getPayloadsDir(braneNid);
|
|
156
|
+
const ext = extname(srcPath) || ".bin";
|
|
157
|
+
const storedName = `${evt.timestamp_ms}_${seq}_${i}${ext}`;
|
|
158
|
+
copyFileSync(srcPath, join(dir, storedName));
|
|
159
|
+
payloadPaths.push(`${braneNid}/${storedName}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
summary.unresolvedAssets++;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return payloadPaths.length > 0 ? payloadPaths : undefined;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Absorb organelle narratives from one or more niche directories.
|
|
170
|
+
*
|
|
171
|
+
* Reads events from ~/.organelle/index/search.db, metadata from
|
|
172
|
+
* {niche}/.organelle/narratives/{nid}/meta.json, and copies
|
|
173
|
+
* attachments from receptor directories.
|
|
174
|
+
*/
|
|
175
|
+
export async function absorbOrganelle(db, niches, braneId, identity, onProgress, dryRun) {
|
|
176
|
+
const summary = {
|
|
177
|
+
provider: "organelle",
|
|
178
|
+
conversations: 0,
|
|
179
|
+
messages: 0,
|
|
180
|
+
oldest: null,
|
|
181
|
+
newest: null,
|
|
182
|
+
models: {},
|
|
183
|
+
skipped: 0,
|
|
184
|
+
appended: 0,
|
|
185
|
+
assets: 0,
|
|
186
|
+
assetsBytes: 0,
|
|
187
|
+
unresolvedAssets: 0,
|
|
188
|
+
};
|
|
189
|
+
const searchDbPath = findSearchDb();
|
|
190
|
+
if (!searchDbPath) {
|
|
191
|
+
throw new Error("Cannot find organelle search database at ~/.organelle/index/search.db");
|
|
192
|
+
}
|
|
193
|
+
const organelleDb = new BetterSqlite3(searchDbPath, { readonly: true });
|
|
194
|
+
// Prepared statements for brane DB
|
|
195
|
+
const insertNarrative = dryRun
|
|
196
|
+
? undefined
|
|
197
|
+
: db.prepare(`INSERT INTO narratives (id, brane_id, fold_path, agent_type, role, created_at, status, title, archived, agent_session_id)
|
|
198
|
+
VALUES (?, ?, ?, ?, ?, ?, 'ended', ?, 1, ?)`);
|
|
199
|
+
const insertEvent = dryRun
|
|
200
|
+
? undefined
|
|
201
|
+
: db.prepare(`INSERT INTO events (narrative_id, seq, time, type, content, content_type, source, re, payloads, meta)
|
|
202
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
203
|
+
// Dedup by agent_session_id (unique across organelle imports)
|
|
204
|
+
const checkExisting = db.prepare(`SELECT id FROM narratives WHERE agent_session_id = ?`);
|
|
205
|
+
const getMaxSeq = db.prepare("SELECT MAX(seq) as max_seq FROM events WHERE narrative_id = ?");
|
|
206
|
+
const getExistingEventCount = db.prepare("SELECT COUNT(*) as cnt FROM events WHERE narrative_id = ?");
|
|
207
|
+
// Query organelle events (excluding terminal_frame and restarted)
|
|
208
|
+
const queryEvents = organelleDb.prepare(`SELECT * FROM events WHERE narrative_id = ?
|
|
209
|
+
AND event_type IN ('narration', 'signal_received', 'started', 'stopped')
|
|
210
|
+
ORDER BY seq ASC`);
|
|
211
|
+
// Build set of all known narrative IDs for agent signal detection
|
|
212
|
+
const allNarrativeIds = new Set(organelleDb
|
|
213
|
+
.prepare("SELECT DISTINCT narrative_id FROM events")
|
|
214
|
+
.all().map((r) => r.narrative_id));
|
|
215
|
+
const source = identity
|
|
216
|
+
? `organelle:${identity.label}`
|
|
217
|
+
: "organelle:operator";
|
|
218
|
+
// Insert a single narrative (transaction-wrapped)
|
|
219
|
+
const insertOne = dryRun
|
|
220
|
+
? undefined
|
|
221
|
+
: db.transaction((orgNid, meta, events, nicheFoldPath, nicheDir) => {
|
|
222
|
+
const uniqueId = randomBase36(8);
|
|
223
|
+
const braneNid = `organelle-${uniqueId}`;
|
|
224
|
+
const agentType = meta?.agent_type || orgNid.replace(/-[a-f0-9]+$/, "");
|
|
225
|
+
const role = "absorbed";
|
|
226
|
+
const createdAt = meta?.started_at
|
|
227
|
+
? new Date(meta.started_at).getTime()
|
|
228
|
+
: events[0]?.timestamp_ms || Date.now();
|
|
229
|
+
const externalId = `organelle:${orgNid}`;
|
|
230
|
+
// Extract title from first narration content (truncated)
|
|
231
|
+
const firstNarration = events.find((e) => e.event_type === "narration" && e.content);
|
|
232
|
+
const title = firstNarration?.content
|
|
233
|
+
? firstNarration.content.slice(0, 100)
|
|
234
|
+
: null;
|
|
235
|
+
insertNarrative.run(braneNid, braneId, nicheFoldPath, agentType, role, createdAt, title, externalId);
|
|
236
|
+
for (let i = 0; i < events.length; i++) {
|
|
237
|
+
const evt = events[i];
|
|
238
|
+
const seq = i + 1;
|
|
239
|
+
const type = mapEventType(evt.event_type, evt.sender, allNarrativeIds);
|
|
240
|
+
const msgSource = evt.event_type === "signal_received"
|
|
241
|
+
? evt.sender || source
|
|
242
|
+
: evt.speaker || orgNid;
|
|
243
|
+
// Build content for started/stopped from extra
|
|
244
|
+
let content = evt.content;
|
|
245
|
+
if (evt.event_type === "started" && !content && evt.extra) {
|
|
246
|
+
try {
|
|
247
|
+
const ex = JSON.parse(evt.extra);
|
|
248
|
+
content = spawnedContent(ex.agent_type || agentType, ex.role || role);
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
content = spawnedContent(agentType, role);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const payloads = copyAttachments(nicheDir, orgNid, evt, braneNid, seq, summary, false);
|
|
255
|
+
insertEvent.run(braneNid, seq, evt.timestamp_ms, type, content, null, // content_type
|
|
256
|
+
msgSource, null, // re
|
|
257
|
+
payloads ? JSON.stringify(payloads) : null, null);
|
|
258
|
+
}
|
|
259
|
+
return braneNid;
|
|
260
|
+
});
|
|
261
|
+
let processed = 0;
|
|
262
|
+
for (const { nichePath, foldPath } of niches) {
|
|
263
|
+
const narrativeIds = scanNicheNarratives(nichePath);
|
|
264
|
+
for (const orgNid of narrativeIds) {
|
|
265
|
+
// Every narrative's work below is synchronous SQLite and file copies.
|
|
266
|
+
// Yield between them so the daemon that runs this keeps answering —
|
|
267
|
+
// and so the progress stream actually reaches the client mid-run.
|
|
268
|
+
await new Promise((r) => setImmediate(r));
|
|
269
|
+
const meta = readNarrativeMeta(nichePath, orgNid);
|
|
270
|
+
// Skip utility narratives (caffeinate, htop, lazygit, zsh)
|
|
271
|
+
if (meta && UTILITY_ROLES.has(meta.role)) {
|
|
272
|
+
processed++;
|
|
273
|
+
onProgress?.(processed, orgNid);
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
const events = queryEvents.all(orgNid);
|
|
277
|
+
// Skip narratives with no importable events
|
|
278
|
+
if (events.length === 0) {
|
|
279
|
+
summary.skipped++;
|
|
280
|
+
processed++;
|
|
281
|
+
onProgress?.(processed, orgNid);
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
// Update summary timestamps
|
|
285
|
+
const firstTime = events[0].timestamp_ms;
|
|
286
|
+
const lastTime = events[events.length - 1].timestamp_ms;
|
|
287
|
+
if (!summary.oldest || firstTime < summary.oldest.time) {
|
|
288
|
+
summary.oldest = { time: firstTime, title: orgNid };
|
|
289
|
+
}
|
|
290
|
+
if (!summary.newest || lastTime > summary.newest.time) {
|
|
291
|
+
summary.newest = { time: lastTime, title: orgNid };
|
|
292
|
+
}
|
|
293
|
+
// Track agent types in models field
|
|
294
|
+
const agentType = meta?.agent_type || orgNid.replace(/-[a-f0-9]+$/, "");
|
|
295
|
+
summary.models[agentType] = (summary.models[agentType] || 0) + 1;
|
|
296
|
+
// Dedup check
|
|
297
|
+
const externalId = `organelle:${orgNid}`;
|
|
298
|
+
const existing = checkExisting.get(externalId);
|
|
299
|
+
if (existing) {
|
|
300
|
+
const { cnt } = getExistingEventCount.get(existing.id);
|
|
301
|
+
if (events.length <= cnt) {
|
|
302
|
+
summary.skipped++;
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
if (!dryRun) {
|
|
306
|
+
// Append new events
|
|
307
|
+
const { max_seq } = getMaxSeq.get(existing.id);
|
|
308
|
+
let nextSeq = max_seq + 1;
|
|
309
|
+
for (let i = cnt; i < events.length; i++) {
|
|
310
|
+
const evt = events[i];
|
|
311
|
+
const type = mapEventType(evt.event_type, evt.sender, allNarrativeIds);
|
|
312
|
+
const msgSource = evt.event_type === "signal_received"
|
|
313
|
+
? evt.sender || source
|
|
314
|
+
: evt.speaker || orgNid;
|
|
315
|
+
const payloads = copyAttachments(nichePath, orgNid, evt, existing.id, nextSeq, summary, false);
|
|
316
|
+
insertEvent.run(existing.id, nextSeq++, evt.timestamp_ms, type, evt.content, null, msgSource, null, payloads ? JSON.stringify(payloads) : null, null);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
summary.appended++;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
// Count content events (narration + signal) for messages total
|
|
324
|
+
const contentEvents = events.filter((e) => e.event_type === "narration" ||
|
|
325
|
+
e.event_type === "signal_received");
|
|
326
|
+
summary.messages += contentEvents.length;
|
|
327
|
+
if (!dryRun) {
|
|
328
|
+
insertOne(orgNid, meta, events, foldPath, nichePath);
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
// Dry-run: count assets
|
|
332
|
+
for (const evt of events) {
|
|
333
|
+
copyAttachments(nichePath, orgNid, evt, "dry-run", 0, summary, true);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
summary.conversations++;
|
|
337
|
+
}
|
|
338
|
+
processed++;
|
|
339
|
+
onProgress?.(processed, orgNid);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
organelleDb.close();
|
|
343
|
+
return summary;
|
|
344
|
+
}
|
|
345
|
+
//# sourceMappingURL=organelle.js.map
|