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,126 @@
|
|
|
1
|
+
import { before, describe, it } from "node:test";
|
|
2
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import assert from "node:assert/strict";
|
|
5
|
+
import { createTestDb } from "./helpers.js";
|
|
6
|
+
import { recordUsageEntries, recordUsageHighWater, ledgerTotal, sampleNarrativeCostDetailed } from "../daemon/server.js";
|
|
7
|
+
const tok = (n) => ({ input: n, output: n, cacheRead: 0, cacheWrite: 0 });
|
|
8
|
+
function reading(sessionId, sig, entries) {
|
|
9
|
+
return {
|
|
10
|
+
sessionId,
|
|
11
|
+
sig,
|
|
12
|
+
unit: "USD",
|
|
13
|
+
entries: entries.map(([key, amount]) => ({ key, amount, tokens: tok(1) })),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
describe("usage ledger", () => {
|
|
17
|
+
it("sums a narrative's entries, with a token breakdown", () => {
|
|
18
|
+
const db = createTestDb();
|
|
19
|
+
recordUsageEntries(db, "claude-a", "claude", [reading("sess-1", "1", [["claude:m1", 1.5], ["claude:m2", 2.25]])]);
|
|
20
|
+
assert.deepEqual(ledgerTotal(db, "claude-a"), { amount: 3.75, unit: "USD", tokens: tok(2) });
|
|
21
|
+
assert.equal(ledgerTotal(db, "claude-nobody"), null);
|
|
22
|
+
});
|
|
23
|
+
it("credits a fork-copied message to the narrative that saw it first, and never moves it", () => {
|
|
24
|
+
const db = createTestDb();
|
|
25
|
+
// Original session A, then fork B which carries m1 forward and adds m2.
|
|
26
|
+
recordUsageEntries(db, "claude-a", "claude", [reading("sess-a", "1", [["claude:m1", 1]])]);
|
|
27
|
+
recordUsageEntries(db, "claude-b", "claude", [reading("sess-b", "1", [["claude:m1", 1], ["claude:m2", 2]])]);
|
|
28
|
+
assert.equal(ledgerTotal(db, "claude-a")?.amount, 1);
|
|
29
|
+
assert.equal(ledgerTotal(db, "claude-b")?.amount, 2);
|
|
30
|
+
});
|
|
31
|
+
it("survives the original transcript being purged: re-reading only the fork changes nothing", () => {
|
|
32
|
+
const db = createTestDb();
|
|
33
|
+
recordUsageEntries(db, "claude-a", "claude", [
|
|
34
|
+
reading("sess-a", "1", [["claude:m1", 1], ["claude:m2", 2]]),
|
|
35
|
+
reading("sess-b", "1", [["claude:m1", 1], ["claude:m2", 2], ["claude:m3", 4]]),
|
|
36
|
+
]);
|
|
37
|
+
assert.equal(ledgerTotal(db, "claude-a")?.amount, 7);
|
|
38
|
+
// sess-a is gone; sess-b is all the harness can show us now, and it has
|
|
39
|
+
// changed (new sig) — still nothing to add, nothing to lose.
|
|
40
|
+
recordUsageEntries(db, "claude-a", "claude", [
|
|
41
|
+
reading("sess-b", "2", [["claude:m1", 1], ["claude:m2", 2], ["claude:m3", 4]]),
|
|
42
|
+
]);
|
|
43
|
+
assert.equal(ledgerTotal(db, "claude-a")?.amount, 7);
|
|
44
|
+
});
|
|
45
|
+
it("skips a session whose signature is unchanged, and picks up new entries when it changes", () => {
|
|
46
|
+
const db = createTestDb();
|
|
47
|
+
recordUsageEntries(db, "claude-a", "claude", [reading("sess-1", "sig1", [["claude:m1", 1]])]);
|
|
48
|
+
// Same sig, new key: not written (the real reader can't produce this, but
|
|
49
|
+
// it proves the memo short-circuits).
|
|
50
|
+
recordUsageEntries(db, "claude-a", "claude", [reading("sess-1", "sig1", [["claude:m1", 1], ["claude:m2", 5]])]);
|
|
51
|
+
assert.equal(ledgerTotal(db, "claude-a")?.amount, 1);
|
|
52
|
+
recordUsageEntries(db, "claude-a", "claude", [reading("sess-1", "sig2", [["claude:m1", 1], ["claude:m2", 5]])]);
|
|
53
|
+
assert.equal(ledgerTotal(db, "claude-a")?.amount, 6);
|
|
54
|
+
});
|
|
55
|
+
it("keeps the model with the row, and fills it in on a row written without one", () => {
|
|
56
|
+
const db = createTestDb();
|
|
57
|
+
const modelOf = () => db.prepare("SELECT model, amount FROM usage_ledger WHERE key = 'claude:m1'").get();
|
|
58
|
+
recordUsageEntries(db, "claude-a", "claude", [reading("s1", "1", [["claude:m1", 1]])]);
|
|
59
|
+
assert.deepEqual(modelOf(), { model: null, amount: 1 });
|
|
60
|
+
recordUsageEntries(db, "claude-b", "claude", [
|
|
61
|
+
{ sessionId: "s2", sig: "1", unit: "USD", entries: [{ key: "claude:m1", amount: 99, model: "claude-fable-5" }] },
|
|
62
|
+
]);
|
|
63
|
+
// Model filled in; credit (claude-a) and amount untouched.
|
|
64
|
+
assert.deepEqual(modelOf(), { model: "claude-fable-5", amount: 1 });
|
|
65
|
+
assert.equal(ledgerTotal(db, "claude-b"), null);
|
|
66
|
+
});
|
|
67
|
+
it("high-water rows only ever rise", () => {
|
|
68
|
+
const db = createTestDb();
|
|
69
|
+
recordUsageHighWater(db, "codex-a", "codex", "s1", { amount: 100, unit: "TOK", tokens: tok(100) });
|
|
70
|
+
recordUsageHighWater(db, "codex-a", "codex", "s1", { amount: 250, unit: "TOK", tokens: tok(250) });
|
|
71
|
+
recordUsageHighWater(db, "codex-a", "codex", "s1", { amount: 40, unit: "TOK", tokens: tok(40) });
|
|
72
|
+
assert.deepEqual(ledgerTotal(db, "codex-a"), { amount: 250, unit: "TOK", tokens: tok(250) });
|
|
73
|
+
// A second session adds, rather than replaces.
|
|
74
|
+
recordUsageHighWater(db, "codex-a", "codex", "s2", { amount: 10, unit: "TOK" });
|
|
75
|
+
assert.equal(ledgerTotal(db, "codex-a")?.amount, 260);
|
|
76
|
+
});
|
|
77
|
+
it("a high-water row ignores a reading in a different unit", () => {
|
|
78
|
+
const db = createTestDb();
|
|
79
|
+
recordUsageHighWater(db, "x-a", "codex", "s1", { amount: 100, unit: "TOK" });
|
|
80
|
+
recordUsageHighWater(db, "x-a", "codex", "s1", { amount: 999, unit: "USD" });
|
|
81
|
+
assert.deepEqual(ledgerTotal(db, "x-a"), { amount: 100, unit: "TOK" });
|
|
82
|
+
});
|
|
83
|
+
it("never sums across units: the unit with the most rows wins", () => {
|
|
84
|
+
const db = createTestDb();
|
|
85
|
+
recordUsageHighWater(db, "x-a", "copilot", "s1", { amount: 100, unit: "AIC" });
|
|
86
|
+
recordUsageHighWater(db, "x-a", "copilot", "s2", { amount: 5, unit: "AIC" });
|
|
87
|
+
recordUsageHighWater(db, "x-a", "goose", "s3", { amount: 9, unit: "USD" });
|
|
88
|
+
assert.deepEqual(ledgerTotal(db, "x-a"), { amount: 105, unit: "AIC" });
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
// Drive the sampler itself over an adapter that has *both* readUsage and
|
|
92
|
+
// readUsageMany (cline is the only one), through the high-water branch.
|
|
93
|
+
// Cline's store is a brane-owned directory under /tmp keyed by narrative id,
|
|
94
|
+
// so the test can fabricate one for a narrative id nothing else uses.
|
|
95
|
+
describe("sampleNarrativeCostDetailed over a high-water adapter", () => {
|
|
96
|
+
const NID = "cline-ledgertest";
|
|
97
|
+
const store = join("/tmp", `brane-cline-${NID}`, "data", "sessions");
|
|
98
|
+
const writeSession = (id, costs) => {
|
|
99
|
+
mkdirSync(join(store, id), { recursive: true });
|
|
100
|
+
writeFileSync(join(store, id, `${id}.messages.json`), JSON.stringify({ messages: costs.map((cost, i) => ({ id: `${id}-${i}`, metrics: { cost, inputTokens: 1, outputTokens: 1 } })) }));
|
|
101
|
+
};
|
|
102
|
+
before(() => {
|
|
103
|
+
writeSession("1000_aaaaa", [1, 2]); // bound
|
|
104
|
+
writeSession("2000_bbbbb", [4]); // in the store, never captured by brane
|
|
105
|
+
});
|
|
106
|
+
it("prefers readUsageMany, so sessions brane never bound still count, as one narrative-keyed row", () => {
|
|
107
|
+
const db = createTestDb();
|
|
108
|
+
db.prepare(`INSERT INTO narratives (id, brane_id, agent_type, role, created_at, status, fold_path, agent_session_id, session_ids, cost_amount, cost_unit)
|
|
109
|
+
VALUES (?, 'brane-test', 'cline', 'worker', 0, 'active', '/tmp', '1000_aaaaa', '["1000_aaaaa"]', 2.5, 'USD')`).run(NID);
|
|
110
|
+
const dry = sampleNarrativeCostDetailed(db, NID, { dryRun: true });
|
|
111
|
+
assert.equal(dry?.readable, 1);
|
|
112
|
+
assert.equal(dry?.new_amount, 7);
|
|
113
|
+
assert.equal(dry?.after, 7, "dry run projects the column");
|
|
114
|
+
assert.equal(ledgerTotal(db, NID), null, "dry run writes nothing");
|
|
115
|
+
const real = sampleNarrativeCostDetailed(db, NID);
|
|
116
|
+
assert.deepEqual({ before: real?.before, after: real?.after }, { before: 2.5, after: 7 });
|
|
117
|
+
const rows = db.prepare("SELECT key, amount FROM usage_ledger WHERE narrative_id = ?").all(NID);
|
|
118
|
+
assert.deepEqual(rows, [{ key: `session:cline:${NID}`, amount: 7 }]);
|
|
119
|
+
// The harness loses a session: the row, and the card, hold.
|
|
120
|
+
writeSession("2000_bbbbb", []);
|
|
121
|
+
const again = sampleNarrativeCostDetailed(db, NID);
|
|
122
|
+
assert.equal(again?.after, 7);
|
|
123
|
+
assert.equal(ledgerTotal(db, NID)?.amount, 7);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
//# sourceMappingURL=usage-ledger.test.js.map
|