@hasna/todos 0.9.29 → 0.9.31
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 +149 -2
- package/dist/index.js +47 -2
- package/dist/mcp/index.js +192 -48
- package/dist/server/index.js +57 -2
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2253,6 +2253,9 @@ function ensureSchema(db) {
|
|
|
2253
2253
|
ensureColumn("tasks", "approved_at", "TEXT");
|
|
2254
2254
|
ensureColumn("agents", "role", "TEXT DEFAULT 'agent'");
|
|
2255
2255
|
ensureColumn("agents", "permissions", `TEXT DEFAULT '["*"]'`);
|
|
2256
|
+
ensureColumn("agents", "reports_to", "TEXT");
|
|
2257
|
+
ensureColumn("agents", "title", "TEXT");
|
|
2258
|
+
ensureColumn("agents", "level", "TEXT");
|
|
2256
2259
|
ensureColumn("plans", "task_list_id", "TEXT");
|
|
2257
2260
|
ensureColumn("plans", "agent_id", "TEXT");
|
|
2258
2261
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_plan ON tasks(plan_id)");
|
|
@@ -2544,6 +2547,12 @@ var init_database = __esm(() => {
|
|
|
2544
2547
|
ALTER TABLE agents ADD COLUMN permissions TEXT DEFAULT '["*"]';
|
|
2545
2548
|
|
|
2546
2549
|
INSERT OR IGNORE INTO _migrations (id) VALUES (10);
|
|
2550
|
+
`,
|
|
2551
|
+
`
|
|
2552
|
+
ALTER TABLE agents ADD COLUMN reports_to TEXT;
|
|
2553
|
+
ALTER TABLE agents ADD COLUMN title TEXT;
|
|
2554
|
+
ALTER TABLE agents ADD COLUMN level TEXT;
|
|
2555
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (11);
|
|
2547
2556
|
`
|
|
2548
2557
|
];
|
|
2549
2558
|
});
|
|
@@ -3363,6 +3372,8 @@ __export(exports_agents, {
|
|
|
3363
3372
|
updateAgent: () => updateAgent,
|
|
3364
3373
|
registerAgent: () => registerAgent,
|
|
3365
3374
|
listAgents: () => listAgents,
|
|
3375
|
+
getOrgChart: () => getOrgChart,
|
|
3376
|
+
getDirectReports: () => getDirectReports,
|
|
3366
3377
|
getAgentByName: () => getAgentByName,
|
|
3367
3378
|
getAgent: () => getAgent,
|
|
3368
3379
|
deleteAgent: () => deleteAgent
|
|
@@ -3386,13 +3397,16 @@ function registerAgent(input, db) {
|
|
|
3386
3397
|
}
|
|
3387
3398
|
const id = shortUuid();
|
|
3388
3399
|
const timestamp = now();
|
|
3389
|
-
d.run(`INSERT INTO agents (id, name, description, role, permissions, metadata, created_at, last_seen_at)
|
|
3390
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
3400
|
+
d.run(`INSERT INTO agents (id, name, description, role, title, level, permissions, reports_to, metadata, created_at, last_seen_at)
|
|
3401
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
3391
3402
|
id,
|
|
3392
3403
|
input.name,
|
|
3393
3404
|
input.description || null,
|
|
3394
3405
|
input.role || "agent",
|
|
3406
|
+
input.title || null,
|
|
3407
|
+
input.level || null,
|
|
3395
3408
|
JSON.stringify(input.permissions || ["*"]),
|
|
3409
|
+
input.reports_to || null,
|
|
3396
3410
|
JSON.stringify(input.metadata || {}),
|
|
3397
3411
|
timestamp,
|
|
3398
3412
|
timestamp
|
|
@@ -3440,6 +3454,18 @@ function updateAgent(id, input, db) {
|
|
|
3440
3454
|
sets.push("permissions = ?");
|
|
3441
3455
|
params.push(JSON.stringify(input.permissions));
|
|
3442
3456
|
}
|
|
3457
|
+
if (input.title !== undefined) {
|
|
3458
|
+
sets.push("title = ?");
|
|
3459
|
+
params.push(input.title);
|
|
3460
|
+
}
|
|
3461
|
+
if (input.level !== undefined) {
|
|
3462
|
+
sets.push("level = ?");
|
|
3463
|
+
params.push(input.level);
|
|
3464
|
+
}
|
|
3465
|
+
if (input.reports_to !== undefined) {
|
|
3466
|
+
sets.push("reports_to = ?");
|
|
3467
|
+
params.push(input.reports_to);
|
|
3468
|
+
}
|
|
3443
3469
|
if (input.metadata !== undefined) {
|
|
3444
3470
|
sets.push("metadata = ?");
|
|
3445
3471
|
params.push(JSON.stringify(input.metadata));
|
|
@@ -3452,6 +3478,25 @@ function deleteAgent(id, db) {
|
|
|
3452
3478
|
const d = db || getDatabase();
|
|
3453
3479
|
return d.run("DELETE FROM agents WHERE id = ?", [id]).changes > 0;
|
|
3454
3480
|
}
|
|
3481
|
+
function getDirectReports(agentId, db) {
|
|
3482
|
+
const d = db || getDatabase();
|
|
3483
|
+
return d.query("SELECT * FROM agents WHERE reports_to = ? ORDER BY name").all(agentId).map(rowToAgent);
|
|
3484
|
+
}
|
|
3485
|
+
function getOrgChart(db) {
|
|
3486
|
+
const agents = listAgents(db);
|
|
3487
|
+
const byManager = new Map;
|
|
3488
|
+
for (const a of agents) {
|
|
3489
|
+
const key = a.reports_to;
|
|
3490
|
+
if (!byManager.has(key))
|
|
3491
|
+
byManager.set(key, []);
|
|
3492
|
+
byManager.get(key).push(a);
|
|
3493
|
+
}
|
|
3494
|
+
function buildTree(parentId) {
|
|
3495
|
+
const children = byManager.get(parentId) || [];
|
|
3496
|
+
return children.map((a) => ({ agent: a, reports: buildTree(a.id) }));
|
|
3497
|
+
}
|
|
3498
|
+
return buildTree(null);
|
|
3499
|
+
}
|
|
3455
3500
|
var init_agents = __esm(() => {
|
|
3456
3501
|
init_database();
|
|
3457
3502
|
});
|
|
@@ -9205,6 +9250,51 @@ In Progress:`);
|
|
|
9205
9250
|
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
9206
9251
|
}
|
|
9207
9252
|
});
|
|
9253
|
+
server.tool("get_org_chart", "Get agent org chart \u2014 who reports to who.", {}, async () => {
|
|
9254
|
+
try {
|
|
9255
|
+
let render = function(nodes, indent = 0) {
|
|
9256
|
+
return nodes.map((n) => {
|
|
9257
|
+
const prefix = " ".repeat(indent);
|
|
9258
|
+
const title = n.agent.title ? ` \u2014 ${n.agent.title}` : "";
|
|
9259
|
+
const level = n.agent.level ? ` (${n.agent.level})` : "";
|
|
9260
|
+
const line = `${prefix}${n.agent.name}${title}${level}`;
|
|
9261
|
+
const children = n.reports.length > 0 ? `
|
|
9262
|
+
` + render(n.reports, indent + 1) : "";
|
|
9263
|
+
return line + children;
|
|
9264
|
+
}).join(`
|
|
9265
|
+
`);
|
|
9266
|
+
};
|
|
9267
|
+
const { getOrgChart: getOrgChart2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
9268
|
+
const tree = getOrgChart2();
|
|
9269
|
+
const text = tree.length > 0 ? render(tree) : "No agents registered.";
|
|
9270
|
+
return { content: [{ type: "text", text }] };
|
|
9271
|
+
} catch (e) {
|
|
9272
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
9273
|
+
}
|
|
9274
|
+
});
|
|
9275
|
+
server.tool("set_reports_to", "Set who an agent reports to in the org chart.", {
|
|
9276
|
+
agent_name: exports_external.string(),
|
|
9277
|
+
manager_name: exports_external.string().optional()
|
|
9278
|
+
}, async ({ agent_name, manager_name }) => {
|
|
9279
|
+
try {
|
|
9280
|
+
const agent = getAgentByName(agent_name);
|
|
9281
|
+
if (!agent)
|
|
9282
|
+
return { content: [{ type: "text", text: `Agent not found: ${agent_name}` }], isError: true };
|
|
9283
|
+
let managerId = null;
|
|
9284
|
+
if (manager_name) {
|
|
9285
|
+
const manager = getAgentByName(manager_name);
|
|
9286
|
+
if (!manager)
|
|
9287
|
+
return { content: [{ type: "text", text: `Manager not found: ${manager_name}` }], isError: true };
|
|
9288
|
+
managerId = manager.id;
|
|
9289
|
+
}
|
|
9290
|
+
const { updateAgent: updateAgent2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
9291
|
+
updateAgent2(agent.id, { reports_to: managerId });
|
|
9292
|
+
const result = managerId ? `${agent_name} now reports to ${manager_name}` : `${agent_name} reports to no one (top-level)`;
|
|
9293
|
+
return { content: [{ type: "text", text: result }] };
|
|
9294
|
+
} catch (e) {
|
|
9295
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
9296
|
+
}
|
|
9297
|
+
});
|
|
9208
9298
|
server.tool("search_tools", "List tool names matching a query.", { query: exports_external.string().optional() }, async ({ query }) => {
|
|
9209
9299
|
const all = [
|
|
9210
9300
|
"create_task",
|
|
@@ -9656,6 +9746,16 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
9656
9746
|
return json({ error: e instanceof Error ? e.message : "Failed to claim" }, 500, port);
|
|
9657
9747
|
}
|
|
9658
9748
|
}
|
|
9749
|
+
if (path === "/api/org" && method === "GET") {
|
|
9750
|
+
const { getOrgChart: getOrgChart2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
9751
|
+
return json(getOrgChart2(), 200, port);
|
|
9752
|
+
}
|
|
9753
|
+
const teamMatch = path.match(/^\/api\/agents\/([^/]+)\/team$/);
|
|
9754
|
+
if (teamMatch && method === "GET") {
|
|
9755
|
+
const agentId = decodeURIComponent(teamMatch[1]);
|
|
9756
|
+
const { getDirectReports: getDirectReports2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
9757
|
+
return json(getDirectReports2(agentId), 200, port);
|
|
9758
|
+
}
|
|
9659
9759
|
if (path === "/api/agents" && method === "GET") {
|
|
9660
9760
|
return json(listAgents(), 200, port);
|
|
9661
9761
|
}
|
|
@@ -12194,6 +12294,53 @@ program2.command("agents").description("List registered agents").action(() => {
|
|
|
12194
12294
|
handleError(e);
|
|
12195
12295
|
}
|
|
12196
12296
|
});
|
|
12297
|
+
program2.command("org").description("Show agent org chart \u2014 who reports to who").option("--set <agent=manager>", "Set reporting: 'seneca=julius' or 'seneca=' to clear").action((opts) => {
|
|
12298
|
+
const globalOpts = program2.opts();
|
|
12299
|
+
const { getOrgChart: getOrgChart2, getAgentByName: getByName, updateAgent: update } = (init_agents(), __toCommonJS(exports_agents));
|
|
12300
|
+
if (opts.set) {
|
|
12301
|
+
const [agentName, managerName] = opts.set.split("=");
|
|
12302
|
+
const agent = getByName(agentName);
|
|
12303
|
+
if (!agent) {
|
|
12304
|
+
console.error(chalk.red(`Agent not found: ${agentName}`));
|
|
12305
|
+
process.exit(1);
|
|
12306
|
+
}
|
|
12307
|
+
let managerId = null;
|
|
12308
|
+
if (managerName) {
|
|
12309
|
+
const manager = getByName(managerName);
|
|
12310
|
+
if (!manager) {
|
|
12311
|
+
console.error(chalk.red(`Manager not found: ${managerName}`));
|
|
12312
|
+
process.exit(1);
|
|
12313
|
+
}
|
|
12314
|
+
managerId = manager.id;
|
|
12315
|
+
}
|
|
12316
|
+
update(agent.id, { reports_to: managerId });
|
|
12317
|
+
if (globalOpts.json) {
|
|
12318
|
+
output({ agent: agentName, reports_to: managerName || null }, true);
|
|
12319
|
+
} else {
|
|
12320
|
+
console.log(chalk.green(managerId ? `${agentName} \u2192 ${managerName}` : `${agentName} \u2192 (top-level)`));
|
|
12321
|
+
}
|
|
12322
|
+
return;
|
|
12323
|
+
}
|
|
12324
|
+
const tree = getOrgChart2();
|
|
12325
|
+
if (globalOpts.json) {
|
|
12326
|
+
output(tree, true);
|
|
12327
|
+
return;
|
|
12328
|
+
}
|
|
12329
|
+
if (tree.length === 0) {
|
|
12330
|
+
console.log(chalk.dim("No agents registered."));
|
|
12331
|
+
return;
|
|
12332
|
+
}
|
|
12333
|
+
function render2(nodes, indent = 0) {
|
|
12334
|
+
for (const n of nodes) {
|
|
12335
|
+
const prefix = " ".repeat(indent);
|
|
12336
|
+
const title = n.agent.title ? chalk.cyan(` \u2014 ${n.agent.title}`) : "";
|
|
12337
|
+
const level = n.agent.level ? chalk.dim(` (${n.agent.level})`) : "";
|
|
12338
|
+
console.log(`${prefix}${indent > 0 ? "\u251C\u2500\u2500 " : ""}${chalk.bold(n.agent.name)}${title}${level}`);
|
|
12339
|
+
render2(n.reports, indent + 1);
|
|
12340
|
+
}
|
|
12341
|
+
}
|
|
12342
|
+
render2(tree);
|
|
12343
|
+
});
|
|
12197
12344
|
program2.command("lists").aliases(["task-lists", "tl"]).description("List and manage task lists").option("--add <name>", "Create a task list").option("--slug <slug>", "Custom slug (with --add)").option("-d, --description <text>", "Description (with --add)").option("--delete <id>", "Delete a task list").action((opts) => {
|
|
12198
12345
|
try {
|
|
12199
12346
|
const globalOpts = program2.opts();
|
package/dist/index.js
CHANGED
|
@@ -264,6 +264,12 @@ var MIGRATIONS = [
|
|
|
264
264
|
ALTER TABLE agents ADD COLUMN permissions TEXT DEFAULT '["*"]';
|
|
265
265
|
|
|
266
266
|
INSERT OR IGNORE INTO _migrations (id) VALUES (10);
|
|
267
|
+
`,
|
|
268
|
+
`
|
|
269
|
+
ALTER TABLE agents ADD COLUMN reports_to TEXT;
|
|
270
|
+
ALTER TABLE agents ADD COLUMN title TEXT;
|
|
271
|
+
ALTER TABLE agents ADD COLUMN level TEXT;
|
|
272
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (11);
|
|
267
273
|
`
|
|
268
274
|
];
|
|
269
275
|
var _db = null;
|
|
@@ -385,6 +391,9 @@ function ensureSchema(db) {
|
|
|
385
391
|
ensureColumn("tasks", "approved_at", "TEXT");
|
|
386
392
|
ensureColumn("agents", "role", "TEXT DEFAULT 'agent'");
|
|
387
393
|
ensureColumn("agents", "permissions", `TEXT DEFAULT '["*"]'`);
|
|
394
|
+
ensureColumn("agents", "reports_to", "TEXT");
|
|
395
|
+
ensureColumn("agents", "title", "TEXT");
|
|
396
|
+
ensureColumn("agents", "level", "TEXT");
|
|
388
397
|
ensureColumn("plans", "task_list_id", "TEXT");
|
|
389
398
|
ensureColumn("plans", "agent_id", "TEXT");
|
|
390
399
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_plan ON tasks(plan_id)");
|
|
@@ -1388,13 +1397,16 @@ function registerAgent(input, db) {
|
|
|
1388
1397
|
}
|
|
1389
1398
|
const id = shortUuid();
|
|
1390
1399
|
const timestamp = now();
|
|
1391
|
-
d.run(`INSERT INTO agents (id, name, description, role, permissions, metadata, created_at, last_seen_at)
|
|
1392
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
1400
|
+
d.run(`INSERT INTO agents (id, name, description, role, title, level, permissions, reports_to, metadata, created_at, last_seen_at)
|
|
1401
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
1393
1402
|
id,
|
|
1394
1403
|
input.name,
|
|
1395
1404
|
input.description || null,
|
|
1396
1405
|
input.role || "agent",
|
|
1406
|
+
input.title || null,
|
|
1407
|
+
input.level || null,
|
|
1397
1408
|
JSON.stringify(input.permissions || ["*"]),
|
|
1409
|
+
input.reports_to || null,
|
|
1398
1410
|
JSON.stringify(input.metadata || {}),
|
|
1399
1411
|
timestamp,
|
|
1400
1412
|
timestamp
|
|
@@ -1442,6 +1454,18 @@ function updateAgent(id, input, db) {
|
|
|
1442
1454
|
sets.push("permissions = ?");
|
|
1443
1455
|
params.push(JSON.stringify(input.permissions));
|
|
1444
1456
|
}
|
|
1457
|
+
if (input.title !== undefined) {
|
|
1458
|
+
sets.push("title = ?");
|
|
1459
|
+
params.push(input.title);
|
|
1460
|
+
}
|
|
1461
|
+
if (input.level !== undefined) {
|
|
1462
|
+
sets.push("level = ?");
|
|
1463
|
+
params.push(input.level);
|
|
1464
|
+
}
|
|
1465
|
+
if (input.reports_to !== undefined) {
|
|
1466
|
+
sets.push("reports_to = ?");
|
|
1467
|
+
params.push(input.reports_to);
|
|
1468
|
+
}
|
|
1445
1469
|
if (input.metadata !== undefined) {
|
|
1446
1470
|
sets.push("metadata = ?");
|
|
1447
1471
|
params.push(JSON.stringify(input.metadata));
|
|
@@ -1454,6 +1478,25 @@ function deleteAgent(id, db) {
|
|
|
1454
1478
|
const d = db || getDatabase();
|
|
1455
1479
|
return d.run("DELETE FROM agents WHERE id = ?", [id]).changes > 0;
|
|
1456
1480
|
}
|
|
1481
|
+
function getDirectReports(agentId, db) {
|
|
1482
|
+
const d = db || getDatabase();
|
|
1483
|
+
return d.query("SELECT * FROM agents WHERE reports_to = ? ORDER BY name").all(agentId).map(rowToAgent);
|
|
1484
|
+
}
|
|
1485
|
+
function getOrgChart(db) {
|
|
1486
|
+
const agents = listAgents(db);
|
|
1487
|
+
const byManager = new Map;
|
|
1488
|
+
for (const a of agents) {
|
|
1489
|
+
const key = a.reports_to;
|
|
1490
|
+
if (!byManager.has(key))
|
|
1491
|
+
byManager.set(key, []);
|
|
1492
|
+
byManager.get(key).push(a);
|
|
1493
|
+
}
|
|
1494
|
+
function buildTree(parentId) {
|
|
1495
|
+
const children = byManager.get(parentId) || [];
|
|
1496
|
+
return children.map((a) => ({ agent: a, reports: buildTree(a.id) }));
|
|
1497
|
+
}
|
|
1498
|
+
return buildTree(null);
|
|
1499
|
+
}
|
|
1457
1500
|
// src/db/task-lists.ts
|
|
1458
1501
|
function rowToTaskList(row) {
|
|
1459
1502
|
return {
|
|
@@ -2264,6 +2307,8 @@ export {
|
|
|
2264
2307
|
getProjectByPath,
|
|
2265
2308
|
getProject,
|
|
2266
2309
|
getPlan,
|
|
2310
|
+
getOrgChart,
|
|
2311
|
+
getDirectReports,
|
|
2267
2312
|
getDatabase,
|
|
2268
2313
|
getCompletionGuardConfig,
|
|
2269
2314
|
getComment,
|
package/dist/mcp/index.js
CHANGED
|
@@ -187,6 +187,9 @@ function ensureSchema(db) {
|
|
|
187
187
|
ensureColumn("tasks", "approved_at", "TEXT");
|
|
188
188
|
ensureColumn("agents", "role", "TEXT DEFAULT 'agent'");
|
|
189
189
|
ensureColumn("agents", "permissions", `TEXT DEFAULT '["*"]'`);
|
|
190
|
+
ensureColumn("agents", "reports_to", "TEXT");
|
|
191
|
+
ensureColumn("agents", "title", "TEXT");
|
|
192
|
+
ensureColumn("agents", "level", "TEXT");
|
|
190
193
|
ensureColumn("plans", "task_list_id", "TEXT");
|
|
191
194
|
ensureColumn("plans", "agent_id", "TEXT");
|
|
192
195
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_plan ON tasks(plan_id)");
|
|
@@ -478,6 +481,12 @@ var init_database = __esm(() => {
|
|
|
478
481
|
ALTER TABLE agents ADD COLUMN permissions TEXT DEFAULT '["*"]';
|
|
479
482
|
|
|
480
483
|
INSERT OR IGNORE INTO _migrations (id) VALUES (10);
|
|
484
|
+
`,
|
|
485
|
+
`
|
|
486
|
+
ALTER TABLE agents ADD COLUMN reports_to TEXT;
|
|
487
|
+
ALTER TABLE agents ADD COLUMN title TEXT;
|
|
488
|
+
ALTER TABLE agents ADD COLUMN level TEXT;
|
|
489
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (11);
|
|
481
490
|
`
|
|
482
491
|
];
|
|
483
492
|
});
|
|
@@ -509,6 +518,142 @@ var init_audit = __esm(() => {
|
|
|
509
518
|
init_database();
|
|
510
519
|
});
|
|
511
520
|
|
|
521
|
+
// src/db/agents.ts
|
|
522
|
+
var exports_agents = {};
|
|
523
|
+
__export(exports_agents, {
|
|
524
|
+
updateAgentActivity: () => updateAgentActivity,
|
|
525
|
+
updateAgent: () => updateAgent,
|
|
526
|
+
registerAgent: () => registerAgent,
|
|
527
|
+
listAgents: () => listAgents,
|
|
528
|
+
getOrgChart: () => getOrgChart,
|
|
529
|
+
getDirectReports: () => getDirectReports,
|
|
530
|
+
getAgentByName: () => getAgentByName,
|
|
531
|
+
getAgent: () => getAgent,
|
|
532
|
+
deleteAgent: () => deleteAgent
|
|
533
|
+
});
|
|
534
|
+
function shortUuid() {
|
|
535
|
+
return crypto.randomUUID().slice(0, 8);
|
|
536
|
+
}
|
|
537
|
+
function rowToAgent(row) {
|
|
538
|
+
return {
|
|
539
|
+
...row,
|
|
540
|
+
permissions: JSON.parse(row.permissions || '["*"]'),
|
|
541
|
+
metadata: JSON.parse(row.metadata || "{}")
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
function registerAgent(input, db) {
|
|
545
|
+
const d = db || getDatabase();
|
|
546
|
+
const existing = getAgentByName(input.name, d);
|
|
547
|
+
if (existing) {
|
|
548
|
+
d.run("UPDATE agents SET last_seen_at = ? WHERE id = ?", [now(), existing.id]);
|
|
549
|
+
return getAgent(existing.id, d);
|
|
550
|
+
}
|
|
551
|
+
const id = shortUuid();
|
|
552
|
+
const timestamp = now();
|
|
553
|
+
d.run(`INSERT INTO agents (id, name, description, role, title, level, permissions, reports_to, metadata, created_at, last_seen_at)
|
|
554
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
555
|
+
id,
|
|
556
|
+
input.name,
|
|
557
|
+
input.description || null,
|
|
558
|
+
input.role || "agent",
|
|
559
|
+
input.title || null,
|
|
560
|
+
input.level || null,
|
|
561
|
+
JSON.stringify(input.permissions || ["*"]),
|
|
562
|
+
input.reports_to || null,
|
|
563
|
+
JSON.stringify(input.metadata || {}),
|
|
564
|
+
timestamp,
|
|
565
|
+
timestamp
|
|
566
|
+
]);
|
|
567
|
+
return getAgent(id, d);
|
|
568
|
+
}
|
|
569
|
+
function getAgent(id, db) {
|
|
570
|
+
const d = db || getDatabase();
|
|
571
|
+
const row = d.query("SELECT * FROM agents WHERE id = ?").get(id);
|
|
572
|
+
return row ? rowToAgent(row) : null;
|
|
573
|
+
}
|
|
574
|
+
function getAgentByName(name, db) {
|
|
575
|
+
const d = db || getDatabase();
|
|
576
|
+
const row = d.query("SELECT * FROM agents WHERE name = ?").get(name);
|
|
577
|
+
return row ? rowToAgent(row) : null;
|
|
578
|
+
}
|
|
579
|
+
function listAgents(db) {
|
|
580
|
+
const d = db || getDatabase();
|
|
581
|
+
return d.query("SELECT * FROM agents ORDER BY name").all().map(rowToAgent);
|
|
582
|
+
}
|
|
583
|
+
function updateAgentActivity(id, db) {
|
|
584
|
+
const d = db || getDatabase();
|
|
585
|
+
d.run("UPDATE agents SET last_seen_at = ? WHERE id = ?", [now(), id]);
|
|
586
|
+
}
|
|
587
|
+
function updateAgent(id, input, db) {
|
|
588
|
+
const d = db || getDatabase();
|
|
589
|
+
const agent = getAgent(id, d);
|
|
590
|
+
if (!agent)
|
|
591
|
+
throw new Error(`Agent not found: ${id}`);
|
|
592
|
+
const sets = ["last_seen_at = ?"];
|
|
593
|
+
const params = [now()];
|
|
594
|
+
if (input.name !== undefined) {
|
|
595
|
+
sets.push("name = ?");
|
|
596
|
+
params.push(input.name);
|
|
597
|
+
}
|
|
598
|
+
if (input.description !== undefined) {
|
|
599
|
+
sets.push("description = ?");
|
|
600
|
+
params.push(input.description);
|
|
601
|
+
}
|
|
602
|
+
if (input.role !== undefined) {
|
|
603
|
+
sets.push("role = ?");
|
|
604
|
+
params.push(input.role);
|
|
605
|
+
}
|
|
606
|
+
if (input.permissions !== undefined) {
|
|
607
|
+
sets.push("permissions = ?");
|
|
608
|
+
params.push(JSON.stringify(input.permissions));
|
|
609
|
+
}
|
|
610
|
+
if (input.title !== undefined) {
|
|
611
|
+
sets.push("title = ?");
|
|
612
|
+
params.push(input.title);
|
|
613
|
+
}
|
|
614
|
+
if (input.level !== undefined) {
|
|
615
|
+
sets.push("level = ?");
|
|
616
|
+
params.push(input.level);
|
|
617
|
+
}
|
|
618
|
+
if (input.reports_to !== undefined) {
|
|
619
|
+
sets.push("reports_to = ?");
|
|
620
|
+
params.push(input.reports_to);
|
|
621
|
+
}
|
|
622
|
+
if (input.metadata !== undefined) {
|
|
623
|
+
sets.push("metadata = ?");
|
|
624
|
+
params.push(JSON.stringify(input.metadata));
|
|
625
|
+
}
|
|
626
|
+
params.push(id);
|
|
627
|
+
d.run(`UPDATE agents SET ${sets.join(", ")} WHERE id = ?`, params);
|
|
628
|
+
return getAgent(id, d);
|
|
629
|
+
}
|
|
630
|
+
function deleteAgent(id, db) {
|
|
631
|
+
const d = db || getDatabase();
|
|
632
|
+
return d.run("DELETE FROM agents WHERE id = ?", [id]).changes > 0;
|
|
633
|
+
}
|
|
634
|
+
function getDirectReports(agentId, db) {
|
|
635
|
+
const d = db || getDatabase();
|
|
636
|
+
return d.query("SELECT * FROM agents WHERE reports_to = ? ORDER BY name").all(agentId).map(rowToAgent);
|
|
637
|
+
}
|
|
638
|
+
function getOrgChart(db) {
|
|
639
|
+
const agents = listAgents(db);
|
|
640
|
+
const byManager = new Map;
|
|
641
|
+
for (const a of agents) {
|
|
642
|
+
const key = a.reports_to;
|
|
643
|
+
if (!byManager.has(key))
|
|
644
|
+
byManager.set(key, []);
|
|
645
|
+
byManager.get(key).push(a);
|
|
646
|
+
}
|
|
647
|
+
function buildTree(parentId) {
|
|
648
|
+
const children = byManager.get(parentId) || [];
|
|
649
|
+
return children.map((a) => ({ agent: a, reports: buildTree(a.id) }));
|
|
650
|
+
}
|
|
651
|
+
return buildTree(null);
|
|
652
|
+
}
|
|
653
|
+
var init_agents = __esm(() => {
|
|
654
|
+
init_database();
|
|
655
|
+
});
|
|
656
|
+
|
|
512
657
|
// src/db/webhooks.ts
|
|
513
658
|
var exports_webhooks = {};
|
|
514
659
|
__export(exports_webhooks, {
|
|
@@ -5399,54 +5544,8 @@ function deletePlan(id, db) {
|
|
|
5399
5544
|
return result.changes > 0;
|
|
5400
5545
|
}
|
|
5401
5546
|
|
|
5402
|
-
// src/
|
|
5403
|
-
|
|
5404
|
-
function shortUuid() {
|
|
5405
|
-
return crypto.randomUUID().slice(0, 8);
|
|
5406
|
-
}
|
|
5407
|
-
function rowToAgent(row) {
|
|
5408
|
-
return {
|
|
5409
|
-
...row,
|
|
5410
|
-
permissions: JSON.parse(row.permissions || '["*"]'),
|
|
5411
|
-
metadata: JSON.parse(row.metadata || "{}")
|
|
5412
|
-
};
|
|
5413
|
-
}
|
|
5414
|
-
function registerAgent(input, db) {
|
|
5415
|
-
const d = db || getDatabase();
|
|
5416
|
-
const existing = getAgentByName(input.name, d);
|
|
5417
|
-
if (existing) {
|
|
5418
|
-
d.run("UPDATE agents SET last_seen_at = ? WHERE id = ?", [now(), existing.id]);
|
|
5419
|
-
return getAgent(existing.id, d);
|
|
5420
|
-
}
|
|
5421
|
-
const id = shortUuid();
|
|
5422
|
-
const timestamp = now();
|
|
5423
|
-
d.run(`INSERT INTO agents (id, name, description, role, permissions, metadata, created_at, last_seen_at)
|
|
5424
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
5425
|
-
id,
|
|
5426
|
-
input.name,
|
|
5427
|
-
input.description || null,
|
|
5428
|
-
input.role || "agent",
|
|
5429
|
-
JSON.stringify(input.permissions || ["*"]),
|
|
5430
|
-
JSON.stringify(input.metadata || {}),
|
|
5431
|
-
timestamp,
|
|
5432
|
-
timestamp
|
|
5433
|
-
]);
|
|
5434
|
-
return getAgent(id, d);
|
|
5435
|
-
}
|
|
5436
|
-
function getAgent(id, db) {
|
|
5437
|
-
const d = db || getDatabase();
|
|
5438
|
-
const row = d.query("SELECT * FROM agents WHERE id = ?").get(id);
|
|
5439
|
-
return row ? rowToAgent(row) : null;
|
|
5440
|
-
}
|
|
5441
|
-
function getAgentByName(name, db) {
|
|
5442
|
-
const d = db || getDatabase();
|
|
5443
|
-
const row = d.query("SELECT * FROM agents WHERE name = ?").get(name);
|
|
5444
|
-
return row ? rowToAgent(row) : null;
|
|
5445
|
-
}
|
|
5446
|
-
function listAgents(db) {
|
|
5447
|
-
const d = db || getDatabase();
|
|
5448
|
-
return d.query("SELECT * FROM agents ORDER BY name").all().map(rowToAgent);
|
|
5449
|
-
}
|
|
5547
|
+
// src/mcp/index.ts
|
|
5548
|
+
init_agents();
|
|
5450
5549
|
|
|
5451
5550
|
// src/db/task-lists.ts
|
|
5452
5551
|
init_database();
|
|
@@ -6971,6 +7070,51 @@ In Progress:`);
|
|
|
6971
7070
|
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
6972
7071
|
}
|
|
6973
7072
|
});
|
|
7073
|
+
server.tool("get_org_chart", "Get agent org chart \u2014 who reports to who.", {}, async () => {
|
|
7074
|
+
try {
|
|
7075
|
+
let render = function(nodes, indent = 0) {
|
|
7076
|
+
return nodes.map((n) => {
|
|
7077
|
+
const prefix = " ".repeat(indent);
|
|
7078
|
+
const title = n.agent.title ? ` \u2014 ${n.agent.title}` : "";
|
|
7079
|
+
const level = n.agent.level ? ` (${n.agent.level})` : "";
|
|
7080
|
+
const line = `${prefix}${n.agent.name}${title}${level}`;
|
|
7081
|
+
const children = n.reports.length > 0 ? `
|
|
7082
|
+
` + render(n.reports, indent + 1) : "";
|
|
7083
|
+
return line + children;
|
|
7084
|
+
}).join(`
|
|
7085
|
+
`);
|
|
7086
|
+
};
|
|
7087
|
+
const { getOrgChart: getOrgChart2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
7088
|
+
const tree = getOrgChart2();
|
|
7089
|
+
const text = tree.length > 0 ? render(tree) : "No agents registered.";
|
|
7090
|
+
return { content: [{ type: "text", text }] };
|
|
7091
|
+
} catch (e) {
|
|
7092
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
7093
|
+
}
|
|
7094
|
+
});
|
|
7095
|
+
server.tool("set_reports_to", "Set who an agent reports to in the org chart.", {
|
|
7096
|
+
agent_name: exports_external.string(),
|
|
7097
|
+
manager_name: exports_external.string().optional()
|
|
7098
|
+
}, async ({ agent_name, manager_name }) => {
|
|
7099
|
+
try {
|
|
7100
|
+
const agent = getAgentByName(agent_name);
|
|
7101
|
+
if (!agent)
|
|
7102
|
+
return { content: [{ type: "text", text: `Agent not found: ${agent_name}` }], isError: true };
|
|
7103
|
+
let managerId = null;
|
|
7104
|
+
if (manager_name) {
|
|
7105
|
+
const manager = getAgentByName(manager_name);
|
|
7106
|
+
if (!manager)
|
|
7107
|
+
return { content: [{ type: "text", text: `Manager not found: ${manager_name}` }], isError: true };
|
|
7108
|
+
managerId = manager.id;
|
|
7109
|
+
}
|
|
7110
|
+
const { updateAgent: updateAgent2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
7111
|
+
updateAgent2(agent.id, { reports_to: managerId });
|
|
7112
|
+
const result = managerId ? `${agent_name} now reports to ${manager_name}` : `${agent_name} reports to no one (top-level)`;
|
|
7113
|
+
return { content: [{ type: "text", text: result }] };
|
|
7114
|
+
} catch (e) {
|
|
7115
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
7116
|
+
}
|
|
7117
|
+
});
|
|
6974
7118
|
server.tool("search_tools", "List tool names matching a query.", { query: exports_external.string().optional() }, async ({ query }) => {
|
|
6975
7119
|
const all = [
|
|
6976
7120
|
"create_task",
|
package/dist/server/index.js
CHANGED
|
@@ -249,6 +249,9 @@ function ensureSchema(db) {
|
|
|
249
249
|
ensureColumn("tasks", "approved_at", "TEXT");
|
|
250
250
|
ensureColumn("agents", "role", "TEXT DEFAULT 'agent'");
|
|
251
251
|
ensureColumn("agents", "permissions", `TEXT DEFAULT '["*"]'`);
|
|
252
|
+
ensureColumn("agents", "reports_to", "TEXT");
|
|
253
|
+
ensureColumn("agents", "title", "TEXT");
|
|
254
|
+
ensureColumn("agents", "level", "TEXT");
|
|
252
255
|
ensureColumn("plans", "task_list_id", "TEXT");
|
|
253
256
|
ensureColumn("plans", "agent_id", "TEXT");
|
|
254
257
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_plan ON tasks(plan_id)");
|
|
@@ -526,6 +529,12 @@ var init_database = __esm(() => {
|
|
|
526
529
|
ALTER TABLE agents ADD COLUMN permissions TEXT DEFAULT '["*"]';
|
|
527
530
|
|
|
528
531
|
INSERT OR IGNORE INTO _migrations (id) VALUES (10);
|
|
532
|
+
`,
|
|
533
|
+
`
|
|
534
|
+
ALTER TABLE agents ADD COLUMN reports_to TEXT;
|
|
535
|
+
ALTER TABLE agents ADD COLUMN title TEXT;
|
|
536
|
+
ALTER TABLE agents ADD COLUMN level TEXT;
|
|
537
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (11);
|
|
529
538
|
`
|
|
530
539
|
];
|
|
531
540
|
});
|
|
@@ -680,6 +689,8 @@ __export(exports_agents, {
|
|
|
680
689
|
updateAgent: () => updateAgent,
|
|
681
690
|
registerAgent: () => registerAgent,
|
|
682
691
|
listAgents: () => listAgents,
|
|
692
|
+
getOrgChart: () => getOrgChart,
|
|
693
|
+
getDirectReports: () => getDirectReports,
|
|
683
694
|
getAgentByName: () => getAgentByName,
|
|
684
695
|
getAgent: () => getAgent,
|
|
685
696
|
deleteAgent: () => deleteAgent
|
|
@@ -703,13 +714,16 @@ function registerAgent(input, db) {
|
|
|
703
714
|
}
|
|
704
715
|
const id = shortUuid();
|
|
705
716
|
const timestamp = now();
|
|
706
|
-
d.run(`INSERT INTO agents (id, name, description, role, permissions, metadata, created_at, last_seen_at)
|
|
707
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
717
|
+
d.run(`INSERT INTO agents (id, name, description, role, title, level, permissions, reports_to, metadata, created_at, last_seen_at)
|
|
718
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
708
719
|
id,
|
|
709
720
|
input.name,
|
|
710
721
|
input.description || null,
|
|
711
722
|
input.role || "agent",
|
|
723
|
+
input.title || null,
|
|
724
|
+
input.level || null,
|
|
712
725
|
JSON.stringify(input.permissions || ["*"]),
|
|
726
|
+
input.reports_to || null,
|
|
713
727
|
JSON.stringify(input.metadata || {}),
|
|
714
728
|
timestamp,
|
|
715
729
|
timestamp
|
|
@@ -757,6 +771,18 @@ function updateAgent(id, input, db) {
|
|
|
757
771
|
sets.push("permissions = ?");
|
|
758
772
|
params.push(JSON.stringify(input.permissions));
|
|
759
773
|
}
|
|
774
|
+
if (input.title !== undefined) {
|
|
775
|
+
sets.push("title = ?");
|
|
776
|
+
params.push(input.title);
|
|
777
|
+
}
|
|
778
|
+
if (input.level !== undefined) {
|
|
779
|
+
sets.push("level = ?");
|
|
780
|
+
params.push(input.level);
|
|
781
|
+
}
|
|
782
|
+
if (input.reports_to !== undefined) {
|
|
783
|
+
sets.push("reports_to = ?");
|
|
784
|
+
params.push(input.reports_to);
|
|
785
|
+
}
|
|
760
786
|
if (input.metadata !== undefined) {
|
|
761
787
|
sets.push("metadata = ?");
|
|
762
788
|
params.push(JSON.stringify(input.metadata));
|
|
@@ -769,6 +795,25 @@ function deleteAgent(id, db) {
|
|
|
769
795
|
const d = db || getDatabase();
|
|
770
796
|
return d.run("DELETE FROM agents WHERE id = ?", [id]).changes > 0;
|
|
771
797
|
}
|
|
798
|
+
function getDirectReports(agentId, db) {
|
|
799
|
+
const d = db || getDatabase();
|
|
800
|
+
return d.query("SELECT * FROM agents WHERE reports_to = ? ORDER BY name").all(agentId).map(rowToAgent);
|
|
801
|
+
}
|
|
802
|
+
function getOrgChart(db) {
|
|
803
|
+
const agents = listAgents(db);
|
|
804
|
+
const byManager = new Map;
|
|
805
|
+
for (const a of agents) {
|
|
806
|
+
const key = a.reports_to;
|
|
807
|
+
if (!byManager.has(key))
|
|
808
|
+
byManager.set(key, []);
|
|
809
|
+
byManager.get(key).push(a);
|
|
810
|
+
}
|
|
811
|
+
function buildTree(parentId) {
|
|
812
|
+
const children = byManager.get(parentId) || [];
|
|
813
|
+
return children.map((a) => ({ agent: a, reports: buildTree(a.id) }));
|
|
814
|
+
}
|
|
815
|
+
return buildTree(null);
|
|
816
|
+
}
|
|
772
817
|
var init_agents = __esm(() => {
|
|
773
818
|
init_database();
|
|
774
819
|
});
|
|
@@ -1751,6 +1796,16 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
1751
1796
|
return json({ error: e instanceof Error ? e.message : "Failed to claim" }, 500, port);
|
|
1752
1797
|
}
|
|
1753
1798
|
}
|
|
1799
|
+
if (path === "/api/org" && method === "GET") {
|
|
1800
|
+
const { getOrgChart: getOrgChart2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
1801
|
+
return json(getOrgChart2(), 200, port);
|
|
1802
|
+
}
|
|
1803
|
+
const teamMatch = path.match(/^\/api\/agents\/([^/]+)\/team$/);
|
|
1804
|
+
if (teamMatch && method === "GET") {
|
|
1805
|
+
const agentId = decodeURIComponent(teamMatch[1]);
|
|
1806
|
+
const { getDirectReports: getDirectReports2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
1807
|
+
return json(getDirectReports2(agentId), 200, port);
|
|
1808
|
+
}
|
|
1754
1809
|
if (path === "/api/agents" && method === "GET") {
|
|
1755
1810
|
return json(listAgents(), 200, port);
|
|
1756
1811
|
}
|