unify agent items into a flat file-based store, drop the marketplace

Replace the marketplace service dependency and the native/global/user
scope tiers with a single external directory ($OFFICER_ITEMS_DIR) holding
skills, tools, tasks, processes and extensions as plain files.

- tasks move from Postgres to TASK.md files (new file-backed task layer);
  task editing now works, which the DB path never supported
- skills/tools/processes collapse into one shared file router (single dir)
- remove the marketplace client (sync-marketplace/sync-version) and the
  boot-time sync; pi-bridge/pi-manager/sandbox point at the flat store
- drop the dead tasks + vestigial skills/tools/processes/extensions +
  item_chats tables (migration 0004)
- one-time migration script exports DB tasks and consolidates disk items

Migration verified: all 6 tasks round-trip through the runtime parser
identically to their DB rows (pipeline steps, triggers, script impls and
agentic bodies all intact).

NOTE: not yet functionally tested end-to-end — every item (each task mode,
tool, skill, extension) still needs to be run/exercised in the app before
this is trusted. To be done manually.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 00:39:17 +00:00
co-authored by Claude Opus 4.8
parent 5fd3d4faac
commit f3492512ba
29 changed files with 2366 additions and 1357 deletions
+3 -17
View File
@@ -5,7 +5,6 @@
* - DB: user_settings, user_state, user_integrations, dock_configs,
* chat_sessions (cascades chat_messages), chat_groups,
* dashboards, screens, projects,
* tasks, skills, processes, tools, extensions (+ item_chats),
* task_logs, queue_jobs, terminal_containers
* - Filesystem: entire $DATA_PATH/<email>/ directory
* (home, settings, state, dashboards, chat_sessions, emails.db,
@@ -76,7 +75,7 @@ const tables = [
'user_state',
'user_integrations',
'dock_configs',
'chat_sessions', // cascades chat_messages
'chat_sessions', // cascades chat_messages
'chat_groups',
'dashboards',
'screens',
@@ -92,21 +91,8 @@ for (const table of tables) {
console.log(` ${table}: ${count} rows deleted`);
}
// Agent items: tasks, skills, processes, tools, extensions
// These have nullable user_id — delete only rows belonging to this user
const agentTables = ['tasks', 'skills', 'processes', 'tools', 'extensions'];
for (const table of agentTables) {
// First collect item IDs to clean up item_chats
const items = await db.execute(sql.raw(`SELECT id FROM ${table} WHERE user_id = ${userId}`));
if (items.length > 0) {
const ids = items.map((r: Record<string, unknown>) => r.id).join(',');
const chatResult = await db.execute(sql.raw(`DELETE FROM item_chats WHERE item_type = '${table}' AND item_id IN (${ids})`));
console.log(` item_chats (${table}): ${chatResult.length ?? 0} rows deleted`);
}
const result = await db.execute(sql.raw(`DELETE FROM ${table} WHERE user_id = ${userId}`));
console.log(` ${table}: ${result.length ?? 0} rows deleted`);
}
// Agent items (skills, tools, tasks, processes, extensions) are now flat files in
// $OFFICER_ITEMS_DIR, shared and not user-owned — intentionally left untouched by a user reset.
// ── Queue job files ──