Add bot schedules (routines), open Activity, add Help and a Desktop computer view

Bots create, list, update and delete schedules (cron_jobs, Bun.cron in UTC);
a per-minute cron queues due runs as tasks. Routines, Activity (super admins)
and Help get their own rail aside. Help covers familiar problems, starting
with signing in to Google through Cookie-Editor over the new Desktop (noVNC)
view.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-19 10:52:32 +01:00
co-authored by Claude Opus 5.5
parent f24c0d7e82
commit c44048dbab
62 changed files with 1904 additions and 78 deletions
+111
View File
@@ -709,6 +709,117 @@ const schema: BUN_SQLITE_DatabaseSchemaType = {
},
],
},
{
tableName: "cron_jobs",
tableDescription: `A bot's schedules (routines in the UI): a brief queued as a task on a cron schedule, in UTC. The \`run-cron-jobs\` cron queues the due ones every minute`,
fields: [
{
fieldName: "user_id",
fieldDescription: `The owner`,
dataType: "INTEGER",
foreignKey: {
cascadeDelete: true,
destinationTableName: "users",
destinationTableColumnName: "id",
destinationTableColumnType: "INTEGER",
foreignKeyName: "cron_jobs_user_fk",
},
},
{
fieldName: "bot_id",
fieldDescription: `The bot that runs it`,
dataType: "INTEGER",
foreignKey: {
cascadeDelete: true,
destinationTableName: "bots",
destinationTableColumnName: "id",
destinationTableColumnType: "INTEGER",
foreignKeyName: "cron_jobs_bot_fk",
},
},
{
fieldName: "workspace_id",
fieldDescription: `The workspace it runs in (context, computers, models, and the conversation its results go to); null for the bot's own chat`,
dataType: "INTEGER",
foreignKey: {
cascadeDelete: true,
destinationTableName: "workspaces",
destinationTableColumnName: "id",
destinationTableColumnType: "INTEGER",
foreignKeyName: "cron_jobs_workspace_fk",
},
},
{
fieldName: "title",
dataType: "TEXT",
},
{
fieldName: "instructions",
fieldDescription: `The brief each run gets (markdown), like a task's`,
dataType: "TEXT",
},
{
fieldName: "schedule",
fieldDescription: `A Bun.cron expression (5 fields or a nickname like @daily), in UTC`,
dataType: "TEXT",
},
{
fieldName: "computer_id",
fieldDescription: `The computer its runs use; null for the bot's current one when it runs. Not a foreign key`,
dataType: "INTEGER",
},
{
fieldName: "enabled",
dataType: "INTEGER",
options: [0, 1],
defaultValue: 1,
},
{
fieldName: "max_runs",
fieldDescription: `Turns itself off after this many runs (1 for a one-off); null runs until stopped`,
dataType: "INTEGER",
},
{
fieldName: "run_count",
dataType: "INTEGER",
defaultValue: 0,
},
{
fieldName: "next_run_at",
fieldDescription: `Unix ms of the next run; null once it can't run again`,
dataType: "INTEGER",
},
{
fieldName: "last_run_at",
fieldDescription: `Unix ms of the last run queued`,
dataType: "INTEGER",
},
{
fieldName: "last_job_id",
fieldDescription: `The \`bots_queue\` job of the last run. Not a foreign key: finished jobs are pruned`,
dataType: "INTEGER",
},
{
fieldName: "last_error",
fieldDescription: `Why the last run couldn't be queued or was skipped; cleared by the next run`,
dataType: "TEXT",
},
],
indexes: [
{
indexName: "idx_cron_jobs_enabled_next_run_at",
indexTableFields: ["enabled", "next_run_at"],
},
{
indexName: "idx_cron_jobs_bot_id",
indexTableFields: ["bot_id"],
},
{
indexName: "idx_cron_jobs_user_id",
indexTableFields: ["user_id"],
},
],
},
{
tableName: "workspaces",
fields: [
+65 -2
View File
@@ -12,6 +12,7 @@ export const BunSQLiteTables = [
"bot_task_steps",
"bots_queue",
"bots_queue_updates",
"cron_jobs",
"workspaces",
"workspace_bots",
"bot_message_media",
@@ -466,6 +467,68 @@ export type BUN_SQLITE_COBBLE_BOTS_QUEUE_UPDATES = {
metadata?: string;
}
export type BUN_SQLITE_COBBLE_CRON_JOBS = {
/**
* The unique identifier of the record.
*/
id?: number | "";
/**
* The time when the record was created. (Unix Timestamp)
*/
created_at?: number | "";
/**
* The time when the record was updated. (Unix Timestamp)
*/
updated_at?: number | "";
/**
* The owner
*/
user_id?: number | "";
/**
* The bot that runs it
*/
bot_id?: number | "";
/**
* The workspace it runs in (context, computers, models, and the conversation its results go to); null for the bot's own chat
*/
workspace_id?: number | "";
title?: string;
/**
* The brief each run gets (markdown), like a task's
*/
instructions?: string;
/**
* A Bun.cron expression (5 fields or a nickname like @daily), in UTC
*/
schedule?: string;
/**
* The computer its runs use; null for the bot's current one when it runs. Not a foreign key
*/
computer_id?: number | "";
enabled?: 0 | 1 | "";
/**
* Turns itself off after this many runs (1 for a one-off); null runs until stopped
*/
max_runs?: number | "";
run_count?: number | "";
/**
* Unix ms of the next run; null once it can't run again
*/
next_run_at?: number | "";
/**
* Unix ms of the last run queued
*/
last_run_at?: number | "";
/**
* The `bots_queue` job of the last run. Not a foreign key: finished jobs are pruned
*/
last_job_id?: number | "";
/**
* Why the last run couldn't be queued or was skipped; cleared by the next run
*/
last_error?: string;
}
export type BUN_SQLITE_COBBLE_WORKSPACES = {
/**
* The unique identifier of the record.
@@ -587,7 +650,7 @@ export type BUN_SQLITE_COBBLE_CONTAINERS = {
/**
* Last known docker state
*/
status?: "creating" | "failed" | "created" | "running" | "paused" | "restarting" | "exited" | "removing" | "dead" | "unknown" | "";
status?: "creating" | "failed" | "created" | "starting" | "running" | "unhealthy" | "paused" | "restarting" | "exited" | "removing" | "dead" | "unknown" | "";
/**
* Extra docker details (ports, volumes, env names, labels)
*/
@@ -977,4 +1040,4 @@ export type BUN_SQLITE_COBBLE_ENVS = {
expose_to_computers?: 0 | 1 | "";
}
export type BUN_SQLITE_COBBLE_ALL_TYPEDEFS = BUN_SQLITE_COBBLE_USERS & BUN_SQLITE_COBBLE_USER_TYPES & BUN_SQLITE_COBBLE_SSO_LOGIN_CODES & BUN_SQLITE_COBBLE_USER_PASSWORDS & BUN_SQLITE_COBBLE_MEDIA & BUN_SQLITE_COBBLE_MEDIA_PARADIGMS & BUN_SQLITE_COBBLE_BOTS & BUN_SQLITE_COBBLE_BOT_SESSIONS & BUN_SQLITE_COBBLE_BOT_MESSAGES & BUN_SQLITE_COBBLE_BOT_TASKS & BUN_SQLITE_COBBLE_BOT_TASK_STEPS & BUN_SQLITE_COBBLE_BOTS_QUEUE & BUN_SQLITE_COBBLE_BOTS_QUEUE_UPDATES & BUN_SQLITE_COBBLE_WORKSPACES & BUN_SQLITE_COBBLE_WORKSPACE_BOTS & BUN_SQLITE_COBBLE_BOT_MESSAGE_MEDIA & BUN_SQLITE_COBBLE_CONTAINERS & BUN_SQLITE_COBBLE_COMPUTERS & BUN_SQLITE_COBBLE_BOT_COMPUTERS & BUN_SQLITE_COBBLE_WORKSPACE_COMPUTERS & BUN_SQLITE_COBBLE_HARNESS_PROVIDERS & BUN_SQLITE_COBBLE_HARNESS_MODELS & BUN_SQLITE_COBBLE_HARNESS_SETTINGS & BUN_SQLITE_COBBLE_BOT_HARNESS_SETTINGS & BUN_SQLITE_COBBLE_WORKSPACE_HARNESS_SETTINGS & BUN_SQLITE_COBBLE_LOGS & BUN_SQLITE_COBBLE_ENVS
export type BUN_SQLITE_COBBLE_ALL_TYPEDEFS = BUN_SQLITE_COBBLE_USERS & BUN_SQLITE_COBBLE_USER_TYPES & BUN_SQLITE_COBBLE_SSO_LOGIN_CODES & BUN_SQLITE_COBBLE_USER_PASSWORDS & BUN_SQLITE_COBBLE_MEDIA & BUN_SQLITE_COBBLE_MEDIA_PARADIGMS & BUN_SQLITE_COBBLE_BOTS & BUN_SQLITE_COBBLE_BOT_SESSIONS & BUN_SQLITE_COBBLE_BOT_MESSAGES & BUN_SQLITE_COBBLE_BOT_TASKS & BUN_SQLITE_COBBLE_BOT_TASK_STEPS & BUN_SQLITE_COBBLE_BOTS_QUEUE & BUN_SQLITE_COBBLE_BOTS_QUEUE_UPDATES & BUN_SQLITE_COBBLE_CRON_JOBS & BUN_SQLITE_COBBLE_WORKSPACES & BUN_SQLITE_COBBLE_WORKSPACE_BOTS & BUN_SQLITE_COBBLE_BOT_MESSAGE_MEDIA & BUN_SQLITE_COBBLE_CONTAINERS & BUN_SQLITE_COBBLE_COMPUTERS & BUN_SQLITE_COBBLE_BOT_COMPUTERS & BUN_SQLITE_COBBLE_WORKSPACE_COMPUTERS & BUN_SQLITE_COBBLE_HARNESS_PROVIDERS & BUN_SQLITE_COBBLE_HARNESS_MODELS & BUN_SQLITE_COBBLE_HARNESS_SETTINGS & BUN_SQLITE_COBBLE_BOT_HARNESS_SETTINGS & BUN_SQLITE_COBBLE_WORKSPACE_HARNESS_SETTINGS & BUN_SQLITE_COBBLE_LOGS & BUN_SQLITE_COBBLE_ENVS