mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-09-25 03:42:06 +00:00
be576d9e24
* feat: agent roles — role-based (user, role) assignment for items (#PHASE-9) Introduce agent roles as a first-class concept for human-agent work assignment. Roles describe capability specializations (Planner, Implementer, Reviewer, etc.) and items can be assigned to a (user, role) pair, enabling natural handoff workflows between different AI tools. Migration: - New `agent_roles` table (workspace-scoped, slug-unique) - `assigned_user_id` + `agent_role_id` columns on `items` with FKs - Removed legacy `assignee` text field from Tasks schema Backend: - AgentRole model + full CRUD store/API - All item queries updated with LEFT JOINs to resolve assignment - Item list filtering by assigned_user_id and agent_role_id - Role transitions tracked in activity feed metadata CLI: - `pad role list/create/delete` commands - `--role` and `--assign` flags on item create/update/list - Assignment displayed in `pad item show` output Web: - TypeScript types + API client for agent roles - Role badge on item cards in list/board views - Assignment display on item detail page * fix: enforce workspace-scoped assignments and fail fast on unresolved --assign filter Addresses code review feedback from PR #58: P1: Add validateAssignmentScope() to the store layer, called by both CreateItem and UpdateItem. Verifies that assigned_user_id belongs to the workspace (via IsWorkspaceMember) and agent_role_id exists in the workspace (via GetAgentRole) before writing. Prevents cross-workspace assignment leaks. P2: The CLI `pad item list --assign <name>` now errors instead of silently returning unfiltered results when the member lookup fails or no workspace member matches the provided name.
37 lines
1.5 KiB
SQL
37 lines
1.5 KiB
SQL
-- Agent roles: workspace-scoped capability roles for human-agent assignment
|
|
|
|
CREATE TABLE IF NOT EXISTS agent_roles (
|
|
id TEXT PRIMARY KEY,
|
|
workspace_id TEXT NOT NULL REFERENCES workspaces(id),
|
|
slug TEXT NOT NULL,
|
|
name TEXT NOT NULL,
|
|
description TEXT NOT NULL DEFAULT '',
|
|
icon TEXT NOT NULL DEFAULT '',
|
|
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL,
|
|
UNIQUE(workspace_id, slug)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_agent_roles_workspace ON agent_roles(workspace_id);
|
|
|
|
-- Assignment columns on items: (user, role) pairs
|
|
ALTER TABLE items ADD COLUMN assigned_user_id TEXT REFERENCES users(id) ON DELETE SET NULL;
|
|
ALTER TABLE items ADD COLUMN agent_role_id TEXT REFERENCES agent_roles(id) ON DELETE SET NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_items_assigned_user ON items(assigned_user_id) WHERE deleted_at IS NULL;
|
|
CREATE INDEX IF NOT EXISTS idx_items_agent_role ON items(agent_role_id) WHERE deleted_at IS NULL;
|
|
|
|
-- Remove assignee text field from existing Tasks collection schemas.
|
|
-- This replaces the free-text assignee with the structured (user, role) assignment above.
|
|
UPDATE collections
|
|
SET schema = REPLACE(schema, '{"key":"assignee","label":"Assignee","type":"text"},', '')
|
|
WHERE slug = 'tasks'
|
|
AND schema LIKE '%"assignee"%';
|
|
|
|
-- Handle alternate JSON formatting (with spaces)
|
|
UPDATE collections
|
|
SET schema = REPLACE(schema, '{"key": "assignee", "label": "Assignee", "type": "text"},', '')
|
|
WHERE slug = 'tasks'
|
|
AND schema LIKE '%"assignee"%';
|