@saadnvd1/agent-os 0.3.596 → 0.3.597
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/lib/db/migration-types.ts +15 -0
- package/lib/db/migrations/0001_add_group_path_to_sessions.ts +11 -0
- package/lib/db/migrations/0002_add_agent_type_to_sessions.ts +11 -0
- package/lib/db/migrations/0003_add_worktree_columns_to_sessions.ts +12 -0
- package/lib/db/migrations/0004_add_pr_tracking_to_sessions.ts +11 -0
- package/lib/db/migrations/0005_add_group_path_index.ts +11 -0
- package/lib/db/migrations/0006_add_orchestration_columns_to_sessions.ts +16 -0
- package/lib/db/migrations/0007_add_auto_approve_to_sessions.ts +11 -0
- package/lib/db/migrations/0008_add_dev_server_columns.ts +19 -0
- package/lib/db/migrations/0009_add_project_id_to_sessions.ts +17 -0
- package/lib/db/migrations/0010_add_project_id_to_dev_servers.ts +36 -0
- package/lib/db/migrations/0011_add_tmux_name_to_sessions.ts +13 -0
- package/lib/db/migrations/0012_add_initial_prompt_to_projects.ts +9 -0
- package/lib/db/migrations/0013_add_project_repositories_table.ts +22 -0
- package/lib/db/migrations/0014_add_hosts.ts +23 -0
- package/lib/db/migrations/0015_add_workspaces.ts +18 -0
- package/lib/db/migrations/0016_add_task_columns_to_sessions.ts +13 -0
- package/lib/db/migrations/0017_add_bus_messages.ts +24 -0
- package/lib/db/migrations/0018_add_chat.ts +23 -0
- package/lib/db/migrations/0019_add_lumifyhub.ts +36 -0
- package/lib/db/migrations/0020_add_lumifyhub_published_docs.ts +18 -0
- package/lib/db/migrations/0021_add_chat_access.ts +14 -0
- package/lib/db/migrations/0022_add_last_seen.ts +10 -0
- package/lib/db/migrations/0023_mark_existing_sessions_seen.ts +12 -0
- package/lib/db/migrations/0024_add_stacks.ts +49 -0
- package/lib/db/migrations/0025_add_stack_item_attempts.ts +16 -0
- package/lib/db/migrations/0026_add_workspace_orchestrator.ts +47 -0
- package/lib/db/migrations/0027_add_devices_and_settings.ts +28 -0
- package/lib/db/migrations/0028_add_orchestrator_acting.ts +70 -0
- package/lib/db/migrations/0029_add_orchestrator_asks_and_pause.ts +81 -0
- package/lib/db/migrations/0030_add_sessions_archived_at.ts +14 -0
- package/lib/db/migrations/0031_add_stack_item_restacked_heads.ts +22 -0
- package/lib/db/migrations/0032_add_sessions_pinned.ts +12 -0
- package/lib/db/migrations/0033_add_program_status.ts +18 -0
- package/lib/db/migrations/0034_add_session_names.ts +21 -0
- package/lib/db/migrations/0035_add_artifacts.ts +23 -0
- package/lib/db/migrations/0036_add_chat_queue.ts +26 -0
- package/lib/db/migrations/0037_add_chat_plan_and_turns.ts +39 -0
- package/lib/db/migrations/0038_add_schedules.ts +56 -0
- package/lib/db/migrations/0039_add_session_name_source.ts +21 -0
- package/lib/db/migrations/0040_add_schedule_targets_and_phone_notify.ts +41 -0
- package/lib/db/migrations/0041_add_task_setup.ts +17 -0
- package/lib/db/migrations/0042_add_host_links_and_moved_tasks.ts +29 -0
- package/lib/db/migrations/0043_scratch_project.ts +14 -0
- package/lib/db/migrations/0044_chat_item_kind.ts +21 -0
- package/lib/db/migrations/0045_change_versions.ts +13 -0
- package/lib/db/migrations/0046_session_port_slots.ts +21 -0
- package/lib/db/migrations/0047_pin_orchestrators.ts +12 -0
- package/lib/db/migrations/0048_session_database.ts +15 -0
- package/lib/db/migrations/0049_peer_mirror.ts +14 -0
- package/lib/db/migrations/0050_task_queue.ts +44 -0
- package/lib/db/migrations/0051_chat_queue_sent_by.ts +16 -0
- package/lib/db/migrations/0052_sessions_chat_restarted.ts +17 -0
- package/lib/db/migrations/0053_brief_amendments_failure_sha_ask_raised_by.ts +37 -0
- package/lib/db/migrations/0054_sessions_chat_tools_digest.ts +15 -0
- package/lib/db/migrations/0055_sessions_merge_armed_and_rebase.ts +25 -0
- package/lib/db/migrations/0056_orchestrator_rules.ts +39 -0
- package/lib/db/migrations/0057_task_pr_wakes.ts +34 -0
- package/lib/db/migrations/0058_away_mode.ts +71 -0
- package/lib/db/migrations/0059_gate_failure_commits.ts +33 -0
- package/lib/db/migrations/0060_check_runs_and_compactions.ts +44 -0
- package/lib/db/migrations/0061_model_routing.ts +30 -0
- package/lib/db/migrations/0062_sessions_quick_of.ts +19 -0
- package/lib/db/migrations/0063_one_off_schedules.ts +16 -0
- package/lib/db/migrations/0064_chat_compactions_phase.ts +15 -0
- package/lib/db/migrations/0065_orchestrator_triage.ts +23 -0
- package/lib/db/migrations/0066_workspace_orch_mcp_servers.ts +16 -0
- package/lib/db/migrations/0067_orchestrator_event_log_suppressed.ts +14 -0
- package/lib/db/migrations/0068_usage_calls_and_rollups.ts +74 -0
- package/lib/db/migrations/0069_session_logs.ts +26 -0
- package/lib/db/migrations/0070_chat_items_running.ts +15 -0
- package/lib/db/migrations/0071_devices_push.ts +29 -0
- package/lib/db/migrations/0072_push_outbox.ts +33 -0
- package/lib/db/migrations/0073_orchestrated_task_moves.ts +27 -0
- package/lib/db/migrations/0074_held_task_replies.ts +27 -0
- package/lib/db/migrations/0075_plan_only_tasks.ts +17 -0
- package/lib/db/migrations/0076_welcome_backfill.ts +16 -0
- package/lib/db/migrations/0077_simulator_leases.ts +21 -0
- package/lib/db/migrations/0078_orchestrator_questions.ts +34 -0
- package/lib/db/migrations/0079_task_queue_agent.ts +13 -0
- package/lib/db/migrations/0080_recipes.ts +129 -0
- package/lib/db/migrations/0081_schedules_into_recipes.ts +18 -0
- package/lib/db/migrations/0082_session_shelf_times.ts +23 -0
- package/lib/db/migrations/0083_native_devices_can_approve.ts +18 -0
- package/lib/db/migrations/0084_approval_audit.ts +20 -0
- package/lib/db/migrations/0085_experiment_usage.ts +35 -0
- package/lib/db/migrations/0086_learning_cards.ts +28 -0
- package/lib/db/migrations/0087_plan_pieces_reconcile.ts +29 -0
- package/lib/db/migrations/0088_shared_links.ts +25 -0
- package/lib/db/migrations/0089_passkeys_device_keys.ts +23 -0
- package/lib/db/migrations/20261014T0900_task_scheduling.ts +57 -0
- package/lib/db/migrations/20261014T1235_placed_mirror_started_by.ts +19 -0
- package/lib/db/migrations/20261014T1600_queued_task_messages.ts +21 -0
- package/lib/db/migrations/20261014T1800_task_starter_device.ts +20 -0
- package/lib/db/migrations/20261014T1900_pause_note.ts +13 -0
- package/lib/db/migrations/20261014T2000_chat_bookmarks.ts +33 -0
- package/lib/db/migrations/20261014T2100_gate_failure_ask_held.ts +18 -0
- package/lib/db/migrations/README.md +35 -0
- package/lib/db/migrations-legacy-checksums.json +9 -8
- package/lib/db/migrations-split-snapshot.json +1759 -0
- package/lib/db/migrations.ts +76 -2337
- package/package.json +6 -3
- package/scripts/check +1 -0
- package/scripts/gen-migrations-index.mjs +44 -0
- package/scripts/screenshots/demo.ts +5 -1
- package/scripts/screenshots/run.ts +5 -1
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 29,
|
|
5
|
+
name: "add_orchestrator_asks_and_pause",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// Items the orchestrator parks for Saad. One open ask per subject (a
|
|
8
|
+
// task, the brakes, a title it raised), so a repeat escalation updates
|
|
9
|
+
// it instead of adding another. An approval of a gate or brake ask is
|
|
10
|
+
// spent once (used_at), on the commit it was asked about (sha).
|
|
11
|
+
db.exec(`
|
|
12
|
+
CREATE TABLE IF NOT EXISTS orchestrator_asks (
|
|
13
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
14
|
+
workspace_id TEXT NOT NULL,
|
|
15
|
+
subject TEXT NOT NULL,
|
|
16
|
+
kind TEXT NOT NULL,
|
|
17
|
+
title TEXT NOT NULL,
|
|
18
|
+
detail TEXT NOT NULL DEFAULT '',
|
|
19
|
+
link TEXT,
|
|
20
|
+
sha TEXT,
|
|
21
|
+
status TEXT NOT NULL DEFAULT 'open',
|
|
22
|
+
answer TEXT,
|
|
23
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
24
|
+
resolved_at TEXT,
|
|
25
|
+
used_at TEXT,
|
|
26
|
+
brake_key TEXT
|
|
27
|
+
)
|
|
28
|
+
`);
|
|
29
|
+
db.exec(
|
|
30
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_orchestrator_asks_open
|
|
31
|
+
ON orchestrator_asks(workspace_id, subject) WHERE status = 'open'`
|
|
32
|
+
);
|
|
33
|
+
db.exec(
|
|
34
|
+
`CREATE INDEX IF NOT EXISTS idx_orchestrator_asks_workspace
|
|
35
|
+
ON orchestrator_asks(workspace_id, status)`
|
|
36
|
+
);
|
|
37
|
+
// While set, the orchestrator acts on nothing: events queue and its
|
|
38
|
+
// acting tools refuse.
|
|
39
|
+
db.exec(`ALTER TABLE workspaces ADD COLUMN orch_paused_at TEXT`);
|
|
40
|
+
// Proof a person approves: a paired device may answer asks only once
|
|
41
|
+
// Saad lets it, and approvals that matter need a passkey assertion
|
|
42
|
+
// (user verification) on a challenge bound to the one item.
|
|
43
|
+
db.exec(
|
|
44
|
+
`ALTER TABLE devices ADD COLUMN can_approve INTEGER NOT NULL DEFAULT 0`
|
|
45
|
+
);
|
|
46
|
+
db.exec(`
|
|
47
|
+
CREATE TABLE IF NOT EXISTS passkeys (
|
|
48
|
+
id TEXT PRIMARY KEY,
|
|
49
|
+
public_key BLOB NOT NULL,
|
|
50
|
+
counter INTEGER NOT NULL DEFAULT 0,
|
|
51
|
+
transports TEXT,
|
|
52
|
+
rp_id TEXT NOT NULL,
|
|
53
|
+
name TEXT NOT NULL,
|
|
54
|
+
registered_via TEXT,
|
|
55
|
+
registered_from TEXT,
|
|
56
|
+
user_agent TEXT,
|
|
57
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
58
|
+
last_used_at TEXT,
|
|
59
|
+
revoked_at TEXT
|
|
60
|
+
)
|
|
61
|
+
`);
|
|
62
|
+
db.exec(`
|
|
63
|
+
CREATE TABLE IF NOT EXISTS presence_challenges (
|
|
64
|
+
challenge TEXT PRIMARY KEY,
|
|
65
|
+
kind TEXT NOT NULL,
|
|
66
|
+
purpose TEXT NOT NULL,
|
|
67
|
+
binding TEXT NOT NULL,
|
|
68
|
+
rp_id TEXT NOT NULL,
|
|
69
|
+
expires_at INTEGER NOT NULL,
|
|
70
|
+
used_at INTEGER
|
|
71
|
+
)
|
|
72
|
+
`);
|
|
73
|
+
db.exec(`
|
|
74
|
+
CREATE TABLE IF NOT EXISTS passkey_enrollments (
|
|
75
|
+
code_hash TEXT PRIMARY KEY,
|
|
76
|
+
expires_at INTEGER NOT NULL,
|
|
77
|
+
used_at INTEGER
|
|
78
|
+
)
|
|
79
|
+
`);
|
|
80
|
+
},
|
|
81
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 30,
|
|
5
|
+
name: "add_sessions_archived_at",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// Done sessions leave the sidebar but are never deleted, so their
|
|
8
|
+
// history and chat items stay.
|
|
9
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN archived_at TEXT`);
|
|
10
|
+
db.exec(
|
|
11
|
+
`CREATE INDEX IF NOT EXISTS idx_sessions_archived_at ON sessions(archived_at)`
|
|
12
|
+
);
|
|
13
|
+
},
|
|
14
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 31,
|
|
5
|
+
name: "add_stack_item_restacked_heads",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// A branch AgentOS rebased itself: its head before (the commit the
|
|
8
|
+
// task's code review covered) and after (the head AgentOS pushed).
|
|
9
|
+
// Each column checked, so a run cut off between the two can't be
|
|
10
|
+
// marked applied with one missing.
|
|
11
|
+
const cols = new Set(
|
|
12
|
+
(
|
|
13
|
+
db.prepare(`PRAGMA table_info(stack_items)`).all() as {
|
|
14
|
+
name: string;
|
|
15
|
+
}[]
|
|
16
|
+
).map((c) => c.name)
|
|
17
|
+
);
|
|
18
|
+
for (const col of ["restacked_from", "restacked_to"])
|
|
19
|
+
if (!cols.has(col))
|
|
20
|
+
db.exec(`ALTER TABLE stack_items ADD COLUMN ${col} TEXT`);
|
|
21
|
+
},
|
|
22
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 32,
|
|
5
|
+
name: "add_sessions_pinned",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// Pinned sessions sit on their own shelf at the top of the sidebar.
|
|
8
|
+
db.exec(
|
|
9
|
+
`ALTER TABLE sessions ADD COLUMN pinned INTEGER NOT NULL DEFAULT 0`
|
|
10
|
+
);
|
|
11
|
+
},
|
|
12
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 33,
|
|
5
|
+
name: "add_program_status",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// What programs in a terminal report about themselves (OSC 7501),
|
|
8
|
+
// by tmux session: kept so a restart doesn't forget a finished or
|
|
9
|
+
// blocked session.
|
|
10
|
+
db.exec(`
|
|
11
|
+
CREATE TABLE IF NOT EXISTS program_status (
|
|
12
|
+
session_name TEXT PRIMARY KEY,
|
|
13
|
+
records TEXT NOT NULL,
|
|
14
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
15
|
+
)
|
|
16
|
+
`);
|
|
17
|
+
},
|
|
18
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 34,
|
|
5
|
+
name: "add_session_names",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// Names a session had before it was renamed, so a message sent to
|
|
8
|
+
// an old name still reaches it.
|
|
9
|
+
db.exec(`
|
|
10
|
+
CREATE TABLE IF NOT EXISTS session_names (
|
|
11
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
12
|
+
session_id TEXT NOT NULL,
|
|
13
|
+
name TEXT NOT NULL,
|
|
14
|
+
renamed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
15
|
+
)
|
|
16
|
+
`);
|
|
17
|
+
db.exec(
|
|
18
|
+
`CREATE INDEX IF NOT EXISTS idx_session_names_session ON session_names(session_id)`
|
|
19
|
+
);
|
|
20
|
+
},
|
|
21
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 35,
|
|
5
|
+
name: "add_artifacts",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// Pages a chat agent showed with html_render. The HTML lives in a file
|
|
8
|
+
// under ~/.agent-os/artifacts; the row says whose it is and what it's
|
|
9
|
+
// called.
|
|
10
|
+
db.exec(`
|
|
11
|
+
CREATE TABLE IF NOT EXISTS artifacts (
|
|
12
|
+
id TEXT PRIMARY KEY,
|
|
13
|
+
session_id TEXT NOT NULL,
|
|
14
|
+
title TEXT NOT NULL,
|
|
15
|
+
path TEXT NOT NULL,
|
|
16
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
17
|
+
)
|
|
18
|
+
`);
|
|
19
|
+
db.exec(
|
|
20
|
+
`CREATE INDEX IF NOT EXISTS idx_artifacts_session ON artifacts(session_id, created_at)`
|
|
21
|
+
);
|
|
22
|
+
},
|
|
23
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 36,
|
|
5
|
+
name: "add_chat_queue",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// Messages written while a chat turn runs, sent in order once it ends.
|
|
8
|
+
db.exec(`
|
|
9
|
+
CREATE TABLE IF NOT EXISTS chat_queue (
|
|
10
|
+
session_id TEXT NOT NULL,
|
|
11
|
+
id TEXT NOT NULL,
|
|
12
|
+
position REAL NOT NULL,
|
|
13
|
+
text TEXT NOT NULL,
|
|
14
|
+
images TEXT,
|
|
15
|
+
image_count INTEGER NOT NULL DEFAULT 0,
|
|
16
|
+
created_at INTEGER NOT NULL,
|
|
17
|
+
PRIMARY KEY (session_id, id)
|
|
18
|
+
)
|
|
19
|
+
`);
|
|
20
|
+
db.exec(
|
|
21
|
+
`CREATE INDEX IF NOT EXISTS idx_chat_queue_session ON chat_queue(session_id, position)`
|
|
22
|
+
);
|
|
23
|
+
// The agent's guess at the next message, shown in an empty composer.
|
|
24
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN chat_suggestion TEXT`);
|
|
25
|
+
},
|
|
26
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 37,
|
|
5
|
+
name: "add_chat_plan_and_turns",
|
|
6
|
+
// One transaction, so a crash part-way leaves nothing to skip as
|
|
7
|
+
// "duplicate column" on the next start.
|
|
8
|
+
up: (db) =>
|
|
9
|
+
db.transaction(() => {
|
|
10
|
+
// Plan mode is remembered per session; the context meter's last
|
|
11
|
+
// reading survives a reload; and the agent's running totals at its
|
|
12
|
+
// last turn tell what the next turn added.
|
|
13
|
+
db.exec(
|
|
14
|
+
`ALTER TABLE sessions ADD COLUMN chat_plan INTEGER NOT NULL DEFAULT 0`
|
|
15
|
+
);
|
|
16
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN chat_context TEXT`);
|
|
17
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN chat_usage TEXT`);
|
|
18
|
+
// What each chat turn cost, kept with the session's name and
|
|
19
|
+
// workspace so the history outlives the session.
|
|
20
|
+
db.exec(`
|
|
21
|
+
CREATE TABLE IF NOT EXISTS chat_turns (
|
|
22
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
23
|
+
session_id TEXT NOT NULL,
|
|
24
|
+
session_name TEXT NOT NULL,
|
|
25
|
+
workspace_id TEXT,
|
|
26
|
+
at INTEGER NOT NULL,
|
|
27
|
+
cost_usd REAL NOT NULL,
|
|
28
|
+
input_tokens INTEGER NOT NULL,
|
|
29
|
+
output_tokens INTEGER NOT NULL,
|
|
30
|
+
cache_read_tokens INTEGER NOT NULL,
|
|
31
|
+
cache_write_tokens INTEGER NOT NULL
|
|
32
|
+
)
|
|
33
|
+
`);
|
|
34
|
+
db.exec(`CREATE INDEX IF NOT EXISTS idx_chat_turns_at ON chat_turns(at)`);
|
|
35
|
+
db.exec(
|
|
36
|
+
`CREATE INDEX IF NOT EXISTS idx_chat_turns_session ON chat_turns(session_id, id)`
|
|
37
|
+
);
|
|
38
|
+
})(),
|
|
39
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 38,
|
|
5
|
+
name: "add_schedules",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// Cron schedules that start agent work, and every run they made or
|
|
8
|
+
// skipped. A run's (schedule, slot) is unique: claiming the row is
|
|
9
|
+
// what stops a slot from running twice. Runs are never deleted, and a
|
|
10
|
+
// removed schedule is archived, not deleted, so its history stays.
|
|
11
|
+
db.exec(`
|
|
12
|
+
CREATE TABLE IF NOT EXISTS schedules (
|
|
13
|
+
id TEXT PRIMARY KEY,
|
|
14
|
+
workspace_id TEXT NOT NULL,
|
|
15
|
+
project_id TEXT,
|
|
16
|
+
name TEXT NOT NULL,
|
|
17
|
+
cron TEXT NOT NULL,
|
|
18
|
+
timezone TEXT NOT NULL DEFAULT 'America/Chicago',
|
|
19
|
+
prompt TEXT NOT NULL,
|
|
20
|
+
kind TEXT NOT NULL,
|
|
21
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
22
|
+
armed_at INTEGER NOT NULL,
|
|
23
|
+
archived_at TEXT,
|
|
24
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
25
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
26
|
+
)
|
|
27
|
+
`);
|
|
28
|
+
db.exec(`
|
|
29
|
+
CREATE TABLE IF NOT EXISTS schedule_runs (
|
|
30
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
31
|
+
schedule_id TEXT NOT NULL,
|
|
32
|
+
slot TEXT NOT NULL,
|
|
33
|
+
slot_at INTEGER NOT NULL,
|
|
34
|
+
trigger TEXT NOT NULL,
|
|
35
|
+
outcome TEXT NOT NULL,
|
|
36
|
+
detail TEXT,
|
|
37
|
+
session_id TEXT,
|
|
38
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
39
|
+
UNIQUE (schedule_id, slot)
|
|
40
|
+
)
|
|
41
|
+
`);
|
|
42
|
+
db.exec(
|
|
43
|
+
`CREATE INDEX IF NOT EXISTS idx_schedule_runs_schedule ON schedule_runs(schedule_id, id)`
|
|
44
|
+
);
|
|
45
|
+
// Which server process ticks the schedules: one row, renewed each
|
|
46
|
+
// tick, so a second server on the same database never runs them.
|
|
47
|
+
db.exec(`
|
|
48
|
+
CREATE TABLE IF NOT EXISTS scheduler_lease (
|
|
49
|
+
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
50
|
+
owner TEXT NOT NULL,
|
|
51
|
+
pid INTEGER NOT NULL,
|
|
52
|
+
heartbeat INTEGER NOT NULL
|
|
53
|
+
)
|
|
54
|
+
`);
|
|
55
|
+
},
|
|
56
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 39,
|
|
5
|
+
name: "add_session_name_source",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// Who named a session: "user" (typed or given explicitly, never
|
|
8
|
+
// renamed for them), "generated" (a title picked from its prompt) or
|
|
9
|
+
// "default" ("Session 4", or a placeholder until a title arrives).
|
|
10
|
+
// One transaction, so a crash part-way leaves nothing to skip.
|
|
11
|
+
db.transaction(() => {
|
|
12
|
+
db.exec(
|
|
13
|
+
`ALTER TABLE sessions ADD COLUMN name_source TEXT NOT NULL DEFAULT 'default'`
|
|
14
|
+
);
|
|
15
|
+
// A session renamed by hand before this keeps its name.
|
|
16
|
+
db.exec(
|
|
17
|
+
`UPDATE sessions SET name_source = 'user' WHERE id IN (SELECT session_id FROM session_names)`
|
|
18
|
+
);
|
|
19
|
+
})();
|
|
20
|
+
},
|
|
21
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 40,
|
|
5
|
+
name: "add_schedule_targets_and_phone_notify",
|
|
6
|
+
// One transaction, so a crash part-way leaves nothing to skip as
|
|
7
|
+
// "duplicate column" on the next start.
|
|
8
|
+
up: (db) =>
|
|
9
|
+
db.transaction(() => {
|
|
10
|
+
// Where phone notifications go. One row; the bot token is never
|
|
11
|
+
// returned by any route or written to a log.
|
|
12
|
+
db.exec(`
|
|
13
|
+
CREATE TABLE IF NOT EXISTS notify_settings (
|
|
14
|
+
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
15
|
+
telegram_token TEXT,
|
|
16
|
+
telegram_chat_id TEXT,
|
|
17
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
18
|
+
)
|
|
19
|
+
`);
|
|
20
|
+
// Every phone notification, sent or waiting out its source's
|
|
21
|
+
// minute, so one held across a restart still goes.
|
|
22
|
+
db.exec(`
|
|
23
|
+
CREATE TABLE IF NOT EXISTS notify_outbox (
|
|
24
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
25
|
+
source TEXT NOT NULL,
|
|
26
|
+
text TEXT NOT NULL,
|
|
27
|
+
created_at INTEGER NOT NULL,
|
|
28
|
+
send_after INTEGER NOT NULL,
|
|
29
|
+
sent_at INTEGER,
|
|
30
|
+
error TEXT
|
|
31
|
+
)
|
|
32
|
+
`);
|
|
33
|
+
db.exec(
|
|
34
|
+
`CREATE INDEX IF NOT EXISTS idx_notify_outbox_source ON notify_outbox(source, sent_at)`
|
|
35
|
+
);
|
|
36
|
+
// A "message" schedule's session, by id: names change, ids don't.
|
|
37
|
+
// And the agent session that made a schedule, when one did.
|
|
38
|
+
db.exec(`ALTER TABLE schedules ADD COLUMN target_session_id TEXT`);
|
|
39
|
+
db.exec(`ALTER TABLE schedules ADD COLUMN created_by_session_id TEXT`);
|
|
40
|
+
})(),
|
|
41
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 41,
|
|
5
|
+
name: "add_task_setup",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// How a task's worktree setup (deps, setup commands) went before its
|
|
8
|
+
// agent started: running, ok or failed, how long, and what failed;
|
|
9
|
+
// and the brief its launch needs, so a restart can resume it.
|
|
10
|
+
db.transaction(() => {
|
|
11
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN setup_status TEXT`);
|
|
12
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN setup_ms INTEGER`);
|
|
13
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN setup_error TEXT`);
|
|
14
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN task_brief TEXT`);
|
|
15
|
+
})();
|
|
16
|
+
},
|
|
17
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 42,
|
|
5
|
+
name: "add_host_links_and_moved_tasks",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// How this machine reaches another machine's own AgentOS: its URL and
|
|
8
|
+
// the device token it paired with. Apart from hosts so the token never
|
|
9
|
+
// rides along with a host row to the browser.
|
|
10
|
+
db.transaction(() => {
|
|
11
|
+
db.exec(`
|
|
12
|
+
CREATE TABLE IF NOT EXISTS host_links (
|
|
13
|
+
host_id TEXT PRIMARY KEY REFERENCES hosts(id) ON DELETE CASCADE,
|
|
14
|
+
url TEXT NOT NULL,
|
|
15
|
+
token TEXT NOT NULL,
|
|
16
|
+
linked_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
17
|
+
)
|
|
18
|
+
`);
|
|
19
|
+
// A task moved to another machine keeps its row, marked where it
|
|
20
|
+
// went; one that arrived names the session it came from, so the
|
|
21
|
+
// same move imported twice finds the first.
|
|
22
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN moved_to TEXT`);
|
|
23
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN moved_from TEXT`);
|
|
24
|
+
db.exec(
|
|
25
|
+
`CREATE INDEX IF NOT EXISTS idx_sessions_moved_from ON sessions(moved_from)`
|
|
26
|
+
);
|
|
27
|
+
})();
|
|
28
|
+
},
|
|
29
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 43,
|
|
5
|
+
name: "scratch_project",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// Chats with no project work in a scratch folder rather than the home
|
|
8
|
+
// directory. Sessions already made keep their own folders.
|
|
9
|
+
db.prepare(
|
|
10
|
+
`UPDATE projects SET name = 'Scratch', working_directory = '~/.agent-os/scratch'
|
|
11
|
+
WHERE is_uncategorized = 1 AND name = 'Uncategorized' AND working_directory = '~'`
|
|
12
|
+
).run();
|
|
13
|
+
},
|
|
14
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 44,
|
|
5
|
+
name: "chat_item_kind",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// Items of one kind (a chat's background tasks, its sent messages)
|
|
8
|
+
// read from an index, not by parsing every row of a long conversation.
|
|
9
|
+
const columns = db.prepare(`PRAGMA table_xinfo(chat_items)`).all() as {
|
|
10
|
+
name: string;
|
|
11
|
+
}[];
|
|
12
|
+
if (!columns.some((c) => c.name === "kind"))
|
|
13
|
+
db.exec(
|
|
14
|
+
`ALTER TABLE chat_items ADD COLUMN kind TEXT
|
|
15
|
+
GENERATED ALWAYS AS (json_extract(data, '$.kind')) VIRTUAL`
|
|
16
|
+
);
|
|
17
|
+
db.exec(
|
|
18
|
+
`CREATE INDEX IF NOT EXISTS idx_chat_items_kind ON chat_items(session_id, kind, seq)`
|
|
19
|
+
);
|
|
20
|
+
},
|
|
21
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
import { installChangeTriggers, TABLES_WATCHED_45 } from "../changes";
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 45,
|
|
6
|
+
name: "change_versions",
|
|
7
|
+
up: (db) => {
|
|
8
|
+
// What browsers show from these tables is pushed when they change
|
|
9
|
+
// (lib/db/changes.ts) instead of polled. A table added later gets its
|
|
10
|
+
// own migration.
|
|
11
|
+
installChangeTriggers(db, TABLES_WATCHED_45);
|
|
12
|
+
},
|
|
13
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 46,
|
|
5
|
+
name: "session_port_slots",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// A session's port slot and the ports agentos.json's bases resolve to
|
|
8
|
+
// with it (lib/ports.ts). The unique index is what keeps two parallel
|
|
9
|
+
// starts, in any process, off one slot.
|
|
10
|
+
const columns = db.prepare(`PRAGMA table_info(sessions)`).all() as {
|
|
11
|
+
name: string;
|
|
12
|
+
}[];
|
|
13
|
+
if (!columns.some((c) => c.name === "port_slot"))
|
|
14
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN port_slot INTEGER`);
|
|
15
|
+
if (!columns.some((c) => c.name === "ports"))
|
|
16
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN ports TEXT`);
|
|
17
|
+
db.exec(
|
|
18
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_sessions_port_slot ON sessions(port_slot) WHERE port_slot IS NOT NULL`
|
|
19
|
+
);
|
|
20
|
+
},
|
|
21
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 47,
|
|
5
|
+
name: "pin_orchestrators",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// A workspace's orchestrator starts pinned to the top of its list;
|
|
8
|
+
// unpinning it is then remembered on the session, which lives as
|
|
9
|
+
// long as its workspace.
|
|
10
|
+
db.exec(`UPDATE sessions SET pinned = 1 WHERE role = 'orchestrator'`);
|
|
11
|
+
},
|
|
12
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 48,
|
|
5
|
+
name: "session_database",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// The session's private Postgres copy, or why it has none, as JSON
|
|
8
|
+
// (lib/project-config/database.ts).
|
|
9
|
+
const columns = db.prepare(`PRAGMA table_info(sessions)`).all() as {
|
|
10
|
+
name: string;
|
|
11
|
+
}[];
|
|
12
|
+
if (!columns.some((c) => c.name === "database"))
|
|
13
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN database TEXT`);
|
|
14
|
+
},
|
|
15
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 49,
|
|
5
|
+
name: "peer_mirror",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// A row that only shows a linked machine's own session: actions on
|
|
8
|
+
// it go to that machine. Rows this machine started there over ssh
|
|
9
|
+
// are its own, and stay 0.
|
|
10
|
+
db.exec(
|
|
11
|
+
`ALTER TABLE sessions ADD COLUMN peer_mirror INTEGER NOT NULL DEFAULT 0`
|
|
12
|
+
);
|
|
13
|
+
},
|
|
14
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
import { installChangeTriggers, TABLES_WATCHED_50 } from "../changes";
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
id: 50,
|
|
6
|
+
name: "task_queue",
|
|
7
|
+
up: (db) => {
|
|
8
|
+
// Tasks waiting to start (lib/tasks/queue.ts): over the workspace's
|
|
9
|
+
// limit on running tasks, or after another task. A row's id is the
|
|
10
|
+
// session id it starts as, so a restart never starts one twice.
|
|
11
|
+
db.exec(`
|
|
12
|
+
CREATE TABLE IF NOT EXISTS task_queue (
|
|
13
|
+
id TEXT PRIMARY KEY,
|
|
14
|
+
project_id TEXT NOT NULL,
|
|
15
|
+
prompt TEXT NOT NULL,
|
|
16
|
+
name TEXT,
|
|
17
|
+
model TEXT,
|
|
18
|
+
view TEXT,
|
|
19
|
+
base_branch TEXT,
|
|
20
|
+
host_id TEXT,
|
|
21
|
+
after_task TEXT,
|
|
22
|
+
after_any TEXT,
|
|
23
|
+
origin_workspace_id TEXT,
|
|
24
|
+
position INTEGER NOT NULL,
|
|
25
|
+
status TEXT NOT NULL DEFAULT 'queued',
|
|
26
|
+
note TEXT,
|
|
27
|
+
error TEXT,
|
|
28
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
29
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
30
|
+
started_at TEXT
|
|
31
|
+
)
|
|
32
|
+
`);
|
|
33
|
+
db.exec(
|
|
34
|
+
`CREATE INDEX IF NOT EXISTS idx_task_queue_status ON task_queue(status, position)`
|
|
35
|
+
);
|
|
36
|
+
const columns = db.prepare(`PRAGMA table_info(workspaces)`).all() as {
|
|
37
|
+
name: string;
|
|
38
|
+
}[];
|
|
39
|
+
// Null: no limit.
|
|
40
|
+
if (!columns.some((c) => c.name === "max_running_tasks"))
|
|
41
|
+
db.exec(`ALTER TABLE workspaces ADD COLUMN max_running_tasks INTEGER`);
|
|
42
|
+
installChangeTriggers(db, TABLES_WATCHED_50);
|
|
43
|
+
},
|
|
44
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
// 50 is taken by queued tasks, landing separately.
|
|
5
|
+
id: 51,
|
|
6
|
+
name: "chat_queue_sent_by",
|
|
7
|
+
up: (db) => {
|
|
8
|
+
// Who sent a queued message the reader didn't type (lib/chat/events
|
|
9
|
+
// SentBy, as JSON), so it still shows as theirs once it's sent.
|
|
10
|
+
const columns = db.prepare(`PRAGMA table_info(chat_queue)`).all() as {
|
|
11
|
+
name: string;
|
|
12
|
+
}[];
|
|
13
|
+
if (!columns.some((c) => c.name === "sent_by"))
|
|
14
|
+
db.exec(`ALTER TABLE chat_queue ADD COLUMN sent_by TEXT`);
|
|
15
|
+
},
|
|
16
|
+
} satisfies Migration;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Migration } from "../migration-types";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 52,
|
|
5
|
+
name: "sessions_chat_restarted",
|
|
6
|
+
up: (db) => {
|
|
7
|
+
// Set by a chat worker that retired cleanly after a deploy; the next
|
|
8
|
+
// worker tells the agent so with its first message, then clears it.
|
|
9
|
+
const columns = db.prepare(`PRAGMA table_info(sessions)`).all() as {
|
|
10
|
+
name: string;
|
|
11
|
+
}[];
|
|
12
|
+
if (!columns.some((c) => c.name === "chat_restarted"))
|
|
13
|
+
db.exec(
|
|
14
|
+
`ALTER TABLE sessions ADD COLUMN chat_restarted INTEGER NOT NULL DEFAULT 0`
|
|
15
|
+
);
|
|
16
|
+
},
|
|
17
|
+
} satisfies Migration;
|