Files
cobble/src/types/index.ts
T
tbenandClaude Opus 5.5 373210c2a5 Make the skill runbook limits a general setting
The longest runbook a skill may save and how much of it load_skill hands
back are now set on Settings > General (skill_body_max_chars,
skill_body_shown_chars), defaulting to AppData.SkillBodyMaxChars and
SkillBodyShownChars. Saving, confirming and proposing a skill check the
install's limit; a skill saved before it was lowered can still be toggled.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25 09:43:00 +01:00

1981 lines
52 KiB
TypeScript
Executable File

import type {
BUN_SQLITE_COBBLE_ALL_TYPEDEFS,
BUN_SQLITE_COBBLE_BOT_MESSAGES,
BUN_SQLITE_COBBLE_BOT_SESSIONS,
BUN_SQLITE_COBBLE_BOT_TASK_STEPS,
BUN_SQLITE_COBBLE_BOT_TASKS,
BUN_SQLITE_COBBLE_BOTS,
BUN_SQLITE_COBBLE_BOTS_QUEUE_UPDATES,
BUN_SQLITE_COBBLE_COMPUTERS,
BUN_SQLITE_COBBLE_CRON_JOBS,
BUN_SQLITE_COBBLE_MEDIA,
BUN_SQLITE_COBBLE_TASK_MEDIA,
BUN_SQLITE_COBBLE_TASK_NOTES,
BUN_SQLITE_COBBLE_TASKS,
BUN_SQLITE_COBBLE_USER_TYPES,
BUN_SQLITE_COBBLE_USERS,
BUN_SQLITE_COBBLE_WORKSPACES,
BunSQLiteTables,
} from "@/db/types/db";
import type { UserTypes } from "../dict/user-types-dict";
import type { BotPermissions, BotTypes } from "../dict/bot-types-dict";
import type { StorageVolume } from "../utils/storage-volumes";
import type { RunningVersion } from "../utils/running-version";
import type { WebsocketRooms } from "../dict/websocket-rooms";
import type { LucideIcon } from "lucide-react";
import type { ServerQueryParam } from "@moduletrace/bun-sqlite";
import type { MediaParadigms, MediaTypes } from "../dict/media-dict";
import type { BunextPageModuleServerReturnURLObject } from "@moduletrace/bunext/types";
import type { BUN_SQLITE_COBBLE_USERS_JOIN } from "./sql-joins";
import type { ImageInputToBase64FunctionReturn } from "@moduletrace/twui/utils/form/imageInputToBase64";
import type { HarnessKind } from "../dict/harness-dict";
import type { HarnessProviderKind } from "../dict/harness-provider-dict";
import type { EnvParadigm, KnownEnv } from "../dict/env-dict";
import type { ContainerStatus } from "../dict/computer-dict";
import type { BotFace, BotMessageReactionEmoji } from "../dict/bot-dict";
import type { HarnessCallSettings, TokenUsageSummary } from "../harness/usage/types";
import type { McpServerStatus, McpTransport } from "../dict/mcp-dict";
import type { ExtensionProposalKind, ExtensionProposalStatus } from "../dict/extension-proposal-dict";
import type {
CustomToolHttpMethod,
CustomToolKind,
CustomToolScriptLanguage,
CustomToolStatus,
} from "../dict/custom-tool-dict";
export type User = {
id: number;
first_name: string;
last_name: string;
email: string;
username?: string;
image?: string;
image_thumbnail?: string;
logged_in_status: boolean;
verification_status?: number;
date?: number;
csrf?: string;
roles?: string;
};
/**
* A bot row with its face and status line as the user it's for sees them
* (`botFaceSql`). Faces are per user, so a bot row read without one has
* neither.
*/
export type BotWithFace = BUN_SQLITE_COBBLE_BOTS & {
face?: BotFace;
status_line?: string;
};
/**
* A bot row plus its conversation (in its own chat or one workspace):
* unread, latest activity and latest message, for the rail.
*/
export type BotWithLastMessage = BotWithFace & {
/**
* In a workspace's crew: the bot is that workspace's admin
* (`bot_types`), shown with `AdminShield` beside its name.
*/
is_admin?: boolean | null;
unread?: number | null;
last_activity_at?: number | null;
last_message_text?: string | null;
last_message_at?: number | null;
};
/**
* A bot's schedule with what the routines page shows beside it: the bot
* and the workspace it runs in.
*/
export type CronJobWithNames = BUN_SQLITE_COBBLE_CRON_JOBS & {
bot_name?: string | null;
bot_kind?: string | null;
bot_hue?: string | null;
bot_color?: string | null;
bot_stone?: string | null;
bot_face?: string | null;
bot_image_media_id?: number | null;
workspace_name?: string | null;
};
/**
* A task with what a list shows beside it: the bot and workspace it belongs
* to, and its latest note.
*/
export type TaskWithNames = BUN_SQLITE_COBBLE_TASKS & {
bot_name?: string | null;
bot_kind?: string | null;
bot_hue?: string | null;
bot_color?: string | null;
bot_stone?: string | null;
bot_face?: string | null;
bot_image_media_id?: number | null;
workspace_name?: string | null;
/**
* Its newest note's text, for the row's second line.
*/
latest_note?: string | null;
/**
* How many files it carries.
*/
media_count?: number | null;
};
/**
* A file linked to a task, joined with the `media` row it's served from.
*/
export type TaskFile = BUN_SQLITE_COBBLE_TASK_MEDIA & {
media_type?: string | null;
mime_type?: string | null;
/**
* The `media` row's title, when the link has no name of its own.
*/
media_title?: string | null;
/**
* Whether the `media` row is still there.
*/
missing?: boolean;
};
/**
* A task with its notes and files: what the task modal and the workspace's
* tasks group render.
*/
export type TaskDetail = TaskWithNames & {
notes: BUN_SQLITE_COBBLE_TASK_NOTES[];
files: TaskFile[];
};
/**
* A session in a conversation's sessions modal.
*/
export type BotSessionListItem = BUN_SQLITE_COBBLE_BOT_SESSIONS & {
message_count: number;
last_message_text?: string | null;
};
/**
* A workspace in the rail: unread while any conversation in it is.
*/
export type WorkspaceWithActivity = BUN_SQLITE_COBBLE_WORKSPACES & {
unread: number;
last_activity_at?: number | null;
};
/**
* One recent conversation in a workspace, for its dashboard: the user's
* session with the bot, and the bot it's with.
*/
export type WorkspaceActivityItem = BUN_SQLITE_COBBLE_BOT_SESSIONS & {
message_count: number;
last_message_text?: string | null;
bot_name?: string | null;
bot_image_media_id?: number | null;
bot_hue?: string | null;
bot_color?: string | null;
bot_stone?: string | null;
bot_face?: string | null;
};
/**
* A computer with its container's state, for lists and the Add flow.
*/
export type ComputerWithStatus = BUN_SQLITE_COBBLE_COMPUTERS & {
status?: ContainerStatus | null;
/**
* Why setting it up failed, while `status` is `failed`.
*/
error?: string | null;
};
/**
* A bot in a workspace, with what it has for that workspace alone.
*/
export type WorkspaceBot = BotWithLastMessage & {
workspace_system_prompt?: string | null;
workspace_memory?: string | null;
};
/**
* A workspace a bot works in, with what the bot has for that workspace
* alone.
*/
export type BotWorkspace = WorkspaceWithActivity & {
workspace_system_prompt?: string | null;
workspace_memory?: string | null;
/**
* The bot is this workspace's admin (`bot_types`).
*/
is_admin?: boolean;
};
/**
* The task shown in the working-on panel, with its ordered steps.
*/
export type BotTaskWithSteps = BUN_SQLITE_COBBLE_BOT_TASKS & {
steps: BUN_SQLITE_COBBLE_BOT_TASK_STEPS[];
/**
* What its newest job has done so far, oldest first (`grabBotJobUpdates`).
*/
updates: BUN_SQLITE_COBBLE_BOTS_QUEUE_UPDATES[];
};
/**
* What stopping a bot reports back: how many of its jobs were stopped and
* how many of them are still open (an attempt that has to notice its
* lock is gone can take a heartbeat).
*/
export type BotStoppedPayload = {
bot_id: number;
stopped: number;
remaining: number;
};
/**
* `server:bot-job-update` data: a step a running job just took, with the
* task it's for (null for a reply).
*/
export type BotJobUpdateData = BUN_SQLITE_COBBLE_BOTS_QUEUE_UPDATES & {
task_id: number | null;
/**
* The conversation session the job belongs to.
*/
session_id: number | null;
};
/**
* `server:bot-session` data: one of the user's conversation sessions was
* started, named or otherwise changed.
*/
export type BotSessionChangedData = {
session_id: number;
bot_id: number;
workspace_id: number | null;
};
/**
* `server:bot-created` data: a bot the user can now see, the workspaces
* it's in, and whether it belongs in their own chat list (the main rail).
*/
export type BotCreatedData = {
bot: BotWithLastMessage;
workspace_ids: number[];
in_own_chat: boolean;
};
/**
* `server:workspace-created` data: a workspace the user can now see, as
* their rail lists it.
*/
export type WorkspaceCreatedData = {
workspace: WorkspaceWithActivity;
};
/**
* `server:workspace-removed` data: the workspace that was deleted.
*/
export type WorkspaceRemovedData = {
workspace_id: number;
};
/**
* `server:bot-removed` data: the bot that was deleted.
*/
export type BotRemovedData = {
bot_id: number;
};
/**
* `server:bot-updated` data: the bot's new face and status line, and its
* active task (null when there is none).
*/
export type BotUpdatedData = {
id: number;
face: BotFace;
status_line: string;
task: BotTaskWithSteps | null;
/**
* The computer the bot is on, when the push knows it (a switch, or the
* live relay). Null means its main one.
*/
computer_id?: number | null;
/**
* The workspaces the bot is in, when the push read them (a membership
* change). A workspace's crew drops a bot that's no longer in it.
*/
workspace_ids?: number[];
/**
* Its colour and stone, when the push read them (a recolour, or any bot
* change): every rail row and avatar takes them without a reload.
*/
color?: string | null;
stone?: string | null;
/**
* Its picture, when the push read it (a bot that set its own face): the
* rail and the thread swap the stone for it without a reload. Null means
* it has none.
*/
image_media_id?: number | null;
/**
* The workspaces it's admin of, when the push read them: a workspace's
* crew shows or drops its shield without a reload.
*/
admin_workspace_ids?: number[];
};
/**
* `server:workspace-updated` data: a workspace's picture changed, so the
* rail and its header show the new one.
*/
export type WorkspaceUpdatedData = {
workspace_id: number;
image_media_id: number | null;
};
/**
* A model provider as the client sees it: never the key itself.
*/
export type PublicHarnessProvider = {
id: number;
kind: HarnessProviderKind;
name: string;
base_url: string;
enabled: boolean;
has_key: boolean;
/**
* A key is set in the provider's environment variable.
*/
has_env_key: boolean;
needs_key: boolean;
key_env?: string;
last_synced_at?: number;
sync_error?: string;
};
/**
* A model a harness can be set to, for the Models settings page.
*/
export type HarnessModelOption = {
id: number;
provider_id: number;
provider_name: string;
slug: string;
name: string;
free: boolean;
voices?: string[];
/**
* The generation settings the model takes; undefined: all of them.
*/
supported_parameters?: string[];
};
/**
* One harness on the Models settings page: its setting, the models it can
* be set to, and what it runs on right now.
*/
/**
* A provider a harness can be limited to.
*/
export type HarnessProviderChoice = {
id: number;
name: string;
};
export type HarnessOverview = {
harness: HarnessKind;
title: string;
description: string;
required: boolean;
/**
* Picks a free model itself when none is picked. Otherwise it isn't
* available until one is.
*/
automatic: boolean;
model_id?: number;
/**
* The provider the harness is limited to; undefined: any.
*/
provider_id?: number;
/**
* The providers with a model that can do this job.
*/
providers: HarnessProviderChoice[];
fallback: boolean;
enabled: boolean;
options: Record<string, unknown>;
models: HarnessModelOption[];
/**
* The first model it would try now, if any.
*/
current?: HarnessModelOption & { source: "pinned" | "auto" };
/**
* How many models it would try in all.
*/
candidate_count: number;
/**
* On a bot's page: true while the bot uses the default for this
* harness, and what the default runs on.
*/
inherit?: boolean;
default?: Pick<HarnessOverview, "enabled" | "current" | "candidate_count">;
};
/**
* One harness's controls on the Models settings page. `model_id` null is
* automatic.
*/
export type HarnessFormValue = {
/**
* On a bot's page: use the default instead of its own setting.
*/
inherit?: boolean;
model_id: number | null;
provider_id: number | null;
fallback: boolean;
enabled: boolean;
voice?: string;
/**
* Generation settings (temperature, reasoning effort, ...), only the
* ones the picked model takes.
*/
params?: Record<string, number | string>;
};
export type HarnessSettingsFormObject = Partial<
Record<HarnessKind, HarnessFormValue>
>;
/**
* The Models settings page data, also returned by every harness API call
* so the page updates without a reload.
*/
export type HarnessOverviewPayload = {
providers: PublicHarnessProvider[];
harnesses: HarnessOverview[];
};
/**
* The install-wide part of a harness overview: what it is for and the
* models it can pick. Every bot and workspace shares it, so the models
* modal caches one copy per user.
*/
export type HarnessCatalog = Pick<
HarnessOverview,
| "harness"
| "title"
| "description"
| "required"
| "automatic"
| "providers"
| "models"
>;
export type HarnessCatalogPayload = {
harnesses: HarnessCatalog[];
};
/**
* The per-bot (or per-workspace) part of a harness overview: the setting,
* what it runs on now, and what the default runs on.
*/
export type HarnessSettingOverview = Omit<
HarnessOverview,
| "title"
| "description"
| "required"
| "automatic"
| "providers"
| "models"
> & {
/**
* A picked model the catalog no longer lists (its provider dropped it).
* The merge adds it back so the form can show and keep it.
*/
pinned_model?: HarnessModelOption;
/**
* The provider the setting is limited to when the catalog has no model
* from it, so the form still shows the limit.
*/
unavailable_provider?: HarnessProviderChoice;
};
export type BotHarnessSettingsPayload = {
harnesses: HarnessSettingOverview[];
};
/**
* An env as the Environment settings page sees it. `value` is sent only
* for non-secret envs; secrets are replaced, never read back.
*/
export type PublicEnv = {
id: number;
key: string;
description: string;
paradigm: EnvParadigm;
workspace_id: number | null;
computer_id: number | null;
bot_id: number | null;
secret: boolean;
expose_to_computers: boolean;
value?: string;
/**
* An `EnvDict` key the app itself reads.
*/
known: boolean;
};
/**
* Somewhere envs can be set: general, or one of the user's workspaces,
* computers or bots.
*/
export type EnvScope = {
paradigm: EnvParadigm;
id: number | null;
title: string;
};
/**
* One scope's envs, as a bot's or workspace's settings page sees them: the
* envs set there, and whether the viewer may change them.
*/
export type ScopedEnvsPayload = {
scope: EnvScope;
envs: PublicEnv[];
can_manage: boolean;
};
/**
* What saving or removing an env answers with: the Environment page's whole
* overview, or the one bot's or workspace's envs the settings pages show.
*/
export type EnvsMutationResult = {
overview?: EnvsOverviewPayload;
scoped?: ScopedEnvsPayload | null;
};
/**
* An app setting on the Environment page: whether it's saved, or comes
* from the server's environment instead.
*/
export type KnownEnvStatus = KnownEnv & {
saved: boolean;
from_process: boolean;
};
/**
* One tool an MCP server offers, as last listed (`mcp_servers.tools_cache`).
*/
export type McpToolInfo = {
name: string;
description: string;
input_schema: Record<string, unknown>;
};
/**
* Who gets an MCP server or custom tool: every bot, or the bots and
* workspaces it's attached to.
*/
export type ExtensionAccess = {
all_bots: boolean;
bot_ids: number[];
workspace_ids: number[];
};
/**
* An `mcp_servers` row with its JSON read.
*/
export type McpServerRecord = {
id: number;
name: string;
slug: string;
description: string;
transport: McpTransport;
url: string;
headers: Record<string, string>;
command: string;
setup_command: string;
env: Record<string, string>;
excluded_tools: string[];
tools: McpToolInfo[];
all_bots: boolean;
enabled: boolean;
status: McpServerStatus;
last_error: string;
last_synced_at: number | null;
};
export type CustomToolHttpConfig = {
method: CustomToolHttpMethod;
url: string;
headers?: Record<string, string>;
body?: string;
timeout_ms?: number;
};
export type CustomToolScriptConfig = {
language: CustomToolScriptLanguage;
code: string;
timeout_ms?: number;
};
export type CustomToolPromptConfig = {
prompt: string;
};
/**
* A `custom_tools` row with its JSON read, `config` matching its kind.
*/
export type CustomToolRecord = {
id: number;
name: string;
description: string;
parameters: Record<string, unknown>;
all_bots: boolean;
enabled: boolean;
status: CustomToolStatus;
last_error: string;
last_checked_at: number | null;
} & (
| { kind: "http"; config: CustomToolHttpConfig }
| { kind: "script"; config: CustomToolScriptConfig }
| { kind: "prompt"; config: CustomToolPromptConfig }
);
/**
* A `skills` row: a runbook a bot loads when it applies.
*/
export type SkillRecord = {
id: number;
name: string;
slug: string;
description: string;
body: string;
all_bots: boolean;
enabled: boolean;
};
/**
* One env a proposed MCP server or tool sends (`extensionEnvUses`), and
* where it's saved: `general`, or the bots and workspaces it's saved for
* only. Nothing saved means the user has to add it.
*/
export type ExtensionProposalEnv = {
key: string;
where: string;
saved_in: string[];
};
/**
* What a proposed MCP server or tool does, as the confirm card shows it:
* each line read from the config by the app, never from what the bot said.
*/
export type ExtensionProposalDetail = {
label: string;
value: string;
/**
* Long or code-like: shown as a block.
*/
block?: boolean;
};
/**
* An MCP server or tool the coordinator proposed (`extension_proposals`),
* as its chip and confirm card show it to the super admin.
*/
export type ExtensionProposalView = {
id: number;
kind: ExtensionProposalKind;
/**
* The one it changes, null for a new one.
*/
extension_id: number | null;
name: string;
status: ExtensionProposalStatus;
/**
* Still pending, but past `expires_at`: it can't be confirmed.
*/
expired: boolean;
expires_at: number;
outcome: string;
result_id: number | null;
/**
* Where it sends requests from the app; null for a script or a prompt.
*/
host: string | null;
envs: ExtensionProposalEnv[];
details: ExtensionProposalDetail[];
/**
* The bot's background check, in its own words.
*/
research: string;
sources: string[];
};
/**
* A skill as the Skills settings page shows it: nothing secret in one, so
* it's the row with who gets it instead of `all_bots`.
*/
export type PublicSkill = Omit<SkillRecord, "all_bots"> & {
access: ExtensionAccess;
};
/**
* An MCP server as the MCPs settings page shows it. Only super admins get
* how it's reached (`url`, `headers`, `command`, `setup_command`, `env`).
*/
export type PublicMcpServer = Omit<
McpServerRecord,
"url" | "headers" | "command" | "setup_command" | "env" | "all_bots"
> & {
access: ExtensionAccess;
url?: string;
headers?: Record<string, string>;
command?: string;
setup_command?: string;
env?: Record<string, string>;
};
/**
* A custom tool as the Tools settings page shows it. Only super admins get
* its `parameters` and `config`.
*/
export type PublicCustomTool = {
id: number;
name: string;
description: string;
kind: CustomToolKind;
enabled: boolean;
status: CustomToolStatus;
last_error: string;
last_checked_at: number | null;
access: ExtensionAccess;
parameters?: Record<string, unknown>;
config?: CustomToolHttpConfig | CustomToolScriptConfig | CustomToolPromptConfig;
};
/**
* The bots and workspaces an MCP server or tool can be attached to. The
* coordinator is listed for the super admin only.
*/
export type ExtensionTargets = {
bots: { id: number; name: string; role: string; kind: string }[];
workspaces: { id: number; name: string }[];
/**
* A super admin: adds, edits and deletes, and sets "all bots".
*/
can_edit: boolean;
};
/**
* One MCP server or tool a bot has, as its settings page and its chat's
* composer show it.
*/
export type BotExtension = {
kind: "mcp" | "tool" | "skill";
id: number;
name: string;
description: string;
/**
* One line on what it is, e.g. "HTTP request" or "Remote · 12 tools".
*/
detail: string;
state: "ok" | "error" | "untested";
enabled: boolean;
/**
* `bot`: given to the bot, removable. `workspace`: the workspace's,
* only while it works there.
*/
source: "bot" | "workspace";
};
/**
* A bot's MCP servers, tools and skills, and what can be added. Only super admins
* and admins (the super admin alone for the coordinator) manage them.
*/
export type BotExtensionsPayload = {
attached: BotExtension[];
addable: { kind: "mcp" | "tool" | "skill"; id: number; name: string }[];
can_manage: boolean;
};
export type McpServersOverviewPayload = ExtensionTargets & {
servers: PublicMcpServer[];
};
/**
* The install's skill limits (Settings > General, `grab-skill-limits.ts`).
*/
export type SkillLimitsOverview = {
/**
* The longest runbook a skill may save right now.
*/
body_max_chars: number;
/**
* How much of a runbook `load_skill` hands back right now.
*/
body_shown_chars: number;
/**
* The longest runbook when the install saved no limit.
*/
body_max_default: number;
/**
* What `load_skill` hands back when the install saved no limit.
*/
body_shown_default: number;
/**
* The most the settings page accepts for either.
*/
max: number;
};
export type SkillsOverviewPayload = ExtensionTargets & {
skills: PublicSkill[];
/**
* The install's runbook limits, for the skill form's hints.
*/
limits: SkillLimitsOverview;
};
export type CustomToolsOverviewPayload = ExtensionTargets & {
tools: PublicCustomTool[];
};
/**
* What testing an MCP server's form returned: its tools, or why it didn't
* connect.
*/
export type McpServerTestPayload = {
ok: boolean;
tools: McpToolInfo[];
error?: string;
};
/**
* What trying a custom tool returned, as a bot would read it.
*/
export type CustomToolTestPayload = {
output: string;
ok: boolean;
/**
* The page data, with the tool's new status.
*/
overview: CustomToolsOverviewPayload;
};
export type EnvsOverviewPayload = {
scopes: EnvScope[];
envs: PublicEnv[];
known: KnownEnvStatus[];
};
/**
* A bot file as the chat's files modal lists it.
*/
export type PublicBotFile = {
id: number;
name: string;
path: string;
size: number;
media_type: string;
purpose: string;
scope: string;
owner_id: number;
ingested_at?: number;
ingest_error?: string;
created_at: number;
/**
* Where the bytes are served (`/media/<media id>`, private).
*/
url: string;
};
/**
* A conversation's files, with the directory's usage against its quota.
*/
export type BotFileScopesPayload = {
files: PublicBotFile[];
folders: { scope: string; owner_id: number; path: string }[];
usage: { bytes: number; files: number };
quota_bytes: number;
quota_mb: number;
};
/**
* One entry in a folder the files browser shows: a file or a subfolder.
*/
export type StorageEntry = {
name: string;
/**
* Where it is inside the volume, e.g. `seo/coderank/raw`.
*/
path: string;
kind: "file" | "folder";
size: number;
modified_at: number;
media_type?: string;
/**
* The `bot_files` row that holds it, when the folder is a bot's or a
* workspace's.
*/
file_id?: number;
/**
* Where it opens: a `bot_files` row's media URL, else the browser's own
* streaming route.
*/
url?: string;
/**
* What an id folder in a computer's workspace is: the bot's, user's or
* workspace's name.
*/
label?: string;
};
/**
* One folder of the files browser: what it holds and how to get back up.
*/
export type StorageFolderPayload = {
spec: { volume: StorageVolume; owner_id: number };
/**
* What the folder is called: the bot's, workspace's or computer's name.
*/
label: string;
/**
* The folder asked for, inside the volume (empty at the top).
*/
path: string;
breadcrumbs: { name: string; href: string }[];
entries: StorageEntry[];
total: number;
offset: number;
/**
* The folder asked for isn't on disk (a stale link, or a computer whose
* home directory the app can't find), as opposed to an empty one.
*/
missing?: boolean;
};
/**
* What a database table's rows are identified by: a primary key column,
* the rowid a table without one still has, or nothing at all (a virtual
* table with neither).
*/
export type DatabaseTableKey = {
kind: "rowid" | "column" | "none";
/**
* The primary key column's name, for `kind: "column"`.
*/
name?: string;
};
export type DatabaseTableColumn = {
name: string;
/**
* SQLite's declared type, empty when the column has none (a view or a
* virtual table).
*/
type: string;
pk: boolean;
};
/**
* How a search matches: every word somewhere in the record's text, or the
* whole phrase somewhere in it.
*/
export type DatabaseSearchMode = "every_word" | "phrase";
/**
* The period the usage page totals, in epoch ms.
*/
export type UsageWindow = {
days: number;
start: number;
end: number;
};
/**
* Everything the usage page shows for one window: what the install's
* model calls spent, in total, per day, per harness and per model, with
* the day before the window and the last seven days for comparison.
*/
export type UsageOverview = {
window: UsageWindow;
totals: TokenUsageSummary;
by_harness: (TokenUsageSummary & { harness: string })[];
days: (TokenUsageSummary & { at: number; label: string })[];
models: (TokenUsageSummary & {
model_slug: string;
model_name: string | null;
provider_name: string;
provider_id: number | null;
harness: string;
})[];
previous: TokenUsageSummary;
week: TokenUsageSummary;
};
/**
* One table of the database, as the database browser lists it.
*/
export type DatabaseTableSummary = {
name: string;
type: "table" | "virtual";
/**
* How many records it holds, when it could be counted.
*/
rows: number | null;
/**
* What the table's pages take on disk, when SQLite can measure it.
*/
size_bytes: number | null;
columns: DatabaseTableColumn[];
key: DatabaseTableKey;
};
/**
* One value in a record, as a cell shows it. `text` is the whole value,
* or its first `AppData.DatabaseBrowserCellMaxChars` characters when
* `truncated` says so.
*/
export type DatabaseCell = {
text: string;
kind: "text" | "number" | "blob" | "null";
truncated: boolean;
};
/**
* One record of a table: what identifies it, and its columns' values.
*/
export type DatabaseRecord = {
key: string | number | null;
cells: Record<string, DatabaseCell>;
};
/**
* One page of a table's records.
*/
export type DatabaseRecordsPayload = {
table: DatabaseTableSummary;
records: DatabaseRecord[];
total: number;
page: number;
page_size: number;
/**
* The search these records answer, so the page knows whether its pager
* counts the table or a narrowing of it.
*/
search: string;
mode: DatabaseSearchMode;
};
/**
* One record, in full, for its modal.
*/
export type DatabaseRecordPayload = {
table: DatabaseTableSummary;
record: DatabaseRecord | null;
};
/**
* A folder in the files browser's picker.
*/
export type StorageSpecOption = {
spec: { volume: StorageVolume; owner_id: number };
label: string;
};
/**
* A worker bot's model settings page data, also returned when it saves.
*/
/**
* A file on a chat message, as the client shows it.
*/
export type BotMessageAttachment = {
id: number;
name: string;
media_type: MediaType;
url: string;
thumbnail_url?: string;
/**
* The bot file it is, when it was saved in one of the bot's folders.
*/
file_id?: number;
};
/**
* An emoji reaction on a message, grouped by emoji.
*/
export type BotMessageReaction = {
emoji: BotMessageReactionEmoji;
count: number;
/**
* The session user reacted with it.
*/
mine: boolean;
};
/**
* The message a reply quotes, as the thread shows it.
*/
export type BotMessageReply = {
id: number;
author: "bot" | "user";
text: string;
};
export type BotMessageWithAttachments = BUN_SQLITE_COBBLE_BOT_MESSAGES & {
attachments?: BotMessageAttachment[];
reactions?: BotMessageReaction[];
reply_to?: BotMessageReply | null;
/**
* What the model calls behind this message spent (`token_usages`),
* summed. Only on bot messages that took at least one call.
*/
usage?: TokenUsageSummary | null;
};
/**
* One model call behind a message, as its details modal lists it: which
* provider and model answered, for which harness, and what it spent.
*/
export type MessageDetailsCall = {
id: number;
created_at: number;
harness: string;
provider_id: number | null;
provider_name: string | null;
/**
* The provider's kind (`HarnessProviderKinds`), while the provider
* still exists.
*/
provider_kind: string | null;
model_slug: string | null;
/**
* The catalog's display name, while the model is still in it.
*/
model_name: string | null;
prompt_tokens: number;
completion_tokens: number;
cost: number | null;
/**
* How it was made (`token_usages.settings`); null for a call recorded
* before settings were.
*/
settings: HarnessCallSettings | null;
};
/**
* The calls of one provider, model and harness, summed: what the modal's
* "Models" list shows.
*/
export type MessageDetailsModel = TokenUsageSummary & {
harness: string;
provider_name: string | null;
provider_kind: string | null;
model_slug: string | null;
model_name: string | null;
/**
* The latest call's settings: a run keeps its settings, so they are
* the same for every call but a fallback.
*/
settings: HarnessCallSettings | null;
};
/**
* The queued job that produced a message, while it is kept
* (`BotQueueRetentionDays`).
*/
export type MessageDetailsJob = {
id: number;
kind: string | null;
title: string | null;
status: string | null;
attempts: number;
started_at: number | null;
finished_at: number | null;
/**
* How many model turns and notes it recorded (`bots_queue_updates`).
*/
steps: number;
};
/**
* Everything known about how one bot message was generated: the job that
* ran it, every model call it took and their totals.
*/
export type MessageDetails = {
message_id: number;
created_at: number | null;
totals: TokenUsageSummary;
models: MessageDetailsModel[];
/**
* The calls in the order they were made, up to
* `AppData.MessageDetailsMaxCalls`; `totals.calls` counts them all.
*/
calls: MessageDetailsCall[];
job: MessageDetailsJob | null;
};
/**
* `server:bot-reaction` data: a message's reactions changed.
*/
/**
* A page of a session's older messages, oldest first, and whether there
* are older still.
*/
export type OlderBotMessagesData = {
messages: BotMessageWithAttachments[];
has_more: boolean;
};
export type BotMessageReactionData = {
message_id: number;
reactions: BotMessageReaction[];
};
export type BotHarnessOverviewPayload = {
harnesses: HarnessOverview[];
};
/**
* A database snapshot in the bun-sqlite backups directory (`db/.backups`).
*/
export type DbBackup = {
name: string;
created_at: number;
size: number;
};
/**
* A tar.gz archive of the whole `DATA_DIR` in `BACKUP_ARCHIVE_DIR`
* (outside the data volume), newest first. Restoring one is an offline
* operation: the app only creates, lists and downloads them.
*/
export type DataBackup = {
name: string;
created_at: number;
size: number;
};
export type DataBackupRunKind = "archive" | "restore";
/**
* The whole-data archive or restore this process last started
* (`startDataBackupRun`), which the backups page polls while it runs.
* `boot_id` changes when the process restarts, which is how the page
* knows a restore finished.
*/
export type DataBackupRun = {
status: "idle" | "running" | "done" | "failed";
kind?: DataBackupRunKind;
started_at?: number;
finished_at?: number;
/**
* The archive written or restored.
*/
name?: string;
error?: string;
boot_id: string;
};
export type DataBackupStatus = {
run: DataBackupRun;
data_backups: DataBackup[];
};
export type BotVoicePayload = {
transcription: boolean;
speech: boolean;
};
/**
* The text model a conversation's bot runs on now, for its header.
*/
export type BotTextModel = {
name: string;
provider_name: string;
};
/**
* A conversation's history, which its page loads on the client once it
* renders (`grabConversationHistory`): the active session, its latest
* messages, whether it has older ones, and the bot's active task in it.
*/
export type ConversationHistory = {
session: BUN_SQLITE_COBBLE_BOT_SESSIONS;
messages: BotMessageWithAttachments[];
has_more: boolean;
/**
* The bot's active task in the session and what its job has done so
* far.
*/
task: BotTaskWithSteps | null;
};
/**
* What `api/admin/bots/conversation-history` answers: the history, or
* where to go instead when the user can't chat with the bot there any
* more.
*/
export type ConversationHistoryPayload = {
history?: ConversationHistory;
redirect?: string;
};
/**
* One build's `.bunext/public` files, downloaded by the service worker
* before the app runs (`grabPrecacheManifest`).
*/
export type PrecacheManifest = {
build_id: string;
files: string[];
};
export type PagePropsType = {
user?: User | null;
user_types?: BUN_SQLITE_COBBLE_USER_TYPES[] | null;
person?: BUN_SQLITE_COBBLE_USERS_JOIN | null;
persons?: BUN_SQLITE_COBBLE_USERS_JOIN[] | null;
/**
* The user a settings page manages, when it is not the session user
* (`/admin/settings/users/<id>`).
*/
target_person?: BUN_SQLITE_COBBLE_USERS_JOIN | null;
/**
* Every worker and workspace, to pick what a user reaches
* (`grabCrewOptions`).
*/
crew_bots?: BUN_SQLITE_COBBLE_BOTS[] | null;
crew_workspaces?: BUN_SQLITE_COBBLE_WORKSPACES[] | null;
bots?: BotWithLastMessage[] | null;
bot?: BotWithLastMessage | null;
/**
* The user's workspaces, for the rail.
*/
workspaces?: WorkspaceWithActivity[] | null;
/**
* The workspace open now (its page or a conversation in it).
*/
workspace?: BUN_SQLITE_COBBLE_WORKSPACES | null;
/**
* On a workspace's page: its bots, its computers (default first),
* every computer the user has, and its models.
*/
workspace_bots?: WorkspaceBot[] | null;
/**
* Every bot the user has, for adding one to a workspace.
*/
all_bots?: BotWithLastMessage[] | null;
workspace_computers?: ComputerWithStatus[] | null;
computers?: ComputerWithStatus[] | null;
/**
* A workspace's dashboard: the user's latest sessions there.
*/
workspace_activity?: WorkspaceActivityItem[] | null;
/**
* A workspace's dashboard: its shared to-do list.
*/
workspace_tasks?: TaskWithNames[] | null;
/**
* The computer a settings page manages, with its access.
*/
computer?: ComputerWithStatus | null;
computer_bots?: BotWithFace[] | null;
computer_workspaces?: BUN_SQLITE_COBBLE_WORKSPACES[] | null;
workspace_harness_overview?: BotHarnessOverviewPayload | null;
/**
* The workspaces a bot works in, with what it has for each alone.
*/
bot_workspaces?: BotWorkspace[] | null;
/**
* The open bot's computers, the one it's on first.
*/
bot_computers?: ComputerWithStatus[] | null;
/**
* The routines page: every schedule the user's bots have.
*/
cron_jobs?: CronJobWithNames[] | null;
environment?: string;
has_password?: boolean;
backups?: DbBackup[] | null;
data_backups?: DataBackup[] | null;
data_backup_run?: DataBackupRun | null;
harness_overview?: HarnessOverviewPayload | null;
bot_harness_overview?: BotHarnessOverviewPayload | null;
envs_overview?: EnvsOverviewPayload | null;
/**
* What bots keep on disk: the per-folder quota and its usage (the
* General settings page).
*/
storage_quota?: {
setting_key: string;
quota_mb: number;
total_bytes: number;
total_files: number;
folders: number;
} | null;
/**
* The install-wide text appended to every bot's prompt (the General
* settings page).
*/
system_prompt_append?: {
setting_key: string;
text: string;
} | null;
/**
* Model turns a task run and a chat reply may take, with the code's
* defaults (the General settings page).
*/
run_limits?: {
task_steps: number;
reply_steps: number;
task_default: number;
reply_default: number;
max: number;
} | null;
/**
* The longest runbook a skill may save and how much of it a bot reads
* at once, with the code's defaults (the General settings page).
*/
skill_limits?: SkillLimitsOverview | null;
/**
* The release the server is running, for the General settings page.
*/
running_version?: RunningVersion | null;
push_overview?: PushOverview | null;
mcps_overview?: McpServersOverviewPayload | null;
tools_overview?: CustomToolsOverviewPayload | null;
skills_overview?: SkillsOverviewPayload | null;
bot_extensions?: BotExtensionsPayload | null;
/**
* The files browser's folders (a user's own crew and media, and what a
* super admin may open) and the folder it is showing.
*/
storage_folders?: StorageSpecOption[] | null;
storage_folder?: StorageFolderPayload | null;
/**
* The database browser's tables (super admin only) and the first page
* of the one it is showing.
*/
database_tables?: DatabaseTableSummary[] | null;
database_records?: DatabaseRecordsPayload | null;
/**
* What the install's models spent, on the usage page (crew managers
* only).
*/
usage?: UsageOverview | null;
/**
* The open conversation's files (a bot's own, or a workspace's shared
* ones), for the files modal and the chips that name one.
*/
bot_files?: BotFileScopesPayload | null;
/**
* Whether the open conversation's mic (transcription) and read-aloud
* (speech) are turned on for the bot there.
*/
bot_voice?: BotVoicePayload | null;
/**
* The open conversation's text model (its header). The full model
* settings load when the models modal opens.
*/
bot_text_model?: BotTextModel | null;
workspace_extensions?: BotExtensionsPayload | null;
/**
* The bot's own envs, or a workspace's (its settings page). Only a
* super admin gets them: envs are theirs to set.
*/
bot_envs?: ScopedEnvsPayload | null;
workspace_envs?: ScopedEnvsPayload | null;
envs?: {
GOOGLE_CLIENT_ID?: string;
R2_PUBLIC_DOMAIN?: string;
PAYSTACK_PUBLIC_KEY?: string;
};
url?: BunextPageModuleServerReturnURLObject;
};
export type AppContextObject = {
SITE_DATA: SITE_DATA_TYPE;
user: User | null;
user_types: BUN_SQLITE_COBBLE_USER_TYPES[] | null;
appState: AppStateObject;
setAppState: React.Dispatch<React.SetStateAction<AppStateObject>>;
refresh?: number;
setRefresh?: React.Dispatch<React.SetStateAction<number>>;
pageData?: any;
pageProps?: PagePropsType;
query?: PageQueryObject | null;
};
export type AppDataObject = {};
export type AppStateObject = {
data?: AppDataObject;
likes?: string[] | null;
currency?: CurrencyObjectType;
fonts?: any;
setOpenLoginModal?: React.Dispatch<React.SetStateAction<boolean>>;
setOpenSignUpModal?: React.Dispatch<React.SetStateAction<boolean>>;
};
export type CurrencyObjectType = {
symbol: string;
code: string;
multiplier?: number;
icon?: string;
country?: string;
countryCode?: string;
} | null;
export type SITE_DATA_TYPE = {
siteName?: string;
siteSlug?: string;
siteUrl?: string;
currency?: CurrencyObjectType;
currencyOptions?: CurrencyObjectType[];
standardShippingCostInUsd?: number;
};
export type DSQL_RESPONSE = {
success: boolean;
payload?: Object[] | string | any[] | { error: string } | null;
};
export type DSQL_POST_QUERY_OBJECT = {
action: string;
table: string;
data?: object;
identifierColumnName?: string;
identifierValue?: string;
duplicateColumnName?: string;
duplicateColumnValue?: string;
update?: boolean;
};
export type AppApiRes = {
success?: boolean;
payload?: any;
result?: any;
msg?: string;
};
export type GithubUserObject = {
login: string;
id: 1;
node_id: string;
avatar_url: string;
gravatar_id: string;
url: string;
html_url: string;
followers_url: string;
following_url: string;
gists_url: string;
starred_url: string;
subscriptions_url: string;
organizations_url: string;
repos_url: string;
events_url: string;
received_events_url: string;
type: string;
site_admin: boolean;
name: string;
company: string;
blog: string;
location: string;
email: string;
hireable: boolean;
bio: string;
twitter_username: string;
public_repos: 2;
public_gists: 1;
followers: 20;
following: 0;
created_at: string;
updated_at: string;
private_gists: 81;
total_private_repos: 100;
owned_private_repos: 100;
disk_usage: 10000;
collaborators: 8;
two_factor_authentication: boolean;
plan: {
name: string;
space: 400;
private_repos: 20;
collaborators: 0;
};
};
export type FileBase64Object = {
fileBase64: string;
fileBase64Full: string;
fileName: string;
fileSize: number;
fileType: string;
};
export type UserType = (typeof UserTypes)[number]["value"];
export const WebSocketEvents = [
"resource",
"error",
"update",
"ready",
"message",
"url",
"success",
/**
* # Client Events
* @description Events sent from Client to Server
*/
"client:ping",
/**
* # Server Events
* @description Events sent from Server to Client
*/
"server:pong",
/**
* A new message in one of the user's bot conversations (`data`: the
* `bot_messages` row)
*/
"server:bot-message",
/**
* A session in one of the user's bot conversations started, was named
* or otherwise changed (`data`: `BotSessionChangedData`)
*/
"server:bot-session",
/**
* A bot joined the crew or one of the user's workspaces (`data`:
* `BotCreatedData`)
*/
"server:bot-created",
/**
* A bot the user could see was deleted (`data`: `BotRemovedData`)
*/
"server:bot-removed",
/**
* A bot's face or status line changed (`data`: `BotUpdatedData`)
*/
"server:bot-updated",
/**
* A workspace the user can see was created (`data`:
* `WorkspaceCreatedData`)
*/
"server:workspace-created",
/**
* A workspace the user could see was deleted (`data`:
* `WorkspaceRemovedData`)
*/
"server:workspace-removed",
/**
* A workspace the user can see changed (`data`: `WorkspaceUpdatedData`)
*/
"server:workspace-updated",
/**
* A message's emoji reactions changed (`data`: `BotMessageReactionData`)
*/
"server:bot-reaction",
/**
* A running job took a step (`data`: `BotJobUpdateData`)
*/
"server:bot-job-update",
/**
* A computer's container changed state, e.g. finished setting up
* (`data`: `ComputerWithStatus`)
*/
"server:computer-updated",
] as const;
export type WebSocketDataType = {
event: (typeof WebSocketEvents)[number];
data?: any;
error?: string;
message?: string;
};
export type WebsocketRoomType = (typeof WebsocketRooms)[number]["value"];
export type UserAssignmentFnParams = {
actor_user_types?: BUN_SQLITE_COBBLE_USER_TYPES[] | null;
target_user_type: UserType;
target_user_types?: UserType[];
action: "assign" | "delete";
assignment_matrix?: UserTypeAssignmentMatrixType;
deletion_matrix?: UserTypeAssignmentMatrixType;
debug?: boolean;
};
export type UserTypeAssignmentRules = {
all?: boolean;
same_as?: UserType;
allowed_targets?: UserType[];
excluded_targets?: UserType[];
};
export type UserTypeAssignmentEntry = {
allowed_actors?:
| UserType[]
| Partial<Record<UserType, UserTypeAssignmentRules>>;
excluded_targets?: UserType[];
};
export type UserTypeAssignmentMatrixType = Record<
UserType,
UserTypeAssignmentEntry
>;
/**
* The type-matrix shapes, for any set of types (`BotTypeAssignmentMatrix`,
* `BotTypeTargetMatrix`). Actors may be user types or bot types.
*/
export type TypeAssignmentRules<A extends string = string> = {
all?: boolean;
same_as?: A;
allowed_targets?: string[];
excluded_targets?: string[];
};
export type TypeAssignmentEntry<A extends string = string> = {
allowed_actors?: A[] | Partial<Record<A, TypeAssignmentRules<A>>>;
excluded_targets?: string[];
};
export type TypeAssignmentMatrixType<
T extends string,
A extends string = string,
> = Record<T, TypeAssignmentEntry<A>>;
export type BotType = (typeof BotTypes)[number]["value"];
export type BotPermission = (typeof BotPermissions)[number]["value"];
export type LoginFormObject = {
username_or_email?: string;
password?: string;
};
export type SignupFormObject = {
first_name?: string;
last_name?: string;
username?: string;
email?: string;
password?: string;
confirm_password?: string;
};
export type PasswordFormObject = {
current_password?: string;
new_password?: string;
confirm_password?: string;
};
export type ContactFormObject = {
name?: string;
email?: string;
subject?: string;
message?: string;
};
export type ApiReqParams<
T extends BUN_SQLITE_COBBLE_ALL_TYPEDEFS = BUN_SQLITE_COBBLE_ALL_TYPEDEFS,
> = {
login?: {
email?: string;
email_or_username?: string;
password?: string;
};
signup?: {
first_name?: string;
last_name?: string;
username?: string;
email?: string;
password?: string;
};
password_update?: {
current_password?: string;
new_password?: string;
};
new_password?: string;
google_token?: string;
contact?: {
name?: string;
email?: string;
subject?: string;
message?: string;
};
image_url?: string;
sql_query?: ServerQueryParam<T>;
sql_select_params?: any;
sql_insert_params?: any;
count?: boolean;
insert_data?: BUN_SQLITE_COBBLE_ALL_TYPEDEFS[];
update_data?: BUN_SQLITE_COBBLE_ALL_TYPEDEFS;
update_on_duplicate?: boolean;
user_id?: string | number | null;
dependent_id?: string | number | null;
media_base_64?: string;
media_base_64_data_url?: string;
media_paradigms?: MediaParadigmType[];
media_paradigm?: MediaParadigmType;
media_type?: (typeof MediaTypes)[number]["value"];
media_name?: string;
is_media_primary?: boolean;
reauth?: boolean;
search_terms?: string[];
amount?: number;
id?: string | number;
ids?: (string | number)[];
paystack_payment_reference?: string;
target_user_type?: UserType;
page?: number;
/**
* Search Terms
*/
search_term_first_name?: string | string[];
search_term_last_name?: string | string[];
search_term_email?: string | string[];
search_term_id?: string | string[];
search_term_user_type?: string | string[];
text?: string;
return_media_text_content?: boolean;
media?: BUN_SQLITE_COBBLE_MEDIA;
backup_name?: string;
};
export type GoogleCredentialResponse = {
credential?: string;
};
export type GoogleWindow = globalThis.Window & {
google?: {
accounts?: {
id?: {
initialize: (params: {
client_id: string;
callback: (response: GoogleCredentialResponse) => void;
}) => void;
renderButton: (
parent: HTMLElement,
options: Record<string, string | number | boolean>,
) => void;
};
};
};
};
export type UserAuthReturn = {
success: boolean;
msg?: string;
user?: User | null;
user_types?: BUN_SQLITE_COBBLE_USER_TYPES[] | null;
};
export type SQLInsertGenValueType =
| string
| number
| Float32Array<ArrayBuffer>
| Buffer<ArrayBuffer>
| null;
export type MediaType = (typeof MediaTypes)[number]["value"];
export type MediaParadigm = (typeof MediaParadigms)[number]["value"];
export type TableType = (typeof BunSQLiteTables)[number];
export type AdminCrudAPIParams = {
table: TableType;
id?: string | number;
user: User;
user_types: BUN_SQLITE_COBBLE_USER_TYPES[];
body?: ApiReqParams;
query?: ApiReqParams;
req: Request;
};
export type ClientAdminCrudParams<
T extends BUN_SQLITE_COBBLE_ALL_TYPEDEFS = BUN_SQLITE_COBBLE_ALL_TYPEDEFS,
> = {
action: "get" | "insert" | "update" | "delete";
table: TableType;
id?: string | number;
sql_query?: ServerQueryParam<T>;
sql_select_params?: any;
sql_insert_params?: any;
count?: boolean;
insert_data?: T[];
update_data?: T;
update_on_duplicate?: boolean;
request_query?: ApiReqParams<T>;
request_body?: ApiReqParams<T>;
};
export type AdminFetchParams<T extends {} = BUN_SQLITE_COBBLE_ALL_TYPEDEFS> = {
url: string;
query?: ApiReqParams<T>;
body?: ApiReqParams<T>;
method?: "PUT" | "DELETE" | "POST" | "GET";
};
export type UserFormObject = BUN_SQLITE_COBBLE_USERS & {
user_types?: UserType[];
password?: string;
confirm_password?: string;
};
export type PageQueryObject = {
user_id?: string;
bot_id?: string;
workspace_id?: string;
computer_id?: string;
event_id?: string;
user_type?: UserType;
};
export type MediaParadigmType = (typeof MediaParadigms)[number]["value"];
export type AddEventFormMediaObject = BUN_SQLITE_COBBLE_MEDIA &
ImageInputToBase64FunctionReturn;
export type MediaDataType =
| Blob
| File
| NodeJS.TypedArray
| ArrayBufferLike
| string
| Bun.BlobPart[]
| Bun.Archive
| ReadableStream
| Request
| Response;
export type FeatureItem = {
Icon: LucideIcon;
title: string;
description: string;
};
/**
* One device with push notifications on, as Settings lists it. Never the
* endpoint: that is a capability URL held by the browser.
*/
export type PushDeviceOverview = {
id: number;
device: string;
created_at: number;
last_used_at: number;
last_error: string | null;
};
export type PushOverview = {
/**
* The install's VAPID public key, which a subscribing browser needs.
*/
public_key: string | null;
subscriptions: PushDeviceOverview[];
};