@100xprompt/brain 0.0.0-stage → 0.1.1
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/LICENSE +48 -0
- package/README.md +235 -2
- package/package.json +48 -4
- package/src/adapters/aider/index.ts +8 -0
- package/src/adapters/aider/reader.ts +129 -0
- package/src/adapters/aider/records.ts +220 -0
- package/src/adapters/aider/writer.ts +269 -0
- package/src/adapters/amazon-q-cli/index.ts +8 -0
- package/src/adapters/amazon-q-cli/reader.ts +84 -0
- package/src/adapters/amazon-q-cli/records.ts +191 -0
- package/src/adapters/amazon-q-cli/writer.ts +370 -0
- package/src/adapters/amazon-q-ide/index.ts +9 -0
- package/src/adapters/amazon-q-ide/reader.ts +131 -0
- package/src/adapters/amazon-q-ide/records.ts +141 -0
- package/src/adapters/amazon-q-ide/writer.ts +325 -0
- package/src/adapters/antigravity/index.ts +9 -0
- package/src/adapters/antigravity/proto.ts +194 -0
- package/src/adapters/antigravity/reader.ts +424 -0
- package/src/adapters/antigravity/records.ts +236 -0
- package/src/adapters/antigravity/writer.ts +463 -0
- package/src/adapters/auggie/index.ts +36 -0
- package/src/adapters/claude-code/index.ts +8 -0
- package/src/adapters/claude-code/reader.ts +639 -0
- package/src/adapters/claude-code/records.ts +88 -0
- package/src/adapters/claude-code/writer.ts +329 -0
- package/src/adapters/cline/index.ts +12 -0
- package/src/adapters/cline/reader.ts +432 -0
- package/src/adapters/cline/records.ts +151 -0
- package/src/adapters/cline/vscdb.ts +56 -0
- package/src/adapters/cline/writer.ts +656 -0
- package/src/adapters/cline/xml.ts +177 -0
- package/src/adapters/cline4/index.ts +9 -0
- package/src/adapters/cline4/reader.ts +179 -0
- package/src/adapters/cline4/records.ts +92 -0
- package/src/adapters/cline4/writer.ts +361 -0
- package/src/adapters/codebuff/index.ts +8 -0
- package/src/adapters/codebuff/project.ts +207 -0
- package/src/adapters/codebuff/reader.ts +215 -0
- package/src/adapters/codebuff/records.ts +173 -0
- package/src/adapters/codebuff/writer.ts +383 -0
- package/src/adapters/codex/index.ts +8 -0
- package/src/adapters/codex/native.ts +239 -0
- package/src/adapters/codex/reader.ts +747 -0
- package/src/adapters/codex/records.ts +114 -0
- package/src/adapters/codex/writer.ts +479 -0
- package/src/adapters/continue/index.ts +9 -0
- package/src/adapters/continue/reader.ts +68 -0
- package/src/adapters/continue/records.ts +418 -0
- package/src/adapters/continue/writer.ts +162 -0
- package/src/adapters/copilot-cli/index.ts +9 -0
- package/src/adapters/copilot-cli/reader.ts +186 -0
- package/src/adapters/copilot-cli/records.ts +241 -0
- package/src/adapters/copilot-cli/writer.ts +353 -0
- package/src/adapters/crush/index.ts +8 -0
- package/src/adapters/crush/reader.ts +180 -0
- package/src/adapters/crush/records.ts +169 -0
- package/src/adapters/crush/writer.ts +333 -0
- package/src/adapters/cursor-cli/index.ts +405 -0
- package/src/adapters/cursor-ide/agentkv.ts +95 -0
- package/src/adapters/cursor-ide/index.ts +501 -0
- package/src/adapters/cursor-ide/transcripts.ts +122 -0
- package/src/adapters/cursor-ide/workspaces.ts +119 -0
- package/src/adapters/cursor-ide/writer.ts +170 -0
- package/src/adapters/devin/index.ts +8 -0
- package/src/adapters/devin/reader.ts +305 -0
- package/src/adapters/devin/records.ts +277 -0
- package/src/adapters/devin/writer.ts +523 -0
- package/src/adapters/factory-droid/index.ts +12 -0
- package/src/adapters/factory-droid/reader.ts +184 -0
- package/src/adapters/factory-droid/records.ts +79 -0
- package/src/adapters/factory-droid/writer.ts +350 -0
- package/src/adapters/gemini-cli/exchanges.ts +228 -0
- package/src/adapters/gemini-cli/index.ts +396 -0
- package/src/adapters/gemini-cli/records.ts +521 -0
- package/src/adapters/gemini-cli/writer.ts +354 -0
- package/src/adapters/goose/index.ts +8 -0
- package/src/adapters/goose/reader.ts +138 -0
- package/src/adapters/goose/records.ts +199 -0
- package/src/adapters/goose/writer.ts +340 -0
- package/src/adapters/grok-cli/image.ts +44 -0
- package/src/adapters/grok-cli/index.ts +8 -0
- package/src/adapters/grok-cli/reader.ts +302 -0
- package/src/adapters/grok-cli/records.ts +172 -0
- package/src/adapters/grok-cli/writer.ts +329 -0
- package/src/adapters/hermes/index.ts +8 -0
- package/src/adapters/hermes/reader.ts +249 -0
- package/src/adapters/hermes/records.ts +285 -0
- package/src/adapters/hermes/writer.ts +452 -0
- package/src/adapters/iflow-cli/index.ts +72 -0
- package/src/adapters/iflow-cli/records.ts +215 -0
- package/src/adapters/iflow-cli/writer.ts +204 -0
- package/src/adapters/index.ts +112 -0
- package/src/adapters/kilo-cli/index.ts +21 -0
- package/src/adapters/kilo-code/index.ts +11 -0
- package/src/adapters/kilo-code/writer.ts +92 -0
- package/src/adapters/kimi/index.ts +9 -0
- package/src/adapters/kimi/reader.ts +92 -0
- package/src/adapters/kimi/records.ts +221 -0
- package/src/adapters/kimi/writer.ts +367 -0
- package/src/adapters/kiro-cli/index.ts +8 -0
- package/src/adapters/kiro-cli/reader.ts +87 -0
- package/src/adapters/kiro-cli/records.ts +260 -0
- package/src/adapters/kiro-cli/writer.ts +305 -0
- package/src/adapters/kiro-ide/index.ts +8 -0
- package/src/adapters/kiro-ide/writer.ts +52 -0
- package/src/adapters/letta/index.ts +8 -0
- package/src/adapters/letta/reader.ts +177 -0
- package/src/adapters/letta/records.ts +119 -0
- package/src/adapters/letta/writer.ts +413 -0
- package/src/adapters/mastracode/index.ts +8 -0
- package/src/adapters/mastracode/reader.ts +323 -0
- package/src/adapters/mastracode/records.ts +336 -0
- package/src/adapters/mastracode/writer.ts +385 -0
- package/src/adapters/mistral-vibe/index.ts +9 -0
- package/src/adapters/mistral-vibe/reader.ts +62 -0
- package/src/adapters/mistral-vibe/records.ts +104 -0
- package/src/adapters/mistral-vibe/writer.ts +359 -0
- package/src/adapters/muse/index.ts +10 -0
- package/src/adapters/muse/reader.ts +332 -0
- package/src/adapters/muse/records.ts +104 -0
- package/src/adapters/muse/writer.ts +387 -0
- package/src/adapters/omp/index.ts +13 -0
- package/src/adapters/omp/reader.ts +314 -0
- package/src/adapters/omp/records.ts +153 -0
- package/src/adapters/omp/writer.ts +216 -0
- package/src/adapters/opencode/ids.ts +52 -0
- package/src/adapters/opencode/index.ts +31 -0
- package/src/adapters/opencode/note.ts +8 -0
- package/src/adapters/opencode/reader.ts +452 -0
- package/src/adapters/opencode/tools.ts +174 -0
- package/src/adapters/opencode/v2.ts +367 -0
- package/src/adapters/opencode/writer.ts +379 -0
- package/src/adapters/openhands/index.ts +8 -0
- package/src/adapters/openhands/reader.ts +222 -0
- package/src/adapters/openhands/records.ts +136 -0
- package/src/adapters/openhands/writer.ts +404 -0
- package/src/adapters/pearai/index.ts +10 -0
- package/src/adapters/pi/index.ts +28 -0
- package/src/adapters/pi/reader.ts +261 -0
- package/src/adapters/pi/records.ts +99 -0
- package/src/adapters/pi/writer.ts +362 -0
- package/src/adapters/qoder-cli/index.ts +8 -0
- package/src/adapters/qoder-cli/reader.ts +83 -0
- package/src/adapters/qoder-cli/records.ts +45 -0
- package/src/adapters/qoder-cli/writer.ts +72 -0
- package/src/adapters/qwen-code/index.ts +84 -0
- package/src/adapters/qwen-code/records.ts +194 -0
- package/src/adapters/qwen-code/writer.ts +224 -0
- package/src/adapters/tabnine-cli/index.ts +8 -0
- package/src/adapters/tabnine-cli/reader.ts +106 -0
- package/src/adapters/tabnine-cli/records.ts +33 -0
- package/src/adapters/tabnine-cli/writer.ts +156 -0
- package/src/adapters/types.ts +73 -0
- package/src/adapters/void/index.ts +9 -0
- package/src/adapters/void/reader.ts +48 -0
- package/src/adapters/void/records.ts +285 -0
- package/src/adapters/void/writer.ts +93 -0
- package/src/adapters/vscode-copilot/index.ts +9 -0
- package/src/adapters/vscode-copilot/reader.ts +212 -0
- package/src/adapters/vscode-copilot/records.ts +388 -0
- package/src/adapters/vscode-copilot/shared.ts +68 -0
- package/src/adapters/vscode-copilot/writer.ts +546 -0
- package/src/adapters/zed/index.ts +8 -0
- package/src/adapters/zed/reader.ts +198 -0
- package/src/adapters/zed/records.ts +87 -0
- package/src/adapters/zed/writer.ts +341 -0
- package/src/brief-writers.ts +71 -0
- package/src/brief.ts +238 -0
- package/src/cli.ts +351 -0
- package/src/dashboard/cli.ts +148 -0
- package/src/dashboard/conversions.ts +170 -0
- package/src/dashboard/report.ts +261 -0
- package/src/dashboard/send.ts +213 -0
- package/src/dashboard/state.ts +95 -0
- package/src/fsutil.ts +133 -0
- package/src/gateway/common.ts +232 -0
- package/src/gateway/connect.ts +847 -0
- package/src/gateway/connectors/aider.ts +356 -0
- package/src/gateway/connectors/amazon-q-cli.ts +6 -0
- package/src/gateway/connectors/amazon-q-ide.ts +6 -0
- package/src/gateway/connectors/antigravity.ts +6 -0
- package/src/gateway/connectors/auggie.ts +6 -0
- package/src/gateway/connectors/cline-sdk.ts +85 -0
- package/src/gateway/connectors/cline.ts +34 -0
- package/src/gateway/connectors/codebuff.ts +6 -0
- package/src/gateway/connectors/continue.ts +579 -0
- package/src/gateway/connectors/copilot-cli.ts +138 -0
- package/src/gateway/connectors/crush.ts +313 -0
- package/src/gateway/connectors/cursor-cli.ts +6 -0
- package/src/gateway/connectors/cursor.ts +6 -0
- package/src/gateway/connectors/devin.ts +6 -0
- package/src/gateway/connectors/factory-droid.ts +308 -0
- package/src/gateway/connectors/goose.ts +79 -0
- package/src/gateway/connectors/grok-cli.ts +82 -0
- package/src/gateway/connectors/hermes.ts +230 -0
- package/src/gateway/connectors/iflow-cli.ts +50 -0
- package/src/gateway/connectors/index.ts +86 -0
- package/src/gateway/connectors/kilo-cli.ts +434 -0
- package/src/gateway/connectors/kilo-code.ts +32 -0
- package/src/gateway/connectors/kimi-code.ts +241 -0
- package/src/gateway/connectors/kiro-cli.ts +6 -0
- package/src/gateway/connectors/kiro-ide.ts +6 -0
- package/src/gateway/connectors/letta-code.ts +170 -0
- package/src/gateway/connectors/mastracode.ts +91 -0
- package/src/gateway/connectors/mistral-vibe.ts +495 -0
- package/src/gateway/connectors/muse.ts +27 -0
- package/src/gateway/connectors/omp.ts +279 -0
- package/src/gateway/connectors/openhands.ts +296 -0
- package/src/gateway/connectors/pearai.ts +52 -0
- package/src/gateway/connectors/pi.ts +357 -0
- package/src/gateway/connectors/qoder-cli.ts +6 -0
- package/src/gateway/connectors/qwen-code.ts +411 -0
- package/src/gateway/connectors/roo.ts +43 -0
- package/src/gateway/connectors/tabnine-cli.ts +6 -0
- package/src/gateway/connectors/void.ts +6 -0
- package/src/gateway/connectors/vscode-copilot.ts +286 -0
- package/src/gateway/connectors/windsurf.ts +6 -0
- package/src/gateway/connectors/zed.ts +29 -0
- package/src/gateway/signin.ts +323 -0
- package/src/handoff.ts +104 -0
- package/src/hooks.ts +455 -0
- package/src/memory/audit.ts +514 -0
- package/src/memory/blobs.ts +94 -0
- package/src/memory/cli.ts +117 -0
- package/src/memory/distill.ts +381 -0
- package/src/memory/externalize.ts +435 -0
- package/src/memory/lookups.ts +70 -0
- package/src/memory/mcp-install.ts +401 -0
- package/src/memory/mcp-server.ts +296 -0
- package/src/memory/prepare.ts +179 -0
- package/src/memory/preview.ts +154 -0
- package/src/memory/project.ts +35 -0
- package/src/memory/redact.ts +72 -0
- package/src/memory/relevance.ts +187 -0
- package/src/memory/repomap.ts +516 -0
- package/src/memory/store.ts +270 -0
- package/src/memory/sync.ts +166 -0
- package/src/memory/tidy.ts +193 -0
- package/src/memory/types.ts +118 -0
- package/src/org/admin-ops.ts +96 -0
- package/src/org/auth.ts +112 -0
- package/src/org/backup.ts +115 -0
- package/src/org/cli.ts +438 -0
- package/src/org/client.ts +404 -0
- package/src/org/config.ts +44 -0
- package/src/org/crypto.ts +537 -0
- package/src/org/db.ts +435 -0
- package/src/org/graph.ts +318 -0
- package/src/org/oidc.ts +435 -0
- package/src/org/policy.ts +398 -0
- package/src/org/server.ts +920 -0
- package/src/org/sso.ts +316 -0
- package/src/org/tls.ts +66 -0
- package/src/org/types.ts +193 -0
- package/src/self.ts +68 -0
- package/src/session/attachments.ts +53 -0
- package/src/session/peekcache.ts +50 -0
- package/src/session/types.ts +104 -0
- package/src/session/util.ts +130 -0
- package/src/sqlite.ts +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nipurn Agarwal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
Parts of src/adapters/{antigravity,devin,grok-cli,hermes,kilo-cli,mastracode,muse,omp} are ported from session-migrate
|
|
26
|
+
(https://github.com/xhluca/session-migrate), used under its MIT license:
|
|
27
|
+
|
|
28
|
+
MIT License
|
|
29
|
+
|
|
30
|
+
Copyright (c) 2026 xhluca
|
|
31
|
+
|
|
32
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
33
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
34
|
+
in the Software without restriction, including without limitation the rights
|
|
35
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
36
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
37
|
+
furnished to do so, subject to the following conditions:
|
|
38
|
+
|
|
39
|
+
The above copyright notice and this permission notice shall be included in all
|
|
40
|
+
copies or substantial portions of the Software.
|
|
41
|
+
|
|
42
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
43
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
44
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
45
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
46
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
47
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
48
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,236 @@
|
|
|
1
|
-
#
|
|
1
|
+
# brain
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
One working session, any AI coding tool. Start in Claude Code, carry on in Codex, Cursor or another tool, and switch
|
|
4
|
+
back, with the same session. brain also keeps what each project has learned across tools, trims what a long session
|
|
5
|
+
sends back to the model, and can route your tools through the 100xprompt gateway.
|
|
6
|
+
|
|
7
|
+
Nothing calls a model to do any of this, and nothing changes in your tools until you run a command that says so.
|
|
8
|
+
|
|
9
|
+
Runs on [Bun](https://bun.sh) 1.3 or later. Built and tested on macOS.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bun add -g @100xprompt/brain
|
|
15
|
+
brain --version
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Or run it without installing:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bunx @100xprompt/brain session list --here
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Hooks and MCP entries installed from a `bunx` run start that same version later, so they keep working after Bun's
|
|
25
|
+
temporary copy is gone. No Bun yet? `curl -fsSL https://bun.sh/install | bash`.
|
|
26
|
+
|
|
27
|
+
## Quick start
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
brain session list --here # sessions from every tool, for this project, newest first
|
|
31
|
+
brain session continue <id> --in codex --dry-run # what would be written, and what would not carry over
|
|
32
|
+
brain session continue <id> --in codex # a new Codex session that picks up where that one stopped
|
|
33
|
+
brain session handoff --in claude-code # the newest session from another tool in this folder
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`<id>` is `<tool>:<session id>` as `list` prints it, or a unique start of the session id.
|
|
37
|
+
|
|
38
|
+
## Moving a session
|
|
39
|
+
|
|
40
|
+
`continue` writes the session into the target the best way that target allows:
|
|
41
|
+
|
|
42
|
+
- **Native** (a new session in the tool's own storage, opened like any other): Claude Code, Codex, Gemini CLI, Copilot
|
|
43
|
+
Chat in VS Code, the Copilot CLI, Cline (in VS Code, Cursor, Windsurf, and its CLI), Roo Code (in VS Code, Cursor,
|
|
44
|
+
Windsurf), Antigravity, Aider, Amazon Q (CLI and IDE), Auggie, Codebuff, Continue, Crush, Devin CLI, Factory Droid,
|
|
45
|
+
Grok CLI, Hermes Agent, iFlow CLI, Kimi Code, Kiro (CLI and IDE), Letta Code, Mastra Code, Muse Code, Oh My Pi,
|
|
46
|
+
OpenHands CLI, PearAI, Pi, Qoder CLI, Qwen Code, Tabnine CLI, Void and Zed.
|
|
47
|
+
- **Import** (through the tool's own import): 100xprompt, OpenCode, Cursor, Goose, Kilo Code, Kilo CLI and Mistral Vibe.
|
|
48
|
+
- **Brief**: the Cursor CLI, and any other tool (`--in any`: a Markdown file to paste).
|
|
49
|
+
|
|
50
|
+
A native or import writer writes only for the tool versions its format was checked against, and some need the app
|
|
51
|
+
closed (VS Code); otherwise, and whenever the tool is missing, the session goes as a brief. `brain session targets`
|
|
52
|
+
shows what each tool on this machine gets right now, and `brain session list` shows every session brain can read.
|
|
53
|
+
|
|
54
|
+
A **brief** is built without a model call: where the session came from, the goal, where it stands, files changed, the
|
|
55
|
+
last commands, the latest requests, and as many recent turns as fit the target. It is saved as a pending handoff, copied
|
|
56
|
+
to the clipboard where the system has one, and, where the session-start hook is installed (`brain session hooks
|
|
57
|
+
install`, for Claude Code, Codex, Cursor and Gemini CLI), given to the model by the target's next session in the same
|
|
58
|
+
project.
|
|
59
|
+
|
|
60
|
+
## Saving tokens
|
|
61
|
+
|
|
62
|
+
On real sessions, tool calls and their output are about four fifths of the tokens; what was said is about a tenth.
|
|
63
|
+
|
|
64
|
+
- **Lean sessions.** A big tool call or result becomes a one-line digest with a short preview, and the full text stays on
|
|
65
|
+
disk (`~/.brain/blobs/`). `continue` does this by itself on long sessions (`--lean` / `--full` override; `--budget
|
|
66
|
+
<tokens>` trims in steps until the session fits). The model gets the text back only when it asks, through the
|
|
67
|
+
`brain_expand` tool (or `brain expand <id>`).
|
|
68
|
+
- **Project memory.** What a session settled (decisions, constraints, preferences, files, failed approaches, commands) is
|
|
69
|
+
distilled into small items kept per project, so a session in any tool can recall them with `brain_recall`. Memory needs
|
|
70
|
+
[Chitta](https://www.npmjs.com/package/@100xprompt/chitta) (`bun add -g @100xprompt/chitta`, found next to brain, in a
|
|
71
|
+
global install, or at `$BRAIN_CHITTA`); without it everything else works, except a Teams server.
|
|
72
|
+
- **What every request reloads.** `brain tokens audit` checks, without changing anything, what a project sends with every
|
|
73
|
+
request: instruction files, MCP servers, ignore files.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
brain mcp install # brain_recall and brain_expand in Claude Code, Codex, Cursor, Gemini CLI, OpenCode, VS Code
|
|
77
|
+
brain memory sync --here # distill this project's earlier sessions (a few per run; nothing is processed twice)
|
|
78
|
+
brain memory search "how do we run the tests"
|
|
79
|
+
brain tokens audit
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## The 100xprompt gateway
|
|
83
|
+
|
|
84
|
+
Point a coding tool at the 100xprompt gateway, and back. Signing in works like `100xprompt auth login`: your browser opens,
|
|
85
|
+
you sign in to 100xprompt and confirm, and the key comes back to brain by itself.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
brain gateway login # sign in in the browser
|
|
89
|
+
brain gateway connect --tool codex --dry-run # show what would change
|
|
90
|
+
brain gateway connect --tool codex # any tool in the table below (signs in first if needed)
|
|
91
|
+
brain gateway status
|
|
92
|
+
brain gateway disconnect --tool codex # put back exactly what was there
|
|
93
|
+
brain gateway logout
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
- Connecting changes which model the tool uses: it runs on 100xprompt Pro by default (`--model flash` for 100xprompt
|
|
97
|
+
Flash), billed to your 100xprompt account. Context editing is on by default; `--no-context-edit` turns it off and is
|
|
98
|
+
remembered for later connects until `--context-edit`.
|
|
99
|
+
- Before changing anything, `connect` checks that the gateway accepts your key the way that tool sends it (a free check
|
|
100
|
+
that generates nothing). If your account's quota is used up, it still connects and tells you, in the gateway's words.
|
|
101
|
+
- Only the settings brain owns are written; the value each had before is recorded and put back by `disconnect`. The key
|
|
102
|
+
lives in `~/.brain/gateway.key`, readable only by you, and is never printed.
|
|
103
|
+
- On a machine without a browser (SSH): `brain gateway login --no-browser` prints the address. Open it anywhere, then
|
|
104
|
+
paste the key from the page's Copy key button (input is hidden). For scripts and CI: `--key-env VAR`. To reuse the
|
|
105
|
+
100xprompt CLI's sign-in: `--from-cli`.
|
|
106
|
+
- Each sign-in makes a new key on your account. Signing in again also updates every copy of the key that a connected tool
|
|
107
|
+
keeps in its own config.
|
|
108
|
+
|
|
109
|
+
| Tool (`--tool`) | How it gets the key | Context editing | Checked with the real tool |
|
|
110
|
+
|---|---|---|---|
|
|
111
|
+
| Claude Code (`claude-code`) | reads brain's key file at start | yes | yes |
|
|
112
|
+
| Codex (`codex`) | copy in its config, made private | yes | yes |
|
|
113
|
+
| OpenCode (`opencode`) | reads brain's key file | yes | yes |
|
|
114
|
+
| Gemini CLI (`gemini-cli`) | copy in `~/.gemini/.env`, private | no | yes (needs the gateway update that accepts `x-goog-api-key`) |
|
|
115
|
+
| Aider (`aider`) | copy in its model settings, private | yes | yes |
|
|
116
|
+
| Cline CLI (`cline-sdk`) | copy in its providers file, private | yes | yes |
|
|
117
|
+
| Continue (`continue`) | copy in `~/.continue/.env`, private | yes | yes (`cn`) |
|
|
118
|
+
| Copilot CLI (`copilot-cli`) | copy in its providers file, private | yes | yes |
|
|
119
|
+
| Copilot Chat in VS Code (`vscode-copilot`) | copy in VS Code's model list, private | yes | from the extension's code; pick "100xprompt Pro" once in the model picker |
|
|
120
|
+
| Crush (`crush`) | reads brain's key file | yes | yes |
|
|
121
|
+
| Factory Droid (`factory-droid`) | reads brain's key file | yes | yes |
|
|
122
|
+
| Goose (`goose`) | reads brain's key file | yes | yes |
|
|
123
|
+
| Grok CLI (`grok-cli`) | copy in its config, private | yes | yes |
|
|
124
|
+
| Hermes Agent (`hermes`) | copy in `~/.hermes/.env`, private | yes | yes |
|
|
125
|
+
| iFlow CLI (`iflow-cli`) | copy in its settings, private | no | yes |
|
|
126
|
+
| Kilo CLI and Kilo Code (`kilo-cli`, `kilo-code`) | reads brain's key file | yes | yes |
|
|
127
|
+
| Kimi Code (`kimi-code`) | copy in its config, private | yes | yes |
|
|
128
|
+
| Letta Code (`letta-code`) | reads brain's key file (a provider mod; local agents only) | yes | from its source |
|
|
129
|
+
| Mastra Code (`mastracode`) | copy in its settings, private | no | from its source |
|
|
130
|
+
| Mistral Vibe (`mistral-vibe`) | copy in `~/.vibe/.env`, private | yes | yes |
|
|
131
|
+
| Oh My Pi (`omp`) | reads brain's key file | yes | from its source |
|
|
132
|
+
| OpenHands (`openhands`) | copy in its settings, private | yes | yes |
|
|
133
|
+
| PearAI (`pearai`) | copy in `~/.pearai/.env`, private | yes | from its source |
|
|
134
|
+
| Pi (`pi`) | reads brain's key file | yes | yes |
|
|
135
|
+
| Qwen Code (`qwen-code`) | copy in `~/.qwen/.env`, private | yes | yes |
|
|
136
|
+
|
|
137
|
+
"Checked with the real tool" means the real program, pointed at a local stand-in gateway, sent its request to the gateway's
|
|
138
|
+
route with the key and the gateway's model, and `disconnect` gave every file back byte for byte (its original mode too).
|
|
139
|
+
|
|
140
|
+
Some tools cannot be pointed at the gateway from a file brain can safely write and cleanly undo, so they have no connector:
|
|
141
|
+
Cursor and the Cursor CLI, Windsurf, Antigravity, Amazon Q, Kiro, Auggie, Tabnine, Devin and Muse Code (their vendor's own
|
|
142
|
+
servers only); Zed (the key only in the keychain or its launch environment); Void (settings encrypted in the app's state);
|
|
143
|
+
Roo Code and the Cline extension (they keep the key in the editor's own storage, so disconnect could not take it back);
|
|
144
|
+
Codebuff and Qoder (custom endpoints only through their own sign-in or the keychain). The reason and its source are in each
|
|
145
|
+
tool's file under `src/gateway/connectors/`.
|
|
146
|
+
|
|
147
|
+
Gemini CLI loads only the first `.env` it finds from the project folder up: in a project with its own `.env`, put the
|
|
148
|
+
gateway lines there or export them. Letta Code uses the gateway for its local agents only (cloud agents call models from
|
|
149
|
+
Letta's servers). Tools that read brain's key file stop working after `logout` until the next `login`; Kilo refuses to start
|
|
150
|
+
without it.
|
|
151
|
+
|
|
152
|
+
## Dashboard
|
|
153
|
+
|
|
154
|
+
Signed in to the gateway, brain sends a short report of this machine to your 100xprompt account, shown in the console's
|
|
155
|
+
Brain view (https://100xprompt.com/dashboard?view=brain): the coding tools found here, their session counts, which are
|
|
156
|
+
connected to the gateway or have brain's MCP tools and hooks, your gateway settings, memory counts, and every chat brain
|
|
157
|
+
moved from one tool into another (when, from and to which tool, the way, its title and its project folder's name). Never
|
|
158
|
+
chat text, file contents, full paths or keys.
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
brain dashboard # count sessions, send the report now, open the Brain view (--no-open prints the address)
|
|
162
|
+
brain dashboard status # on or off, and when the last report went out
|
|
163
|
+
brain dashboard off # send nothing from this machine (brain dashboard on to start again)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The report goes out in the background, at most every 30 seconds, after a command that changes it (`gateway login`,
|
|
167
|
+
`connect`, `disconnect`, `session continue`, `handoff`, `mcp install`/`uninstall`, `session hooks install`/`uninstall`),
|
|
168
|
+
and never makes that command wait or fail. The first time, brain prints what it sends and how to stop it.
|
|
169
|
+
`BRAIN_NO_REPORT=1` also turns it off. The conversion log is `~/.brain/logs/conversions.jsonl`, readable only by you.
|
|
170
|
+
|
|
171
|
+
## Teams
|
|
172
|
+
|
|
173
|
+
Memory can live on one shared server instead of each person's machine, with who may see what enforced there.
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# on the server (it needs Chitta: bun add -g @100xprompt/chitta)
|
|
177
|
+
brain org admin init --db org.db --org-id acme --org-name Acme --admin-id ana --admin-name Ana # once; prints the admin token
|
|
178
|
+
brain org admin serve --db org.db --host 0.0.0.0 --allow-remote --tls-cert cert.pem --tls-key key.pem
|
|
179
|
+
|
|
180
|
+
# on each person's machine
|
|
181
|
+
brain org login --server https://<server>:4500 --token <token>
|
|
182
|
+
brain org promote --source <session> --to team --team backend
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Every item has a scope: `private` (the default; only its owner, not even an admin), `project`, `team` or `org`. Sharing
|
|
186
|
+
is an explicit, logged act. Roles are `viewer`, `editor` and `admin`; admins set policy (widest scope, paths and terms that
|
|
187
|
+
are never shared, retention) and read the audit log. Only distilled, secret-filtered memory items cross the wire: never
|
|
188
|
+
full tool output, raw turns or attachments. With no login, brain stays entirely local.
|
|
189
|
+
|
|
190
|
+
`admin serve` listens on 127.0.0.1 unless told otherwise: to reach it from other machines, use `--allow-remote` with TLS
|
|
191
|
+
(`--tls-cert`/`--tls-key`), or keep it local behind a TLS proxy (`--trust-proxy`). An encrypted database (`init
|
|
192
|
+
--encrypt`) also needs `libsql` installed next to Chitta. `brain org help` lists every option.
|
|
193
|
+
|
|
194
|
+
## Safety
|
|
195
|
+
|
|
196
|
+
- Reading a session never changes a tool's files: SQLite stores are copied (with their write-ahead logs) and the copy is
|
|
197
|
+
read. To see which version is installed, `targets` and `--dry-run` start each installed tool with `--version`.
|
|
198
|
+
- Continuing always writes a **new** session; the source is never changed, so switching back is continuing the original.
|
|
199
|
+
- Writers check the installed tool version against the one their format was verified on, and fall back to the brief otherwise.
|
|
200
|
+
- `--dry-run` shows what would be written. Hooks, MCP entries and gateway settings are merged with your own, backed up
|
|
201
|
+
first, and removed exactly by the matching `uninstall` or `disconnect`.
|
|
202
|
+
|
|
203
|
+
## Commands
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
brain session list | show | export | continue | handoff | targets | hooks
|
|
207
|
+
brain memory ingest | search | status | forget | sync
|
|
208
|
+
brain mcp serve | install | uninstall | status
|
|
209
|
+
brain tokens audit | lookups
|
|
210
|
+
brain gateway login | logout | connect | disconnect | status | tools
|
|
211
|
+
brain dashboard [push | on | off | status]
|
|
212
|
+
brain org login | logout | whoami | status | promote | demote | forget | admin ...
|
|
213
|
+
brain expand <id>
|
|
214
|
+
brain --version
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
`brain --help` lists every command with its main options; `brain gateway`, `brain mcp` and `brain org help` show the rest
|
|
218
|
+
of theirs.
|
|
219
|
+
|
|
220
|
+
## Known limits
|
|
221
|
+
|
|
222
|
+
- Built and tested on macOS. Linux and Windows are not tested yet.
|
|
223
|
+
- Each writer is checked against specific versions, for example Claude Code 2.1.296 to 2.1.319 (a newer 2.1.x is
|
|
224
|
+
accepted with a note), Codex 0.147.0, Gemini CLI 0.33.1 and 0.67.0, Cursor 3.27 and 3.29, VS Code 1.144 with Copilot
|
|
225
|
+
Chat 0.72, OpenCode 2.2.6, Zed 1.26.2 and 1.27.0, Aider 0.86.2. A tool at another version gets the brief instead.
|
|
226
|
+
- Into Codex: tool names from Claude Code (`Read`, `Grep`, `Agent`, MCP calls) stay as they are, and subagent transcripts
|
|
227
|
+
are not carried. Pasted images are.
|
|
228
|
+
- Into Claude Code: reasoning and subagent transcripts are not written.
|
|
229
|
+
- Cursor is reached through its own import of Claude Code sessions (for the folder it has open), not by writing to
|
|
230
|
+
Cursor's database; the brief opens in Cursor's chat when that is not possible.
|
|
231
|
+
- Session-start hooks were checked against each tool's installed code, not yet inside every live tool. Codex asks you to
|
|
232
|
+
trust a new hook once.
|
|
233
|
+
|
|
234
|
+
## License
|
|
235
|
+
|
|
236
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,50 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@100xprompt/brain",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "One working session, any AI coding tool: move sessions between Claude Code, Codex, Cursor, Gemini CLI, OpenCode and more, keep what projects learned, spend fewer tokens. Runs on Bun. By 100xprompt.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Nipurn Agarwal",
|
|
7
|
+
"homepage": "https://www.npmjs.com/package/@100xprompt/brain",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"ai-coding",
|
|
10
|
+
"coding-agent",
|
|
11
|
+
"claude-code",
|
|
12
|
+
"codex",
|
|
13
|
+
"cursor",
|
|
14
|
+
"gemini-cli",
|
|
15
|
+
"opencode",
|
|
16
|
+
"session",
|
|
17
|
+
"handoff",
|
|
18
|
+
"context",
|
|
19
|
+
"memory",
|
|
20
|
+
"mcp",
|
|
21
|
+
"tokens",
|
|
22
|
+
"100xprompt"
|
|
23
|
+
],
|
|
24
|
+
"type": "module",
|
|
25
|
+
"engines": {
|
|
26
|
+
"bun": ">=1.3.0"
|
|
27
|
+
},
|
|
28
|
+
"bin": {
|
|
29
|
+
"brain": "./src/cli.ts"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"src",
|
|
33
|
+
"README.md",
|
|
34
|
+
"LICENSE"
|
|
35
|
+
],
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"brain": "bun run src/cli.ts",
|
|
41
|
+
"test": "bun test --timeout 60000",
|
|
42
|
+
"typecheck": "tsc --noEmit -p .",
|
|
43
|
+
"wire": "bun wire/run.ts"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/bun": "^1.4.4",
|
|
47
|
+
"oidc-provider": "9.13.3",
|
|
48
|
+
"typescript": "5.8.2"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Reader, Writer } from "../types.ts"
|
|
2
|
+
import { aiderReader } from "./reader.ts"
|
|
3
|
+
import { aiderNativeWriter } from "./writer.ts"
|
|
4
|
+
|
|
5
|
+
// Aider: reads each run of a project's .aider.chat.history.md as a session, and continues any session as a
|
|
6
|
+
// new run in that history, which `aider --restore-chat-history` hands to the model.
|
|
7
|
+
export const readers: Reader[] = [aiderReader]
|
|
8
|
+
export const writers: Writer[] = [aiderNativeWriter]
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { createHash } from "node:crypto"
|
|
2
|
+
import { readFileSync, statSync } from "node:fs"
|
|
3
|
+
import { dirname } from "node:path"
|
|
4
|
+
import type { Session, Turn } from "../../session/types.ts"
|
|
5
|
+
import { header, lossCounter, noteModel } from "../../session/util.ts"
|
|
6
|
+
import type { Reader, SessionRef } from "../types.ts"
|
|
7
|
+
import { CONTINUED_NOTE, LABEL, SUMMARY_PREFIX, TOOL, type Run, assistantText, findHistories, parseRuns, userText } from "./records.ts"
|
|
8
|
+
|
|
9
|
+
// Aider sessions. Aider has no session list or ids: every project keeps one history file and each launch
|
|
10
|
+
// appends a run to it, so a run ("# aider chat started at ...") is read as one session. That is also what
|
|
11
|
+
// a launch without --restore-chat-history sees: a fresh chat. Ids are made from the file and the run's start.
|
|
12
|
+
|
|
13
|
+
/** "2026-11-08 10:00:00" (local time, as Aider writes it) → ISO. */
|
|
14
|
+
const runTime = (stamp: string | undefined) => {
|
|
15
|
+
if (!stamp) return undefined
|
|
16
|
+
const t = new Date(stamp.replace(" ", "T"))
|
|
17
|
+
return Number.isFinite(t.getTime()) ? t.toISOString() : undefined
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const fileKey = (path: string) => createHash("sha1").update(path).digest("hex").slice(0, 8)
|
|
21
|
+
|
|
22
|
+
/** The id of a run: the file's key and the run's start (YYYYMMDDhhmmss), with its index when two share a second. */
|
|
23
|
+
export function runId(path: string, run: Run, runs: Run[]): string {
|
|
24
|
+
const stamp = (run.startedAt ?? "00000000000000").replace(/\D/g, "")
|
|
25
|
+
const twin = runs.filter((r) => r.startedAt === run.startedAt).length > 1
|
|
26
|
+
return `${fileKey(path)}-${stamp}${twin || !run.startedAt ? `-${run.index}` : ""}`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Runs that hold conversation, not only Aider's startup notices. */
|
|
30
|
+
const talked = (run: Run) => run.messages.some((m) => m.role !== "tool")
|
|
31
|
+
|
|
32
|
+
function readText(path: string): string {
|
|
33
|
+
try {
|
|
34
|
+
return readFileSync(path, "utf8")
|
|
35
|
+
} catch (e) {
|
|
36
|
+
throw new Error(`cannot read the Aider history ${path}: ${(e as Error).message}`)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** One run as a portable session. */
|
|
41
|
+
export function runSession(path: string, run: Run, runs: Run[], updatedAt?: string): Session {
|
|
42
|
+
const id = runId(path, run, runs)
|
|
43
|
+
const h = header(TOOL, id, { sourcePath: path, project: { cwd: dirname(path) }, startedAt: runTime(run.startedAt), updatedAt })
|
|
44
|
+
const lost = lossCounter()
|
|
45
|
+
const turns: Turn[] = []
|
|
46
|
+
for (const [i, m] of run.messages.entries()) {
|
|
47
|
+
if (m.role === "tool") {
|
|
48
|
+
// Aider's own notices: never sent to the model. Kept: the model it ran, its version, and the files it edited.
|
|
49
|
+
for (const line of m.content.split("\n")) {
|
|
50
|
+
const model = line.match(/^(?:Main model|Model): (\S+)/)?.[1]
|
|
51
|
+
if (model) noteModel(h, model)
|
|
52
|
+
const version = line.match(/^Aider v(\d+\.\d+\.\d+\S*)/)?.[1]
|
|
53
|
+
if (version) h.toolVersion ??= version
|
|
54
|
+
const edited = line.match(/^Applied edit to (.+?)\s*$/)?.[1]
|
|
55
|
+
if (edited) turns.push({ kind: "file_edit", path: edited })
|
|
56
|
+
}
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
if (m.role === "user") {
|
|
60
|
+
const text = userText(m.content)
|
|
61
|
+
if (!text) continue
|
|
62
|
+
const note = i === run.messages.findIndex((x) => x.role === "user") ? text.match(CONTINUED_NOTE) : null
|
|
63
|
+
if (note) {
|
|
64
|
+
h.parent = { id: note[1]!.replace(/[.,]$/, ""), kind: "continued" }
|
|
65
|
+
continue
|
|
66
|
+
}
|
|
67
|
+
if (text.startsWith(SUMMARY_PREFIX.trim())) {
|
|
68
|
+
turns.push({ kind: "compaction", summary: text.slice(SUMMARY_PREFIX.trim().length).trim() })
|
|
69
|
+
continue
|
|
70
|
+
}
|
|
71
|
+
turns.push({ kind: "user", text })
|
|
72
|
+
continue
|
|
73
|
+
}
|
|
74
|
+
const text = assistantText(m.content)
|
|
75
|
+
if (text) turns.push({ kind: "assistant", text, ...(h.models.length ? { model: h.models[h.models.length - 1] } : {}) })
|
|
76
|
+
}
|
|
77
|
+
if (!turns.some((t) => t.kind === "user" || t.kind === "assistant")) lost.add("runs with only Aider's own notices")
|
|
78
|
+
lost.flush(h)
|
|
79
|
+
const first = turns.find((t) => t.kind === "user") as Extract<Turn, { kind: "user" }> | undefined
|
|
80
|
+
if (first) h.title = first.text.replace(/\s+/g, " ").trim().slice(0, 80)
|
|
81
|
+
return { header: h, turns }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export const aiderReader: Reader = {
|
|
85
|
+
tool: TOOL,
|
|
86
|
+
label: LABEL,
|
|
87
|
+
|
|
88
|
+
async list(home: string): Promise<SessionRef[]> {
|
|
89
|
+
const refs: SessionRef[] = []
|
|
90
|
+
for (const path of findHistories(home)) {
|
|
91
|
+
let text: string
|
|
92
|
+
let mtime: string | undefined
|
|
93
|
+
try {
|
|
94
|
+
text = readFileSync(path, "utf8")
|
|
95
|
+
mtime = statSync(path).mtime.toISOString()
|
|
96
|
+
} catch {
|
|
97
|
+
continue
|
|
98
|
+
}
|
|
99
|
+
const runs = parseRuns(text)
|
|
100
|
+
runs.forEach((run, i) => {
|
|
101
|
+
if (!talked(run)) return
|
|
102
|
+
const next = runs.slice(i + 1).find((r) => r.startedAt)
|
|
103
|
+
const first = run.messages.find((m) => m.role === "user" && !CONTINUED_NOTE.test(userText(m.content)))
|
|
104
|
+
refs.push({
|
|
105
|
+
tool: TOOL,
|
|
106
|
+
sourceId: runId(path, run, runs),
|
|
107
|
+
path,
|
|
108
|
+
cwd: dirname(path),
|
|
109
|
+
updatedAt: (next ? runTime(next.startedAt) : mtime) ?? runTime(run.startedAt),
|
|
110
|
+
...(first ? { title: userText(first.content).replace(/\s+/g, " ").trim().slice(0, 80) } : {}),
|
|
111
|
+
extra: { run: run.index },
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
return refs.sort((a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? ""))
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
async read(ref: SessionRef): Promise<Session> {
|
|
119
|
+
const runs = parseRuns(readText(ref.path))
|
|
120
|
+
const run = runs.find((r) => runId(ref.path, r, runs) === ref.sourceId) ?? runs.find((r) => r.index === ref.extra?.run)
|
|
121
|
+
if (!run) throw new Error(`no run ${ref.sourceId} in the Aider history ${ref.path}`)
|
|
122
|
+
let updatedAt: string | undefined
|
|
123
|
+
try {
|
|
124
|
+
updatedAt = statSync(ref.path).mtime.toISOString()
|
|
125
|
+
} catch {}
|
|
126
|
+
const next = runs.slice(run.index + 1).find((r) => r.startedAt)
|
|
127
|
+
return runSession(ref.path, run, runs, next ? runTime(next.startedAt) : updatedAt)
|
|
128
|
+
},
|
|
129
|
+
}
|