@hasna/todos 0.10.11 → 0.10.13
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/dist/cli/index.js +162 -1
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/project-agent-roles.d.ts +34 -0
- package/dist/db/project-agent-roles.d.ts.map +1 -0
- package/dist/index.js +15 -1
- package/dist/mcp/index.js +162 -1
- package/dist/server/index.js +15 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2897,6 +2897,20 @@ var init_database = __esm(() => {
|
|
|
2897
2897
|
ALTER TABLE agents ADD COLUMN status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'archived'));
|
|
2898
2898
|
CREATE INDEX IF NOT EXISTS idx_agents_status ON agents(status);
|
|
2899
2899
|
INSERT OR IGNORE INTO _migrations (id) VALUES (30);
|
|
2900
|
+
`,
|
|
2901
|
+
`
|
|
2902
|
+
CREATE TABLE IF NOT EXISTS project_agent_roles (
|
|
2903
|
+
id TEXT PRIMARY KEY,
|
|
2904
|
+
project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
2905
|
+
agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
|
|
2906
|
+
role TEXT NOT NULL,
|
|
2907
|
+
is_lead INTEGER NOT NULL DEFAULT 0,
|
|
2908
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
2909
|
+
UNIQUE(project_id, agent_id, role)
|
|
2910
|
+
);
|
|
2911
|
+
CREATE INDEX IF NOT EXISTS idx_project_agent_roles_project ON project_agent_roles(project_id);
|
|
2912
|
+
CREATE INDEX IF NOT EXISTS idx_project_agent_roles_agent ON project_agent_roles(agent_id);
|
|
2913
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (31);
|
|
2900
2914
|
`,
|
|
2901
2915
|
`
|
|
2902
2916
|
CREATE TABLE IF NOT EXISTS file_locks (
|
|
@@ -2910,7 +2924,7 @@ var init_database = __esm(() => {
|
|
|
2910
2924
|
CREATE INDEX IF NOT EXISTS idx_file_locks_path ON file_locks(path);
|
|
2911
2925
|
CREATE INDEX IF NOT EXISTS idx_file_locks_agent ON file_locks(agent_id);
|
|
2912
2926
|
CREATE INDEX IF NOT EXISTS idx_file_locks_expires ON file_locks(expires_at);
|
|
2913
|
-
INSERT OR IGNORE INTO _migrations (id) VALUES (
|
|
2927
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (32);
|
|
2914
2928
|
`
|
|
2915
2929
|
];
|
|
2916
2930
|
});
|
|
@@ -10432,6 +10446,81 @@ var init_kg = __esm(() => {
|
|
|
10432
10446
|
init_database();
|
|
10433
10447
|
});
|
|
10434
10448
|
|
|
10449
|
+
// src/db/project-agent-roles.ts
|
|
10450
|
+
var exports_project_agent_roles = {};
|
|
10451
|
+
__export(exports_project_agent_roles, {
|
|
10452
|
+
setProjectAgentRole: () => setProjectAgentRole,
|
|
10453
|
+
removeProjectAgentRole: () => removeProjectAgentRole,
|
|
10454
|
+
listProjectAgentRoles: () => listProjectAgentRoles,
|
|
10455
|
+
getProjectOrgChart: () => getProjectOrgChart,
|
|
10456
|
+
getAgentProjectRoles: () => getAgentProjectRoles
|
|
10457
|
+
});
|
|
10458
|
+
function rowToRole(row) {
|
|
10459
|
+
return { ...row, is_lead: row.is_lead === 1 };
|
|
10460
|
+
}
|
|
10461
|
+
function setProjectAgentRole(projectId, agentId, role, isLead = false, db) {
|
|
10462
|
+
const d = db || getDatabase();
|
|
10463
|
+
const existing = d.query("SELECT * FROM project_agent_roles WHERE project_id = ? AND agent_id = ? AND role = ?").get(projectId, agentId, role);
|
|
10464
|
+
if (existing) {
|
|
10465
|
+
d.run("UPDATE project_agent_roles SET is_lead = ? WHERE id = ?", [isLead ? 1 : 0, existing.id]);
|
|
10466
|
+
return rowToRole(d.query("SELECT * FROM project_agent_roles WHERE id = ?").get(existing.id));
|
|
10467
|
+
}
|
|
10468
|
+
const id = uuid();
|
|
10469
|
+
d.run("INSERT INTO project_agent_roles (id, project_id, agent_id, role, is_lead, created_at) VALUES (?, ?, ?, ?, ?, ?)", [id, projectId, agentId, role, isLead ? 1 : 0, now()]);
|
|
10470
|
+
return rowToRole(d.query("SELECT * FROM project_agent_roles WHERE id = ?").get(id));
|
|
10471
|
+
}
|
|
10472
|
+
function removeProjectAgentRole(projectId, agentId, role, db) {
|
|
10473
|
+
const d = db || getDatabase();
|
|
10474
|
+
if (role) {
|
|
10475
|
+
return d.run("DELETE FROM project_agent_roles WHERE project_id = ? AND agent_id = ? AND role = ?", [projectId, agentId, role]).changes;
|
|
10476
|
+
}
|
|
10477
|
+
return d.run("DELETE FROM project_agent_roles WHERE project_id = ? AND agent_id = ?", [projectId, agentId]).changes;
|
|
10478
|
+
}
|
|
10479
|
+
function listProjectAgentRoles(projectId, db) {
|
|
10480
|
+
const d = db || getDatabase();
|
|
10481
|
+
return d.query("SELECT * FROM project_agent_roles WHERE project_id = ? ORDER BY role, created_at").all(projectId).map(rowToRole);
|
|
10482
|
+
}
|
|
10483
|
+
function getAgentProjectRoles(agentId, db) {
|
|
10484
|
+
const d = db || getDatabase();
|
|
10485
|
+
return d.query("SELECT * FROM project_agent_roles WHERE agent_id = ? ORDER BY project_id, role").all(agentId).map(rowToRole);
|
|
10486
|
+
}
|
|
10487
|
+
function getProjectOrgChart(projectId, opts, db) {
|
|
10488
|
+
const d = db || getDatabase();
|
|
10489
|
+
const globalTree = getOrgChart(d);
|
|
10490
|
+
const projectRoles = listProjectAgentRoles(projectId, d);
|
|
10491
|
+
const rolesByAgent = new Map;
|
|
10492
|
+
for (const pr of projectRoles) {
|
|
10493
|
+
if (!rolesByAgent.has(pr.agent_id))
|
|
10494
|
+
rolesByAgent.set(pr.agent_id, { roles: [], isLead: false });
|
|
10495
|
+
const entry = rolesByAgent.get(pr.agent_id);
|
|
10496
|
+
entry.roles.push(pr.role);
|
|
10497
|
+
if (pr.is_lead)
|
|
10498
|
+
entry.isLead = true;
|
|
10499
|
+
}
|
|
10500
|
+
function augmentTree(nodes) {
|
|
10501
|
+
return nodes.map((n) => {
|
|
10502
|
+
const override = rolesByAgent.get(n.agent.id);
|
|
10503
|
+
return {
|
|
10504
|
+
...n,
|
|
10505
|
+
reports: augmentTree(n.reports),
|
|
10506
|
+
project_roles: override?.roles ?? [],
|
|
10507
|
+
is_project_lead: override?.isLead ?? false
|
|
10508
|
+
};
|
|
10509
|
+
}).filter((n) => {
|
|
10510
|
+
if (!opts?.filter_to_project)
|
|
10511
|
+
return true;
|
|
10512
|
+
const hasRole = n.project_roles.length > 0;
|
|
10513
|
+
const hasDescendant = n.reports.length > 0;
|
|
10514
|
+
return hasRole || hasDescendant;
|
|
10515
|
+
});
|
|
10516
|
+
}
|
|
10517
|
+
return augmentTree(globalTree);
|
|
10518
|
+
}
|
|
10519
|
+
var init_project_agent_roles = __esm(() => {
|
|
10520
|
+
init_database();
|
|
10521
|
+
init_agents();
|
|
10522
|
+
});
|
|
10523
|
+
|
|
10435
10524
|
// src/db/patrol.ts
|
|
10436
10525
|
var exports_patrol = {};
|
|
10437
10526
|
__export(exports_patrol, {
|
|
@@ -13768,6 +13857,78 @@ ${lines.join(`
|
|
|
13768
13857
|
}
|
|
13769
13858
|
});
|
|
13770
13859
|
}
|
|
13860
|
+
if (shouldRegisterTool("set_project_agent_role")) {
|
|
13861
|
+
server.tool("set_project_agent_role", "Assign an agent a role on a specific project (client, lead, developer, qa, reviewer, etc.). Per-project roles extend the global org chart.", {
|
|
13862
|
+
project_id: exports_external.string().describe("Project ID"),
|
|
13863
|
+
agent_name: exports_external.string().describe("Agent name"),
|
|
13864
|
+
role: exports_external.string().describe("Role on this project (e.g. 'lead', 'developer', 'qa')"),
|
|
13865
|
+
is_lead: exports_external.coerce.boolean().optional().describe("Whether this agent is the project lead for this role")
|
|
13866
|
+
}, async ({ project_id, agent_name, role, is_lead }) => {
|
|
13867
|
+
try {
|
|
13868
|
+
const { setProjectAgentRole: setProjectAgentRole2 } = (init_project_agent_roles(), __toCommonJS(exports_project_agent_roles));
|
|
13869
|
+
const agent = getAgentByName(agent_name);
|
|
13870
|
+
if (!agent)
|
|
13871
|
+
return { content: [{ type: "text", text: `Agent not found: ${agent_name}` }], isError: true };
|
|
13872
|
+
const pid = resolveId(project_id, "projects");
|
|
13873
|
+
const result = setProjectAgentRole2(pid, agent.id, role, is_lead ?? false);
|
|
13874
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
13875
|
+
} catch (e) {
|
|
13876
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
13877
|
+
}
|
|
13878
|
+
});
|
|
13879
|
+
}
|
|
13880
|
+
if (shouldRegisterTool("get_project_org_chart")) {
|
|
13881
|
+
server.tool("get_project_org_chart", "Get org chart scoped to a project \u2014 global hierarchy with per-project role overrides merged in.", {
|
|
13882
|
+
project_id: exports_external.string().describe("Project ID"),
|
|
13883
|
+
format: exports_external.enum(["text", "json"]).optional().describe("Output format (default: text)"),
|
|
13884
|
+
filter_to_project: exports_external.coerce.boolean().optional().describe("Only show agents with a role on this project")
|
|
13885
|
+
}, async ({ project_id, format, filter_to_project }) => {
|
|
13886
|
+
try {
|
|
13887
|
+
let render = function(nodes, indent = 0) {
|
|
13888
|
+
return nodes.map((n) => {
|
|
13889
|
+
const prefix = " ".repeat(indent);
|
|
13890
|
+
const title = n.agent.title ? ` \u2014 ${n.agent.title}` : "";
|
|
13891
|
+
const globalRole = n.agent.role ? ` [${n.agent.role}]` : "";
|
|
13892
|
+
const projectRoles = n.project_roles.length > 0 ? ` <${n.project_roles.join(", ")}>` : "";
|
|
13893
|
+
const lead = n.is_project_lead ? " \u2605" : "";
|
|
13894
|
+
const lastSeen = new Date(n.agent.last_seen_at).getTime();
|
|
13895
|
+
const active = now2 - lastSeen < ACTIVE_MS ? " \u25CF" : " \u25CB";
|
|
13896
|
+
const line = `${prefix}${active} ${n.agent.name}${title}${globalRole}${projectRoles}${lead}`;
|
|
13897
|
+
const children = n.reports.length > 0 ? `
|
|
13898
|
+
` + render(n.reports, indent + 1) : "";
|
|
13899
|
+
return line + children;
|
|
13900
|
+
}).join(`
|
|
13901
|
+
`);
|
|
13902
|
+
};
|
|
13903
|
+
const { getProjectOrgChart: getProjectOrgChart2 } = (init_project_agent_roles(), __toCommonJS(exports_project_agent_roles));
|
|
13904
|
+
const pid = resolveId(project_id, "projects");
|
|
13905
|
+
const tree = getProjectOrgChart2(pid, { filter_to_project });
|
|
13906
|
+
if (format === "json") {
|
|
13907
|
+
return { content: [{ type: "text", text: JSON.stringify(tree, null, 2) }] };
|
|
13908
|
+
}
|
|
13909
|
+
const now2 = Date.now();
|
|
13910
|
+
const ACTIVE_MS = 30 * 60 * 1000;
|
|
13911
|
+
const text = tree.length > 0 ? render(tree) : "No agents in this project's org chart.";
|
|
13912
|
+
return { content: [{ type: "text", text }] };
|
|
13913
|
+
} catch (e) {
|
|
13914
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
13915
|
+
}
|
|
13916
|
+
});
|
|
13917
|
+
}
|
|
13918
|
+
if (shouldRegisterTool("list_project_agent_roles")) {
|
|
13919
|
+
server.tool("list_project_agent_roles", "List all agent role assignments for a project.", {
|
|
13920
|
+
project_id: exports_external.string().describe("Project ID")
|
|
13921
|
+
}, async ({ project_id }) => {
|
|
13922
|
+
try {
|
|
13923
|
+
const { listProjectAgentRoles: listProjectAgentRoles2 } = (init_project_agent_roles(), __toCommonJS(exports_project_agent_roles));
|
|
13924
|
+
const pid = resolveId(project_id, "projects");
|
|
13925
|
+
const roles = listProjectAgentRoles2(pid);
|
|
13926
|
+
return { content: [{ type: "text", text: JSON.stringify(roles, null, 2) }] };
|
|
13927
|
+
} catch (e) {
|
|
13928
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
13929
|
+
}
|
|
13930
|
+
});
|
|
13931
|
+
}
|
|
13771
13932
|
if (shouldRegisterTool("get_capable_agents")) {
|
|
13772
13933
|
server.tool("get_capable_agents", "Find agents that match given capabilities, sorted by match score.", {
|
|
13773
13934
|
capabilities: exports_external.array(exports_external.string()).describe("Required capabilities to match against"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC,eAAO,MAAM,mBAAmB,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AA4iBtC,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAkBrD;AAyRD,wBAAgB,aAAa,IAAI,IAAI,CAKpC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED,wBAAgB,GAAG,IAAI,MAAM,CAE5B;AAED,wBAAgB,IAAI,IAAI,MAAM,CAE7B;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAK9D;AAED,wBAAgB,gBAAgB,CAAC,KAAK,SAAa,GAAG,MAAM,CAG3D;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAGpD;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA0B9F"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite";
|
|
2
|
+
import type { OrgNode } from "./agents.js";
|
|
3
|
+
export interface ProjectAgentRole {
|
|
4
|
+
id: string;
|
|
5
|
+
project_id: string;
|
|
6
|
+
agent_id: string;
|
|
7
|
+
role: string;
|
|
8
|
+
is_lead: boolean;
|
|
9
|
+
created_at: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ProjectAgentRoleRow {
|
|
12
|
+
id: string;
|
|
13
|
+
project_id: string;
|
|
14
|
+
agent_id: string;
|
|
15
|
+
role: string;
|
|
16
|
+
is_lead: number;
|
|
17
|
+
created_at: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function setProjectAgentRole(projectId: string, agentId: string, role: string, isLead?: boolean, db?: Database): ProjectAgentRole;
|
|
20
|
+
export declare function removeProjectAgentRole(projectId: string, agentId: string, role?: string, db?: Database): number;
|
|
21
|
+
export declare function listProjectAgentRoles(projectId: string, db?: Database): ProjectAgentRole[];
|
|
22
|
+
export declare function getAgentProjectRoles(agentId: string, db?: Database): ProjectAgentRole[];
|
|
23
|
+
export interface ProjectOrgNode extends OrgNode {
|
|
24
|
+
project_roles: string[];
|
|
25
|
+
is_project_lead: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get org chart scoped to a project. Returns global org chart with per-project
|
|
29
|
+
* role overrides merged in. Agents not in the project are excluded when filter=true.
|
|
30
|
+
*/
|
|
31
|
+
export declare function getProjectOrgChart(projectId: string, opts?: {
|
|
32
|
+
filter_to_project?: boolean;
|
|
33
|
+
}, db?: Database): ProjectOrgNode[];
|
|
34
|
+
//# sourceMappingURL=project-agent-roles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-agent-roles.d.ts","sourceRoot":"","sources":["../../src/db/project-agent-roles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAMD,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,MAAM,UAAQ,EACd,EAAE,CAAC,EAAE,QAAQ,GACZ,gBAAgB,CAoBlB;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,MAAM,EACb,EAAE,CAAC,EAAE,QAAQ,GACZ,MAAM,CAYR;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,gBAAgB,EAAE,CAK1F;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,gBAAgB,EAAE,CAKvF;AAED,MAAM,WAAW,cAAe,SAAQ,OAAO;IAC7C,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE;IAAE,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAE,EACtC,EAAE,CAAC,EAAE,QAAQ,GACZ,cAAc,EAAE,CAkClB"}
|
package/dist/index.js
CHANGED
|
@@ -704,6 +704,20 @@ var MIGRATIONS = [
|
|
|
704
704
|
INSERT OR IGNORE INTO _migrations (id) VALUES (30);
|
|
705
705
|
`,
|
|
706
706
|
`
|
|
707
|
+
CREATE TABLE IF NOT EXISTS project_agent_roles (
|
|
708
|
+
id TEXT PRIMARY KEY,
|
|
709
|
+
project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
710
|
+
agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
|
|
711
|
+
role TEXT NOT NULL,
|
|
712
|
+
is_lead INTEGER NOT NULL DEFAULT 0,
|
|
713
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
714
|
+
UNIQUE(project_id, agent_id, role)
|
|
715
|
+
);
|
|
716
|
+
CREATE INDEX IF NOT EXISTS idx_project_agent_roles_project ON project_agent_roles(project_id);
|
|
717
|
+
CREATE INDEX IF NOT EXISTS idx_project_agent_roles_agent ON project_agent_roles(agent_id);
|
|
718
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (31);
|
|
719
|
+
`,
|
|
720
|
+
`
|
|
707
721
|
CREATE TABLE IF NOT EXISTS file_locks (
|
|
708
722
|
id TEXT PRIMARY KEY,
|
|
709
723
|
path TEXT NOT NULL UNIQUE,
|
|
@@ -715,7 +729,7 @@ var MIGRATIONS = [
|
|
|
715
729
|
CREATE INDEX IF NOT EXISTS idx_file_locks_path ON file_locks(path);
|
|
716
730
|
CREATE INDEX IF NOT EXISTS idx_file_locks_agent ON file_locks(agent_id);
|
|
717
731
|
CREATE INDEX IF NOT EXISTS idx_file_locks_expires ON file_locks(expires_at);
|
|
718
|
-
INSERT OR IGNORE INTO _migrations (id) VALUES (
|
|
732
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (32);
|
|
719
733
|
`
|
|
720
734
|
];
|
|
721
735
|
var _db = null;
|
package/dist/mcp/index.js
CHANGED
|
@@ -942,6 +942,20 @@ var init_database = __esm(() => {
|
|
|
942
942
|
ALTER TABLE agents ADD COLUMN status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'archived'));
|
|
943
943
|
CREATE INDEX IF NOT EXISTS idx_agents_status ON agents(status);
|
|
944
944
|
INSERT OR IGNORE INTO _migrations (id) VALUES (30);
|
|
945
|
+
`,
|
|
946
|
+
`
|
|
947
|
+
CREATE TABLE IF NOT EXISTS project_agent_roles (
|
|
948
|
+
id TEXT PRIMARY KEY,
|
|
949
|
+
project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
950
|
+
agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
|
|
951
|
+
role TEXT NOT NULL,
|
|
952
|
+
is_lead INTEGER NOT NULL DEFAULT 0,
|
|
953
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
954
|
+
UNIQUE(project_id, agent_id, role)
|
|
955
|
+
);
|
|
956
|
+
CREATE INDEX IF NOT EXISTS idx_project_agent_roles_project ON project_agent_roles(project_id);
|
|
957
|
+
CREATE INDEX IF NOT EXISTS idx_project_agent_roles_agent ON project_agent_roles(agent_id);
|
|
958
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (31);
|
|
945
959
|
`,
|
|
946
960
|
`
|
|
947
961
|
CREATE TABLE IF NOT EXISTS file_locks (
|
|
@@ -955,7 +969,7 @@ var init_database = __esm(() => {
|
|
|
955
969
|
CREATE INDEX IF NOT EXISTS idx_file_locks_path ON file_locks(path);
|
|
956
970
|
CREATE INDEX IF NOT EXISTS idx_file_locks_agent ON file_locks(agent_id);
|
|
957
971
|
CREATE INDEX IF NOT EXISTS idx_file_locks_expires ON file_locks(expires_at);
|
|
958
|
-
INSERT OR IGNORE INTO _migrations (id) VALUES (
|
|
972
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (32);
|
|
959
973
|
`
|
|
960
974
|
];
|
|
961
975
|
});
|
|
@@ -1977,6 +1991,81 @@ var init_kg = __esm(() => {
|
|
|
1977
1991
|
init_database();
|
|
1978
1992
|
});
|
|
1979
1993
|
|
|
1994
|
+
// src/db/project-agent-roles.ts
|
|
1995
|
+
var exports_project_agent_roles = {};
|
|
1996
|
+
__export(exports_project_agent_roles, {
|
|
1997
|
+
setProjectAgentRole: () => setProjectAgentRole,
|
|
1998
|
+
removeProjectAgentRole: () => removeProjectAgentRole,
|
|
1999
|
+
listProjectAgentRoles: () => listProjectAgentRoles,
|
|
2000
|
+
getProjectOrgChart: () => getProjectOrgChart,
|
|
2001
|
+
getAgentProjectRoles: () => getAgentProjectRoles
|
|
2002
|
+
});
|
|
2003
|
+
function rowToRole(row) {
|
|
2004
|
+
return { ...row, is_lead: row.is_lead === 1 };
|
|
2005
|
+
}
|
|
2006
|
+
function setProjectAgentRole(projectId, agentId, role, isLead = false, db) {
|
|
2007
|
+
const d = db || getDatabase();
|
|
2008
|
+
const existing = d.query("SELECT * FROM project_agent_roles WHERE project_id = ? AND agent_id = ? AND role = ?").get(projectId, agentId, role);
|
|
2009
|
+
if (existing) {
|
|
2010
|
+
d.run("UPDATE project_agent_roles SET is_lead = ? WHERE id = ?", [isLead ? 1 : 0, existing.id]);
|
|
2011
|
+
return rowToRole(d.query("SELECT * FROM project_agent_roles WHERE id = ?").get(existing.id));
|
|
2012
|
+
}
|
|
2013
|
+
const id = uuid();
|
|
2014
|
+
d.run("INSERT INTO project_agent_roles (id, project_id, agent_id, role, is_lead, created_at) VALUES (?, ?, ?, ?, ?, ?)", [id, projectId, agentId, role, isLead ? 1 : 0, now()]);
|
|
2015
|
+
return rowToRole(d.query("SELECT * FROM project_agent_roles WHERE id = ?").get(id));
|
|
2016
|
+
}
|
|
2017
|
+
function removeProjectAgentRole(projectId, agentId, role, db) {
|
|
2018
|
+
const d = db || getDatabase();
|
|
2019
|
+
if (role) {
|
|
2020
|
+
return d.run("DELETE FROM project_agent_roles WHERE project_id = ? AND agent_id = ? AND role = ?", [projectId, agentId, role]).changes;
|
|
2021
|
+
}
|
|
2022
|
+
return d.run("DELETE FROM project_agent_roles WHERE project_id = ? AND agent_id = ?", [projectId, agentId]).changes;
|
|
2023
|
+
}
|
|
2024
|
+
function listProjectAgentRoles(projectId, db) {
|
|
2025
|
+
const d = db || getDatabase();
|
|
2026
|
+
return d.query("SELECT * FROM project_agent_roles WHERE project_id = ? ORDER BY role, created_at").all(projectId).map(rowToRole);
|
|
2027
|
+
}
|
|
2028
|
+
function getAgentProjectRoles(agentId, db) {
|
|
2029
|
+
const d = db || getDatabase();
|
|
2030
|
+
return d.query("SELECT * FROM project_agent_roles WHERE agent_id = ? ORDER BY project_id, role").all(agentId).map(rowToRole);
|
|
2031
|
+
}
|
|
2032
|
+
function getProjectOrgChart(projectId, opts, db) {
|
|
2033
|
+
const d = db || getDatabase();
|
|
2034
|
+
const globalTree = getOrgChart(d);
|
|
2035
|
+
const projectRoles = listProjectAgentRoles(projectId, d);
|
|
2036
|
+
const rolesByAgent = new Map;
|
|
2037
|
+
for (const pr of projectRoles) {
|
|
2038
|
+
if (!rolesByAgent.has(pr.agent_id))
|
|
2039
|
+
rolesByAgent.set(pr.agent_id, { roles: [], isLead: false });
|
|
2040
|
+
const entry = rolesByAgent.get(pr.agent_id);
|
|
2041
|
+
entry.roles.push(pr.role);
|
|
2042
|
+
if (pr.is_lead)
|
|
2043
|
+
entry.isLead = true;
|
|
2044
|
+
}
|
|
2045
|
+
function augmentTree(nodes) {
|
|
2046
|
+
return nodes.map((n) => {
|
|
2047
|
+
const override = rolesByAgent.get(n.agent.id);
|
|
2048
|
+
return {
|
|
2049
|
+
...n,
|
|
2050
|
+
reports: augmentTree(n.reports),
|
|
2051
|
+
project_roles: override?.roles ?? [],
|
|
2052
|
+
is_project_lead: override?.isLead ?? false
|
|
2053
|
+
};
|
|
2054
|
+
}).filter((n) => {
|
|
2055
|
+
if (!opts?.filter_to_project)
|
|
2056
|
+
return true;
|
|
2057
|
+
const hasRole = n.project_roles.length > 0;
|
|
2058
|
+
const hasDescendant = n.reports.length > 0;
|
|
2059
|
+
return hasRole || hasDescendant;
|
|
2060
|
+
});
|
|
2061
|
+
}
|
|
2062
|
+
return augmentTree(globalTree);
|
|
2063
|
+
}
|
|
2064
|
+
var init_project_agent_roles = __esm(() => {
|
|
2065
|
+
init_database();
|
|
2066
|
+
init_agents();
|
|
2067
|
+
});
|
|
2068
|
+
|
|
1980
2069
|
// src/db/patrol.ts
|
|
1981
2070
|
var exports_patrol = {};
|
|
1982
2071
|
__export(exports_patrol, {
|
|
@@ -11496,6 +11585,78 @@ ${lines.join(`
|
|
|
11496
11585
|
}
|
|
11497
11586
|
});
|
|
11498
11587
|
}
|
|
11588
|
+
if (shouldRegisterTool("set_project_agent_role")) {
|
|
11589
|
+
server.tool("set_project_agent_role", "Assign an agent a role on a specific project (client, lead, developer, qa, reviewer, etc.). Per-project roles extend the global org chart.", {
|
|
11590
|
+
project_id: exports_external.string().describe("Project ID"),
|
|
11591
|
+
agent_name: exports_external.string().describe("Agent name"),
|
|
11592
|
+
role: exports_external.string().describe("Role on this project (e.g. 'lead', 'developer', 'qa')"),
|
|
11593
|
+
is_lead: exports_external.coerce.boolean().optional().describe("Whether this agent is the project lead for this role")
|
|
11594
|
+
}, async ({ project_id, agent_name, role, is_lead }) => {
|
|
11595
|
+
try {
|
|
11596
|
+
const { setProjectAgentRole: setProjectAgentRole2 } = (init_project_agent_roles(), __toCommonJS(exports_project_agent_roles));
|
|
11597
|
+
const agent = getAgentByName(agent_name);
|
|
11598
|
+
if (!agent)
|
|
11599
|
+
return { content: [{ type: "text", text: `Agent not found: ${agent_name}` }], isError: true };
|
|
11600
|
+
const pid = resolveId(project_id, "projects");
|
|
11601
|
+
const result = setProjectAgentRole2(pid, agent.id, role, is_lead ?? false);
|
|
11602
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
11603
|
+
} catch (e) {
|
|
11604
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
11605
|
+
}
|
|
11606
|
+
});
|
|
11607
|
+
}
|
|
11608
|
+
if (shouldRegisterTool("get_project_org_chart")) {
|
|
11609
|
+
server.tool("get_project_org_chart", "Get org chart scoped to a project \u2014 global hierarchy with per-project role overrides merged in.", {
|
|
11610
|
+
project_id: exports_external.string().describe("Project ID"),
|
|
11611
|
+
format: exports_external.enum(["text", "json"]).optional().describe("Output format (default: text)"),
|
|
11612
|
+
filter_to_project: exports_external.coerce.boolean().optional().describe("Only show agents with a role on this project")
|
|
11613
|
+
}, async ({ project_id, format, filter_to_project }) => {
|
|
11614
|
+
try {
|
|
11615
|
+
let render = function(nodes, indent = 0) {
|
|
11616
|
+
return nodes.map((n) => {
|
|
11617
|
+
const prefix = " ".repeat(indent);
|
|
11618
|
+
const title = n.agent.title ? ` \u2014 ${n.agent.title}` : "";
|
|
11619
|
+
const globalRole = n.agent.role ? ` [${n.agent.role}]` : "";
|
|
11620
|
+
const projectRoles = n.project_roles.length > 0 ? ` <${n.project_roles.join(", ")}>` : "";
|
|
11621
|
+
const lead = n.is_project_lead ? " \u2605" : "";
|
|
11622
|
+
const lastSeen = new Date(n.agent.last_seen_at).getTime();
|
|
11623
|
+
const active = now2 - lastSeen < ACTIVE_MS ? " \u25CF" : " \u25CB";
|
|
11624
|
+
const line = `${prefix}${active} ${n.agent.name}${title}${globalRole}${projectRoles}${lead}`;
|
|
11625
|
+
const children = n.reports.length > 0 ? `
|
|
11626
|
+
` + render(n.reports, indent + 1) : "";
|
|
11627
|
+
return line + children;
|
|
11628
|
+
}).join(`
|
|
11629
|
+
`);
|
|
11630
|
+
};
|
|
11631
|
+
const { getProjectOrgChart: getProjectOrgChart2 } = (init_project_agent_roles(), __toCommonJS(exports_project_agent_roles));
|
|
11632
|
+
const pid = resolveId(project_id, "projects");
|
|
11633
|
+
const tree = getProjectOrgChart2(pid, { filter_to_project });
|
|
11634
|
+
if (format === "json") {
|
|
11635
|
+
return { content: [{ type: "text", text: JSON.stringify(tree, null, 2) }] };
|
|
11636
|
+
}
|
|
11637
|
+
const now2 = Date.now();
|
|
11638
|
+
const ACTIVE_MS = 30 * 60 * 1000;
|
|
11639
|
+
const text = tree.length > 0 ? render(tree) : "No agents in this project's org chart.";
|
|
11640
|
+
return { content: [{ type: "text", text }] };
|
|
11641
|
+
} catch (e) {
|
|
11642
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
11643
|
+
}
|
|
11644
|
+
});
|
|
11645
|
+
}
|
|
11646
|
+
if (shouldRegisterTool("list_project_agent_roles")) {
|
|
11647
|
+
server.tool("list_project_agent_roles", "List all agent role assignments for a project.", {
|
|
11648
|
+
project_id: exports_external.string().describe("Project ID")
|
|
11649
|
+
}, async ({ project_id }) => {
|
|
11650
|
+
try {
|
|
11651
|
+
const { listProjectAgentRoles: listProjectAgentRoles2 } = (init_project_agent_roles(), __toCommonJS(exports_project_agent_roles));
|
|
11652
|
+
const pid = resolveId(project_id, "projects");
|
|
11653
|
+
const roles = listProjectAgentRoles2(pid);
|
|
11654
|
+
return { content: [{ type: "text", text: JSON.stringify(roles, null, 2) }] };
|
|
11655
|
+
} catch (e) {
|
|
11656
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
11657
|
+
}
|
|
11658
|
+
});
|
|
11659
|
+
}
|
|
11499
11660
|
if (shouldRegisterTool("get_capable_agents")) {
|
|
11500
11661
|
server.tool("get_capable_agents", "Find agents that match given capabilities, sorted by match score.", {
|
|
11501
11662
|
capabilities: exports_external.array(exports_external.string()).describe("Required capabilities to match against"),
|
package/dist/server/index.js
CHANGED
|
@@ -858,6 +858,20 @@ var init_database = __esm(() => {
|
|
|
858
858
|
ALTER TABLE agents ADD COLUMN status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'archived'));
|
|
859
859
|
CREATE INDEX IF NOT EXISTS idx_agents_status ON agents(status);
|
|
860
860
|
INSERT OR IGNORE INTO _migrations (id) VALUES (30);
|
|
861
|
+
`,
|
|
862
|
+
`
|
|
863
|
+
CREATE TABLE IF NOT EXISTS project_agent_roles (
|
|
864
|
+
id TEXT PRIMARY KEY,
|
|
865
|
+
project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
866
|
+
agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
|
|
867
|
+
role TEXT NOT NULL,
|
|
868
|
+
is_lead INTEGER NOT NULL DEFAULT 0,
|
|
869
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
870
|
+
UNIQUE(project_id, agent_id, role)
|
|
871
|
+
);
|
|
872
|
+
CREATE INDEX IF NOT EXISTS idx_project_agent_roles_project ON project_agent_roles(project_id);
|
|
873
|
+
CREATE INDEX IF NOT EXISTS idx_project_agent_roles_agent ON project_agent_roles(agent_id);
|
|
874
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (31);
|
|
861
875
|
`,
|
|
862
876
|
`
|
|
863
877
|
CREATE TABLE IF NOT EXISTS file_locks (
|
|
@@ -871,7 +885,7 @@ var init_database = __esm(() => {
|
|
|
871
885
|
CREATE INDEX IF NOT EXISTS idx_file_locks_path ON file_locks(path);
|
|
872
886
|
CREATE INDEX IF NOT EXISTS idx_file_locks_agent ON file_locks(agent_id);
|
|
873
887
|
CREATE INDEX IF NOT EXISTS idx_file_locks_expires ON file_locks(expires_at);
|
|
874
|
-
INSERT OR IGNORE INTO _migrations (id) VALUES (
|
|
888
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (32);
|
|
875
889
|
`
|
|
876
890
|
];
|
|
877
891
|
});
|