@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
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite"
|
|
2
|
+
import { join, resolve } from "node:path"
|
|
3
|
+
import { appSupport, versionOf } from "../../fsutil.ts"
|
|
4
|
+
import type { ToolKind } from "../../session/types.ts"
|
|
5
|
+
import { toolKindOf } from "../../session/util.ts"
|
|
6
|
+
|
|
7
|
+
// Devin CLI (Cognition): where its sessions are and what its rows look like. From xhluca/session-migrate (MIT):
|
|
8
|
+
// docs/devin-format.md and src/session_migrate/formats/devin.py, pinned to Devin CLI 3000.6.7 (260a97c8) and
|
|
9
|
+
// its SQLite schema 16, and from the store that exact CLI wrote in session-migrate's native corpus
|
|
10
|
+
// (tests/native_corpus/v1/sources/devin/3000.6.7/portable-rich, copied to test/fixtures/native-corpus/devin).
|
|
11
|
+
//
|
|
12
|
+
// Every local conversation lives in one shared sessions.db: a `sessions` row per conversation (its id a
|
|
13
|
+
// human-readable slug such as "pricey-toaster", its cwd, model and title; rows with hidden = 1 are not shown),
|
|
14
|
+
// and `message_nodes`, a forest of chat messages per session. `sessions.main_chain_id` is the tip of the
|
|
15
|
+
// active branch, so the conversation is the walk from that tip up the parent links; retried or edited-away
|
|
16
|
+
// nodes stay in the table and are not part of it. Each node's chat_message is JSON with a role (system, user,
|
|
17
|
+
// assistant, tool): user messages carry base64 `images`, assistant messages `tool_calls` and `thinking`, tool
|
|
18
|
+
// messages a `tool_call_id`. `tool_call_state` keeps the ACP ToolCall / ToolCallUpdate Devin shows for each
|
|
19
|
+
// call. Times in columns are epoch seconds; times inside the JSON are RFC 3339. `devin --resume <id>` resumes.
|
|
20
|
+
|
|
21
|
+
export const TOOL = "devin"
|
|
22
|
+
export const LABEL = "Devin CLI"
|
|
23
|
+
/** Devin CLI versions whose store the reader and writer were checked against. */
|
|
24
|
+
export const TESTED_VERSIONS = ["3000.6.7"]
|
|
25
|
+
/** The CLI version whose schema (16 migrations below) the store has; Devin's rows do not record the version. */
|
|
26
|
+
export const PINNED_VERSION = "3000.6.7"
|
|
27
|
+
/** The model a continued session runs on: Devin's default (the Free plan's) in the doc and the capture. */
|
|
28
|
+
export const DEFAULT_MODEL = "swe-1-6-slow"
|
|
29
|
+
|
|
30
|
+
/** The devin binary on PATH, read at call time (Bun.which does not see a PATH changed after start). */
|
|
31
|
+
export const devinBin = (): string | undefined => Bun.which("devin", { PATH: process.env.PATH ?? "" }) ?? undefined
|
|
32
|
+
|
|
33
|
+
/** What `devin --version` says ("devin 3000.6.7 (260a97c8)") and the version in it. */
|
|
34
|
+
export function devinVersion(bin: string): { raw?: string; version?: string } {
|
|
35
|
+
const raw = versionOf(bin)
|
|
36
|
+
const version = raw?.match(/\d+\.\d+\.\d+/)?.[0]
|
|
37
|
+
return { ...(raw ? { raw } : {}), ...(version ? { version } : {}) }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const DB = "sessions.db"
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* $XDG_DATA_HOME, when it describes this home (the person's own, not a test's or another account's), else
|
|
44
|
+
* <home>/.local/share.
|
|
45
|
+
*/
|
|
46
|
+
function xdgDataHome(home: string): string {
|
|
47
|
+
const xdg = process.env.XDG_DATA_HOME
|
|
48
|
+
if (xdg?.startsWith("/") && process.env.HOME && resolve(home) === resolve(process.env.HOME)) return xdg
|
|
49
|
+
return join(home, ".local", "share")
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The store Devin uses on this platform: ~/Library/Application Support/devin/cli/sessions.db on macOS,
|
|
54
|
+
* $XDG_DATA_HOME/devin/cli/sessions.db (else ~/.local/share/...) on Linux, %APPDATA%\devin\cli on Windows.
|
|
55
|
+
*/
|
|
56
|
+
export function storePath(home: string, platform: string = process.platform): string {
|
|
57
|
+
if (platform === "darwin") return join(appSupport(home), "devin", "cli", DB)
|
|
58
|
+
if (platform === "win32") return join(home, "AppData", "Roaming", "devin", "cli", DB)
|
|
59
|
+
return join(xdgDataHome(home), "devin", "cli", DB)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Every place a store may be: the platform's own first, then the Linux ones (a store copied from Linux). */
|
|
63
|
+
export function storeCandidates(home: string): string[] {
|
|
64
|
+
return [...new Set([storePath(home), join(xdgDataHome(home), "devin", "cli", DB), join(home, ".local", "share", "devin", "cli", DB)])]
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** refinery's migrations of a schema-16 store, with their checksums: (version, name, checksum). */
|
|
68
|
+
export const MIGRATIONS: Array<[number, string, string]> = [
|
|
69
|
+
[1, "initial_schema", "9244923949255133246"],
|
|
70
|
+
[2, "add_thinking_column", "14224532003883382682"],
|
|
71
|
+
[3, "add_prompt_history", "12622061916787456317"],
|
|
72
|
+
[4, "add_metadata_column", "10743897110053661924"],
|
|
73
|
+
[5, "message_forest", "9668121967925007678"],
|
|
74
|
+
[6, "add_node_metadata", "8078921727324108560"],
|
|
75
|
+
[7, "add_shell_context", "258551201440621856"],
|
|
76
|
+
[8, "add_session_cogs", "105359765896368723"],
|
|
77
|
+
[9, "add_rendered_commits", "3762685451217257726"],
|
|
78
|
+
[10, "add_workspace_dirs", "10474887258761036276"],
|
|
79
|
+
[11, "add_prompt_history_is_shell", "11375493059147639310"],
|
|
80
|
+
[12, "add_app_state", "14171664772219278324"],
|
|
81
|
+
[13, "rename_permission_mode_to_agent_mode", "14037567567567316550"],
|
|
82
|
+
[14, "tool_call_state", "9276893574920127698"],
|
|
83
|
+
[15, "add_hidden_column", "3632756168171233470"],
|
|
84
|
+
[16, "add_session_json_metadata", "4954231843905863386"],
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
/** Every table of a schema-16 store with its columns, in order. */
|
|
88
|
+
export const COLUMNS: Record<string, string[]> = {
|
|
89
|
+
sessions: ["id", "working_directory", "backend_type", "model", "agent_mode", "created_at", "last_activity_at", "title", "main_chain_id", "shell_last_seen_index", "cogs_json", "workspace_dirs", "hidden", "metadata"],
|
|
90
|
+
message_nodes: ["row_id", "session_id", "node_id", "parent_node_id", "chat_message", "created_at", "metadata"],
|
|
91
|
+
prompt_history: ["id", "content", "timestamp", "session_id", "is_shell"],
|
|
92
|
+
tool_call_state: ["session_id", "tool_call_id", "tool_call_json", "tool_call_update_json"],
|
|
93
|
+
rendered_commits: ["id", "session_id", "sequence_number", "rendered_html", "created_at"],
|
|
94
|
+
app_state: ["key", "value"],
|
|
95
|
+
refinery_schema_history: ["version", "name", "applied_on", "checksum"],
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The statements whose text sqlite_master holds in a store Devin 3000.6.7 made, in its order (sqlite_sequence
|
|
100
|
+
* comes by itself with the first AUTOINCREMENT table). Run as they are, a new store has the same schema text.
|
|
101
|
+
*/
|
|
102
|
+
export const SCHEMA: string[] = [
|
|
103
|
+
"CREATE TABLE refinery_schema_history(\n version int4 PRIMARY KEY,\n name VARCHAR(255),\n applied_on VARCHAR(255),\n checksum VARCHAR(255))",
|
|
104
|
+
"CREATE TABLE sessions (\n id TEXT PRIMARY KEY,\n working_directory TEXT NOT NULL,\n backend_type TEXT NOT NULL,\n model TEXT NOT NULL,\n agent_mode TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n last_activity_at INTEGER NOT NULL, title TEXT, main_chain_id INTEGER, shell_last_seen_index INTEGER DEFAULT 0, cogs_json TEXT, workspace_dirs TEXT, hidden INTEGER NOT NULL DEFAULT 0, metadata TEXT)",
|
|
105
|
+
"CREATE TABLE prompt_history (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n content TEXT NOT NULL,\n timestamp INTEGER NOT NULL,\n session_id TEXT NOT NULL\n, is_shell INTEGER NOT NULL DEFAULT 0)",
|
|
106
|
+
"CREATE TABLE message_nodes (\n row_id INTEGER PRIMARY KEY AUTOINCREMENT,\n session_id TEXT NOT NULL,\n node_id INTEGER NOT NULL, -- node_id within this session's forest\n parent_node_id INTEGER, -- NULL for root nodes\n chat_message TEXT NOT NULL,\n created_at INTEGER NOT NULL, metadata TEXT,\n FOREIGN KEY (session_id) REFERENCES sessions(id),\n UNIQUE(session_id, node_id)\n)",
|
|
107
|
+
"CREATE TABLE rendered_commits (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n session_id TEXT NOT NULL,\n sequence_number INTEGER NOT NULL,\n rendered_html TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n FOREIGN KEY (session_id) REFERENCES sessions(id),\n UNIQUE(session_id, sequence_number)\n)",
|
|
108
|
+
"CREATE TABLE app_state (\n key TEXT PRIMARY KEY NOT NULL,\n value TEXT NOT NULL\n)",
|
|
109
|
+
"CREATE TABLE tool_call_state (\n session_id TEXT NOT NULL,\n tool_call_id TEXT NOT NULL,\n -- Serialised acp::ToolCall JSON (the initial ToolCall event).\n -- Nullable: may be absent for interrupted sessions where the tool result\n -- was saved but resolve_and_commit did not complete.\n tool_call_json TEXT,\n -- Serialised acp::ToolCallUpdate JSON (the final completion update).\n tool_call_update_json TEXT,\n PRIMARY KEY (session_id, tool_call_id),\n FOREIGN KEY (session_id) REFERENCES sessions(id)\n)",
|
|
110
|
+
"CREATE INDEX idx_sessions_activity\n ON sessions(last_activity_at DESC)",
|
|
111
|
+
"CREATE INDEX idx_prompt_history_timestamp\n ON prompt_history(timestamp DESC)",
|
|
112
|
+
"CREATE INDEX idx_prompt_history_session\n ON prompt_history(session_id)",
|
|
113
|
+
"CREATE INDEX idx_message_nodes_session\n ON message_nodes(session_id)",
|
|
114
|
+
"CREATE INDEX idx_rendered_commits_session\n ON rendered_commits(session_id, sequence_number)",
|
|
115
|
+
"CREATE INDEX idx_sessions_hidden ON sessions(hidden)",
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
/** The columns the reader needs; a store without them is not one it knows. */
|
|
119
|
+
export const NEEDED_TO_READ: Record<string, string[]> = {
|
|
120
|
+
sessions: ["id", "working_directory", "model", "created_at", "last_activity_at", "title", "main_chain_id", "hidden"],
|
|
121
|
+
message_nodes: ["session_id", "node_id", "parent_node_id", "chat_message", "created_at"],
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Columns a table lacks (all of them when the table is missing). */
|
|
125
|
+
export function missingColumns(d: Database, need: Record<string, string[]>): string[] {
|
|
126
|
+
const out: string[] = []
|
|
127
|
+
for (const [table, cols] of Object.entries(need)) {
|
|
128
|
+
const have = new Set((d.query(`PRAGMA table_info("${table}")`).all() as Array<{ name: string }>).map((c) => c.name))
|
|
129
|
+
for (const c of cols) if (!have.has(c)) out.push(`${table}.${c}`)
|
|
130
|
+
}
|
|
131
|
+
return out
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** The migrations a store has applied, or [] when it has no refinery table. */
|
|
135
|
+
export function appliedMigrations(d: Database): Array<[number, string, string]> {
|
|
136
|
+
try {
|
|
137
|
+
return (d.query("SELECT version, name, checksum FROM refinery_schema_history ORDER BY version").all() as Array<{ version: number; name: string; checksum: unknown }>).map((r) => [
|
|
138
|
+
Number(r.version),
|
|
139
|
+
String(r.name),
|
|
140
|
+
String(r.checksum),
|
|
141
|
+
])
|
|
142
|
+
} catch {
|
|
143
|
+
return []
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Why a store is not one the writer may add to (exactly the schema-16 tables and migrations), or undefined. */
|
|
148
|
+
export function schemaProblem(d: Database): string | undefined {
|
|
149
|
+
const applied = appliedMigrations(d)
|
|
150
|
+
const newest = applied.at(-1)?.[0] ?? 0
|
|
151
|
+
if (newest > MIGRATIONS.length) return `the Devin store was migrated by a newer Devin (schema ${newest}; this writer knows ${MIGRATIONS.length})`
|
|
152
|
+
if (JSON.stringify(applied) !== JSON.stringify(MIGRATIONS)) return `the Devin store's migrations are not the ${PINNED_VERSION} ones (schema ${newest})`
|
|
153
|
+
for (const [table, cols] of Object.entries(COLUMNS)) {
|
|
154
|
+
const have = (d.query(`PRAGMA table_info("${table}")`).all() as Array<{ name: string }>).map((c) => c.name)
|
|
155
|
+
if (JSON.stringify(have) !== JSON.stringify(cols)) return `the Devin store's ${table} table is not the one Devin ${PINNED_VERSION} makes`
|
|
156
|
+
}
|
|
157
|
+
return undefined
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** One image of a user message, as Devin stores it (session-migrate's own writer used media_type). */
|
|
161
|
+
export interface DevinImage {
|
|
162
|
+
width: number
|
|
163
|
+
height: number
|
|
164
|
+
base64_data: string
|
|
165
|
+
mime_type?: string
|
|
166
|
+
media_type?: string
|
|
167
|
+
source_path?: string
|
|
168
|
+
caption?: string
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export interface DevinToolCall {
|
|
172
|
+
id: string
|
|
173
|
+
name: string
|
|
174
|
+
arguments: Record<string, unknown>
|
|
175
|
+
index: number
|
|
176
|
+
kind: "function"
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** The metadata of a chat message; extensions are namespaced ("chisel/…", "agent-ext/…", "brain/…"). */
|
|
180
|
+
export interface DevinMessageMeta {
|
|
181
|
+
num_tokens: number | null
|
|
182
|
+
is_user_input: boolean | null
|
|
183
|
+
request_id: string | null
|
|
184
|
+
metrics: Record<string, unknown> | null
|
|
185
|
+
finish_reason: string | null
|
|
186
|
+
extensions?: Record<string, unknown>
|
|
187
|
+
started_generation_at?: string
|
|
188
|
+
created_at: string
|
|
189
|
+
generation_model?: string
|
|
190
|
+
telemetry: { source: string; operation: string }
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** A message_nodes.chat_message. */
|
|
194
|
+
export interface DevinMessage {
|
|
195
|
+
message_id: string
|
|
196
|
+
role: "system" | "user" | "assistant" | "tool"
|
|
197
|
+
content: string
|
|
198
|
+
images?: DevinImage[]
|
|
199
|
+
tool_calls?: DevinToolCall[]
|
|
200
|
+
thinking?: { thinking: string; signature: string } | null
|
|
201
|
+
tool_call_id?: string
|
|
202
|
+
metadata: DevinMessageMeta
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** ACP's tool kinds, which Devin records for each call, as portable ones. */
|
|
206
|
+
const FROM_ACP: Record<string, ToolKind> = { read: "read", edit: "edit", search: "search", execute: "shell", fetch: "web" }
|
|
207
|
+
|
|
208
|
+
/** What a Devin tool call does: from its name where that says, else from the ACP kind Devin recorded. */
|
|
209
|
+
export function devinToolKind(name: string, acpKind?: string): ToolKind {
|
|
210
|
+
const byName = toolKindOf(name)
|
|
211
|
+
return byName !== "other" ? byName : (acpKind && FROM_ACP[acpKind]) || "other"
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** The ACP kind a portable call is shown with. */
|
|
215
|
+
export function acpKindOf(kind: ToolKind): string {
|
|
216
|
+
switch (kind) {
|
|
217
|
+
case "read":
|
|
218
|
+
return "read"
|
|
219
|
+
case "edit":
|
|
220
|
+
case "write":
|
|
221
|
+
return "edit"
|
|
222
|
+
case "shell":
|
|
223
|
+
return "execute"
|
|
224
|
+
case "search":
|
|
225
|
+
case "list":
|
|
226
|
+
return "search"
|
|
227
|
+
case "web":
|
|
228
|
+
return "fetch"
|
|
229
|
+
default:
|
|
230
|
+
return "other"
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** The marker on a compaction the writer stores (as a system message), and the text before its summary. */
|
|
235
|
+
export const COMPACTION_EXT = "brain/compaction"
|
|
236
|
+
export const SUMMARY_PREFIX = "[Summary of the earlier conversation]\n"
|
|
237
|
+
/** session-migrate's writer stores a compaction as a user message with this flag and prefix. */
|
|
238
|
+
export const SM_SUMMARY_PREFIX = "[Imported conversation summary]\n"
|
|
239
|
+
|
|
240
|
+
/** An image's type from its first bytes, for a stored image without one. */
|
|
241
|
+
export function sniffImage(bytes: Uint8Array): string | undefined {
|
|
242
|
+
const b = Buffer.from(bytes.buffer, bytes.byteOffset, Math.min(bytes.length, 16))
|
|
243
|
+
if (b.subarray(0, 8).equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))) return "image/png"
|
|
244
|
+
if (b[0] === 0xff && b[1] === 0xd8 && b[2] === 0xff) return "image/jpeg"
|
|
245
|
+
if (b.subarray(0, 6).toString("latin1") === "GIF87a" || b.subarray(0, 6).toString("latin1") === "GIF89a") return "image/gif"
|
|
246
|
+
if (b.subarray(0, 4).toString("latin1") === "RIFF" && b.subarray(8, 12).toString("latin1") === "WEBP") return "image/webp"
|
|
247
|
+
return undefined
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** Width and height from a PNG, JPEG, GIF or WebP header, as Devin records them; 0 × 0 when unreadable. */
|
|
251
|
+
export function imageSize(bytes: Buffer): { width: number; height: number } {
|
|
252
|
+
try {
|
|
253
|
+
const type = sniffImage(bytes)
|
|
254
|
+
if (type === "image/png") return { width: bytes.readUInt32BE(16), height: bytes.readUInt32BE(20) }
|
|
255
|
+
if (type === "image/gif") return { width: bytes.readUInt16LE(6), height: bytes.readUInt16LE(8) }
|
|
256
|
+
if (type === "image/jpeg") {
|
|
257
|
+
// The first start-of-frame marker (C0–CF, except C4 DHT, C8 JPG and CC DAC) holds the size.
|
|
258
|
+
for (let i = 2; i + 9 < bytes.length; ) {
|
|
259
|
+
if (bytes[i] !== 0xff) break
|
|
260
|
+
const marker = bytes[i + 1]!
|
|
261
|
+
if (marker >= 0xc0 && marker <= 0xcf && marker !== 0xc4 && marker !== 0xc8 && marker !== 0xcc)
|
|
262
|
+
return { width: bytes.readUInt16BE(i + 7), height: bytes.readUInt16BE(i + 5) }
|
|
263
|
+
i += 2 + bytes.readUInt16BE(i + 2)
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (type === "image/webp") {
|
|
267
|
+
const chunk = bytes.subarray(12, 16).toString("latin1")
|
|
268
|
+
if (chunk === "VP8 ") return { width: bytes.readUInt16LE(26) & 0x3fff, height: bytes.readUInt16LE(28) & 0x3fff }
|
|
269
|
+
if (chunk === "VP8L") {
|
|
270
|
+
const [b0, b1, b2, b3] = [bytes[21]!, bytes[22]!, bytes[23]!, bytes[24]!]
|
|
271
|
+
return { width: 1 + (((b1 & 0x3f) << 8) | b0), height: 1 + (((b3 & 0xf) << 10) | (b2 << 2) | ((b1 & 0xc0) >> 6)) }
|
|
272
|
+
}
|
|
273
|
+
if (chunk === "VP8X") return { width: 1 + bytes.readUIntLE(24, 3), height: 1 + bytes.readUIntLE(27, 3) }
|
|
274
|
+
}
|
|
275
|
+
} catch {}
|
|
276
|
+
return { width: 0, height: 0 }
|
|
277
|
+
}
|