@hasna/todos 0.9.29 → 0.9.30
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 +133 -2
- package/dist/index.js +33 -2
- package/dist/mcp/index.js +177 -48
- package/dist/server/index.js +43 -2
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2253,6 +2253,7 @@ 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");
|
|
2256
2257
|
ensureColumn("plans", "task_list_id", "TEXT");
|
|
2257
2258
|
ensureColumn("plans", "agent_id", "TEXT");
|
|
2258
2259
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_plan ON tasks(plan_id)");
|
|
@@ -2544,6 +2545,10 @@ var init_database = __esm(() => {
|
|
|
2544
2545
|
ALTER TABLE agents ADD COLUMN permissions TEXT DEFAULT '["*"]';
|
|
2545
2546
|
|
|
2546
2547
|
INSERT OR IGNORE INTO _migrations (id) VALUES (10);
|
|
2548
|
+
`,
|
|
2549
|
+
`
|
|
2550
|
+
ALTER TABLE agents ADD COLUMN reports_to TEXT;
|
|
2551
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (11);
|
|
2547
2552
|
`
|
|
2548
2553
|
];
|
|
2549
2554
|
});
|
|
@@ -3363,6 +3368,8 @@ __export(exports_agents, {
|
|
|
3363
3368
|
updateAgent: () => updateAgent,
|
|
3364
3369
|
registerAgent: () => registerAgent,
|
|
3365
3370
|
listAgents: () => listAgents,
|
|
3371
|
+
getOrgChart: () => getOrgChart,
|
|
3372
|
+
getDirectReports: () => getDirectReports,
|
|
3366
3373
|
getAgentByName: () => getAgentByName,
|
|
3367
3374
|
getAgent: () => getAgent,
|
|
3368
3375
|
deleteAgent: () => deleteAgent
|
|
@@ -3386,13 +3393,14 @@ function registerAgent(input, db) {
|
|
|
3386
3393
|
}
|
|
3387
3394
|
const id = shortUuid();
|
|
3388
3395
|
const timestamp = now();
|
|
3389
|
-
d.run(`INSERT INTO agents (id, name, description, role, permissions, metadata, created_at, last_seen_at)
|
|
3390
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
3396
|
+
d.run(`INSERT INTO agents (id, name, description, role, permissions, reports_to, metadata, created_at, last_seen_at)
|
|
3397
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
3391
3398
|
id,
|
|
3392
3399
|
input.name,
|
|
3393
3400
|
input.description || null,
|
|
3394
3401
|
input.role || "agent",
|
|
3395
3402
|
JSON.stringify(input.permissions || ["*"]),
|
|
3403
|
+
input.reports_to || null,
|
|
3396
3404
|
JSON.stringify(input.metadata || {}),
|
|
3397
3405
|
timestamp,
|
|
3398
3406
|
timestamp
|
|
@@ -3440,6 +3448,10 @@ function updateAgent(id, input, db) {
|
|
|
3440
3448
|
sets.push("permissions = ?");
|
|
3441
3449
|
params.push(JSON.stringify(input.permissions));
|
|
3442
3450
|
}
|
|
3451
|
+
if (input.reports_to !== undefined) {
|
|
3452
|
+
sets.push("reports_to = ?");
|
|
3453
|
+
params.push(input.reports_to);
|
|
3454
|
+
}
|
|
3443
3455
|
if (input.metadata !== undefined) {
|
|
3444
3456
|
sets.push("metadata = ?");
|
|
3445
3457
|
params.push(JSON.stringify(input.metadata));
|
|
@@ -3452,6 +3464,25 @@ function deleteAgent(id, db) {
|
|
|
3452
3464
|
const d = db || getDatabase();
|
|
3453
3465
|
return d.run("DELETE FROM agents WHERE id = ?", [id]).changes > 0;
|
|
3454
3466
|
}
|
|
3467
|
+
function getDirectReports(agentId, db) {
|
|
3468
|
+
const d = db || getDatabase();
|
|
3469
|
+
return d.query("SELECT * FROM agents WHERE reports_to = ? ORDER BY name").all(agentId).map(rowToAgent);
|
|
3470
|
+
}
|
|
3471
|
+
function getOrgChart(db) {
|
|
3472
|
+
const agents = listAgents(db);
|
|
3473
|
+
const byManager = new Map;
|
|
3474
|
+
for (const a of agents) {
|
|
3475
|
+
const key = a.reports_to;
|
|
3476
|
+
if (!byManager.has(key))
|
|
3477
|
+
byManager.set(key, []);
|
|
3478
|
+
byManager.get(key).push(a);
|
|
3479
|
+
}
|
|
3480
|
+
function buildTree(parentId) {
|
|
3481
|
+
const children = byManager.get(parentId) || [];
|
|
3482
|
+
return children.map((a) => ({ agent: a, reports: buildTree(a.id) }));
|
|
3483
|
+
}
|
|
3484
|
+
return buildTree(null);
|
|
3485
|
+
}
|
|
3455
3486
|
var init_agents = __esm(() => {
|
|
3456
3487
|
init_database();
|
|
3457
3488
|
});
|
|
@@ -9205,6 +9236,50 @@ In Progress:`);
|
|
|
9205
9236
|
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
9206
9237
|
}
|
|
9207
9238
|
});
|
|
9239
|
+
server.tool("get_org_chart", "Get agent org chart \u2014 who reports to who.", {}, async () => {
|
|
9240
|
+
try {
|
|
9241
|
+
let render = function(nodes, indent = 0) {
|
|
9242
|
+
return nodes.map((n) => {
|
|
9243
|
+
const prefix = " ".repeat(indent);
|
|
9244
|
+
const role = n.agent.role ? ` (${n.agent.role})` : "";
|
|
9245
|
+
const line = `${prefix}${n.agent.name}${role} [${n.agent.id}]`;
|
|
9246
|
+
const children = n.reports.length > 0 ? `
|
|
9247
|
+
` + render(n.reports, indent + 1) : "";
|
|
9248
|
+
return line + children;
|
|
9249
|
+
}).join(`
|
|
9250
|
+
`);
|
|
9251
|
+
};
|
|
9252
|
+
const { getOrgChart: getOrgChart2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
9253
|
+
const tree = getOrgChart2();
|
|
9254
|
+
const text = tree.length > 0 ? render(tree) : "No agents registered.";
|
|
9255
|
+
return { content: [{ type: "text", text }] };
|
|
9256
|
+
} catch (e) {
|
|
9257
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
9258
|
+
}
|
|
9259
|
+
});
|
|
9260
|
+
server.tool("set_reports_to", "Set who an agent reports to in the org chart.", {
|
|
9261
|
+
agent_name: exports_external.string(),
|
|
9262
|
+
manager_name: exports_external.string().optional()
|
|
9263
|
+
}, async ({ agent_name, manager_name }) => {
|
|
9264
|
+
try {
|
|
9265
|
+
const agent = getAgentByName(agent_name);
|
|
9266
|
+
if (!agent)
|
|
9267
|
+
return { content: [{ type: "text", text: `Agent not found: ${agent_name}` }], isError: true };
|
|
9268
|
+
let managerId = null;
|
|
9269
|
+
if (manager_name) {
|
|
9270
|
+
const manager = getAgentByName(manager_name);
|
|
9271
|
+
if (!manager)
|
|
9272
|
+
return { content: [{ type: "text", text: `Manager not found: ${manager_name}` }], isError: true };
|
|
9273
|
+
managerId = manager.id;
|
|
9274
|
+
}
|
|
9275
|
+
const { updateAgent: updateAgent2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
9276
|
+
updateAgent2(agent.id, { reports_to: managerId });
|
|
9277
|
+
const result = managerId ? `${agent_name} now reports to ${manager_name}` : `${agent_name} reports to no one (top-level)`;
|
|
9278
|
+
return { content: [{ type: "text", text: result }] };
|
|
9279
|
+
} catch (e) {
|
|
9280
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
9281
|
+
}
|
|
9282
|
+
});
|
|
9208
9283
|
server.tool("search_tools", "List tool names matching a query.", { query: exports_external.string().optional() }, async ({ query }) => {
|
|
9209
9284
|
const all = [
|
|
9210
9285
|
"create_task",
|
|
@@ -9656,6 +9731,16 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
9656
9731
|
return json({ error: e instanceof Error ? e.message : "Failed to claim" }, 500, port);
|
|
9657
9732
|
}
|
|
9658
9733
|
}
|
|
9734
|
+
if (path === "/api/org" && method === "GET") {
|
|
9735
|
+
const { getOrgChart: getOrgChart2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
9736
|
+
return json(getOrgChart2(), 200, port);
|
|
9737
|
+
}
|
|
9738
|
+
const teamMatch = path.match(/^\/api\/agents\/([^/]+)\/team$/);
|
|
9739
|
+
if (teamMatch && method === "GET") {
|
|
9740
|
+
const agentId = decodeURIComponent(teamMatch[1]);
|
|
9741
|
+
const { getDirectReports: getDirectReports2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
9742
|
+
return json(getDirectReports2(agentId), 200, port);
|
|
9743
|
+
}
|
|
9659
9744
|
if (path === "/api/agents" && method === "GET") {
|
|
9660
9745
|
return json(listAgents(), 200, port);
|
|
9661
9746
|
}
|
|
@@ -12194,6 +12279,52 @@ program2.command("agents").description("List registered agents").action(() => {
|
|
|
12194
12279
|
handleError(e);
|
|
12195
12280
|
}
|
|
12196
12281
|
});
|
|
12282
|
+
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) => {
|
|
12283
|
+
const globalOpts = program2.opts();
|
|
12284
|
+
const { getOrgChart: getOrgChart2, getAgentByName: getByName, updateAgent: update } = (init_agents(), __toCommonJS(exports_agents));
|
|
12285
|
+
if (opts.set) {
|
|
12286
|
+
const [agentName, managerName] = opts.set.split("=");
|
|
12287
|
+
const agent = getByName(agentName);
|
|
12288
|
+
if (!agent) {
|
|
12289
|
+
console.error(chalk.red(`Agent not found: ${agentName}`));
|
|
12290
|
+
process.exit(1);
|
|
12291
|
+
}
|
|
12292
|
+
let managerId = null;
|
|
12293
|
+
if (managerName) {
|
|
12294
|
+
const manager = getByName(managerName);
|
|
12295
|
+
if (!manager) {
|
|
12296
|
+
console.error(chalk.red(`Manager not found: ${managerName}`));
|
|
12297
|
+
process.exit(1);
|
|
12298
|
+
}
|
|
12299
|
+
managerId = manager.id;
|
|
12300
|
+
}
|
|
12301
|
+
update(agent.id, { reports_to: managerId });
|
|
12302
|
+
if (globalOpts.json) {
|
|
12303
|
+
output({ agent: agentName, reports_to: managerName || null }, true);
|
|
12304
|
+
} else {
|
|
12305
|
+
console.log(chalk.green(managerId ? `${agentName} \u2192 ${managerName}` : `${agentName} \u2192 (top-level)`));
|
|
12306
|
+
}
|
|
12307
|
+
return;
|
|
12308
|
+
}
|
|
12309
|
+
const tree = getOrgChart2();
|
|
12310
|
+
if (globalOpts.json) {
|
|
12311
|
+
output(tree, true);
|
|
12312
|
+
return;
|
|
12313
|
+
}
|
|
12314
|
+
if (tree.length === 0) {
|
|
12315
|
+
console.log(chalk.dim("No agents registered."));
|
|
12316
|
+
return;
|
|
12317
|
+
}
|
|
12318
|
+
function render2(nodes, indent = 0) {
|
|
12319
|
+
for (const n of nodes) {
|
|
12320
|
+
const prefix = " ".repeat(indent);
|
|
12321
|
+
const role = n.agent.role ? chalk.dim(` (${n.agent.role})`) : "";
|
|
12322
|
+
console.log(`${prefix}${indent > 0 ? "\u251C\u2500\u2500 " : ""}${chalk.bold(n.agent.name)}${role} ${chalk.dim(n.agent.id)}`);
|
|
12323
|
+
render2(n.reports, indent + 1);
|
|
12324
|
+
}
|
|
12325
|
+
}
|
|
12326
|
+
render2(tree);
|
|
12327
|
+
});
|
|
12197
12328
|
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
12329
|
try {
|
|
12199
12330
|
const globalOpts = program2.opts();
|
package/dist/index.js
CHANGED
|
@@ -264,6 +264,10 @@ 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
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (11);
|
|
267
271
|
`
|
|
268
272
|
];
|
|
269
273
|
var _db = null;
|
|
@@ -385,6 +389,7 @@ function ensureSchema(db) {
|
|
|
385
389
|
ensureColumn("tasks", "approved_at", "TEXT");
|
|
386
390
|
ensureColumn("agents", "role", "TEXT DEFAULT 'agent'");
|
|
387
391
|
ensureColumn("agents", "permissions", `TEXT DEFAULT '["*"]'`);
|
|
392
|
+
ensureColumn("agents", "reports_to", "TEXT");
|
|
388
393
|
ensureColumn("plans", "task_list_id", "TEXT");
|
|
389
394
|
ensureColumn("plans", "agent_id", "TEXT");
|
|
390
395
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_plan ON tasks(plan_id)");
|
|
@@ -1388,13 +1393,14 @@ function registerAgent(input, db) {
|
|
|
1388
1393
|
}
|
|
1389
1394
|
const id = shortUuid();
|
|
1390
1395
|
const timestamp = now();
|
|
1391
|
-
d.run(`INSERT INTO agents (id, name, description, role, permissions, metadata, created_at, last_seen_at)
|
|
1392
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
1396
|
+
d.run(`INSERT INTO agents (id, name, description, role, permissions, reports_to, metadata, created_at, last_seen_at)
|
|
1397
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
1393
1398
|
id,
|
|
1394
1399
|
input.name,
|
|
1395
1400
|
input.description || null,
|
|
1396
1401
|
input.role || "agent",
|
|
1397
1402
|
JSON.stringify(input.permissions || ["*"]),
|
|
1403
|
+
input.reports_to || null,
|
|
1398
1404
|
JSON.stringify(input.metadata || {}),
|
|
1399
1405
|
timestamp,
|
|
1400
1406
|
timestamp
|
|
@@ -1442,6 +1448,10 @@ function updateAgent(id, input, db) {
|
|
|
1442
1448
|
sets.push("permissions = ?");
|
|
1443
1449
|
params.push(JSON.stringify(input.permissions));
|
|
1444
1450
|
}
|
|
1451
|
+
if (input.reports_to !== undefined) {
|
|
1452
|
+
sets.push("reports_to = ?");
|
|
1453
|
+
params.push(input.reports_to);
|
|
1454
|
+
}
|
|
1445
1455
|
if (input.metadata !== undefined) {
|
|
1446
1456
|
sets.push("metadata = ?");
|
|
1447
1457
|
params.push(JSON.stringify(input.metadata));
|
|
@@ -1454,6 +1464,25 @@ function deleteAgent(id, db) {
|
|
|
1454
1464
|
const d = db || getDatabase();
|
|
1455
1465
|
return d.run("DELETE FROM agents WHERE id = ?", [id]).changes > 0;
|
|
1456
1466
|
}
|
|
1467
|
+
function getDirectReports(agentId, db) {
|
|
1468
|
+
const d = db || getDatabase();
|
|
1469
|
+
return d.query("SELECT * FROM agents WHERE reports_to = ? ORDER BY name").all(agentId).map(rowToAgent);
|
|
1470
|
+
}
|
|
1471
|
+
function getOrgChart(db) {
|
|
1472
|
+
const agents = listAgents(db);
|
|
1473
|
+
const byManager = new Map;
|
|
1474
|
+
for (const a of agents) {
|
|
1475
|
+
const key = a.reports_to;
|
|
1476
|
+
if (!byManager.has(key))
|
|
1477
|
+
byManager.set(key, []);
|
|
1478
|
+
byManager.get(key).push(a);
|
|
1479
|
+
}
|
|
1480
|
+
function buildTree(parentId) {
|
|
1481
|
+
const children = byManager.get(parentId) || [];
|
|
1482
|
+
return children.map((a) => ({ agent: a, reports: buildTree(a.id) }));
|
|
1483
|
+
}
|
|
1484
|
+
return buildTree(null);
|
|
1485
|
+
}
|
|
1457
1486
|
// src/db/task-lists.ts
|
|
1458
1487
|
function rowToTaskList(row) {
|
|
1459
1488
|
return {
|
|
@@ -2264,6 +2293,8 @@ export {
|
|
|
2264
2293
|
getProjectByPath,
|
|
2265
2294
|
getProject,
|
|
2266
2295
|
getPlan,
|
|
2296
|
+
getOrgChart,
|
|
2297
|
+
getDirectReports,
|
|
2267
2298
|
getDatabase,
|
|
2268
2299
|
getCompletionGuardConfig,
|
|
2269
2300
|
getComment,
|
package/dist/mcp/index.js
CHANGED
|
@@ -187,6 +187,7 @@ 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");
|
|
190
191
|
ensureColumn("plans", "task_list_id", "TEXT");
|
|
191
192
|
ensureColumn("plans", "agent_id", "TEXT");
|
|
192
193
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_plan ON tasks(plan_id)");
|
|
@@ -478,6 +479,10 @@ var init_database = __esm(() => {
|
|
|
478
479
|
ALTER TABLE agents ADD COLUMN permissions TEXT DEFAULT '["*"]';
|
|
479
480
|
|
|
480
481
|
INSERT OR IGNORE INTO _migrations (id) VALUES (10);
|
|
482
|
+
`,
|
|
483
|
+
`
|
|
484
|
+
ALTER TABLE agents ADD COLUMN reports_to TEXT;
|
|
485
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (11);
|
|
481
486
|
`
|
|
482
487
|
];
|
|
483
488
|
});
|
|
@@ -509,6 +514,132 @@ var init_audit = __esm(() => {
|
|
|
509
514
|
init_database();
|
|
510
515
|
});
|
|
511
516
|
|
|
517
|
+
// src/db/agents.ts
|
|
518
|
+
var exports_agents = {};
|
|
519
|
+
__export(exports_agents, {
|
|
520
|
+
updateAgentActivity: () => updateAgentActivity,
|
|
521
|
+
updateAgent: () => updateAgent,
|
|
522
|
+
registerAgent: () => registerAgent,
|
|
523
|
+
listAgents: () => listAgents,
|
|
524
|
+
getOrgChart: () => getOrgChart,
|
|
525
|
+
getDirectReports: () => getDirectReports,
|
|
526
|
+
getAgentByName: () => getAgentByName,
|
|
527
|
+
getAgent: () => getAgent,
|
|
528
|
+
deleteAgent: () => deleteAgent
|
|
529
|
+
});
|
|
530
|
+
function shortUuid() {
|
|
531
|
+
return crypto.randomUUID().slice(0, 8);
|
|
532
|
+
}
|
|
533
|
+
function rowToAgent(row) {
|
|
534
|
+
return {
|
|
535
|
+
...row,
|
|
536
|
+
permissions: JSON.parse(row.permissions || '["*"]'),
|
|
537
|
+
metadata: JSON.parse(row.metadata || "{}")
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function registerAgent(input, db) {
|
|
541
|
+
const d = db || getDatabase();
|
|
542
|
+
const existing = getAgentByName(input.name, d);
|
|
543
|
+
if (existing) {
|
|
544
|
+
d.run("UPDATE agents SET last_seen_at = ? WHERE id = ?", [now(), existing.id]);
|
|
545
|
+
return getAgent(existing.id, d);
|
|
546
|
+
}
|
|
547
|
+
const id = shortUuid();
|
|
548
|
+
const timestamp = now();
|
|
549
|
+
d.run(`INSERT INTO agents (id, name, description, role, permissions, reports_to, metadata, created_at, last_seen_at)
|
|
550
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
551
|
+
id,
|
|
552
|
+
input.name,
|
|
553
|
+
input.description || null,
|
|
554
|
+
input.role || "agent",
|
|
555
|
+
JSON.stringify(input.permissions || ["*"]),
|
|
556
|
+
input.reports_to || null,
|
|
557
|
+
JSON.stringify(input.metadata || {}),
|
|
558
|
+
timestamp,
|
|
559
|
+
timestamp
|
|
560
|
+
]);
|
|
561
|
+
return getAgent(id, d);
|
|
562
|
+
}
|
|
563
|
+
function getAgent(id, db) {
|
|
564
|
+
const d = db || getDatabase();
|
|
565
|
+
const row = d.query("SELECT * FROM agents WHERE id = ?").get(id);
|
|
566
|
+
return row ? rowToAgent(row) : null;
|
|
567
|
+
}
|
|
568
|
+
function getAgentByName(name, db) {
|
|
569
|
+
const d = db || getDatabase();
|
|
570
|
+
const row = d.query("SELECT * FROM agents WHERE name = ?").get(name);
|
|
571
|
+
return row ? rowToAgent(row) : null;
|
|
572
|
+
}
|
|
573
|
+
function listAgents(db) {
|
|
574
|
+
const d = db || getDatabase();
|
|
575
|
+
return d.query("SELECT * FROM agents ORDER BY name").all().map(rowToAgent);
|
|
576
|
+
}
|
|
577
|
+
function updateAgentActivity(id, db) {
|
|
578
|
+
const d = db || getDatabase();
|
|
579
|
+
d.run("UPDATE agents SET last_seen_at = ? WHERE id = ?", [now(), id]);
|
|
580
|
+
}
|
|
581
|
+
function updateAgent(id, input, db) {
|
|
582
|
+
const d = db || getDatabase();
|
|
583
|
+
const agent = getAgent(id, d);
|
|
584
|
+
if (!agent)
|
|
585
|
+
throw new Error(`Agent not found: ${id}`);
|
|
586
|
+
const sets = ["last_seen_at = ?"];
|
|
587
|
+
const params = [now()];
|
|
588
|
+
if (input.name !== undefined) {
|
|
589
|
+
sets.push("name = ?");
|
|
590
|
+
params.push(input.name);
|
|
591
|
+
}
|
|
592
|
+
if (input.description !== undefined) {
|
|
593
|
+
sets.push("description = ?");
|
|
594
|
+
params.push(input.description);
|
|
595
|
+
}
|
|
596
|
+
if (input.role !== undefined) {
|
|
597
|
+
sets.push("role = ?");
|
|
598
|
+
params.push(input.role);
|
|
599
|
+
}
|
|
600
|
+
if (input.permissions !== undefined) {
|
|
601
|
+
sets.push("permissions = ?");
|
|
602
|
+
params.push(JSON.stringify(input.permissions));
|
|
603
|
+
}
|
|
604
|
+
if (input.reports_to !== undefined) {
|
|
605
|
+
sets.push("reports_to = ?");
|
|
606
|
+
params.push(input.reports_to);
|
|
607
|
+
}
|
|
608
|
+
if (input.metadata !== undefined) {
|
|
609
|
+
sets.push("metadata = ?");
|
|
610
|
+
params.push(JSON.stringify(input.metadata));
|
|
611
|
+
}
|
|
612
|
+
params.push(id);
|
|
613
|
+
d.run(`UPDATE agents SET ${sets.join(", ")} WHERE id = ?`, params);
|
|
614
|
+
return getAgent(id, d);
|
|
615
|
+
}
|
|
616
|
+
function deleteAgent(id, db) {
|
|
617
|
+
const d = db || getDatabase();
|
|
618
|
+
return d.run("DELETE FROM agents WHERE id = ?", [id]).changes > 0;
|
|
619
|
+
}
|
|
620
|
+
function getDirectReports(agentId, db) {
|
|
621
|
+
const d = db || getDatabase();
|
|
622
|
+
return d.query("SELECT * FROM agents WHERE reports_to = ? ORDER BY name").all(agentId).map(rowToAgent);
|
|
623
|
+
}
|
|
624
|
+
function getOrgChart(db) {
|
|
625
|
+
const agents = listAgents(db);
|
|
626
|
+
const byManager = new Map;
|
|
627
|
+
for (const a of agents) {
|
|
628
|
+
const key = a.reports_to;
|
|
629
|
+
if (!byManager.has(key))
|
|
630
|
+
byManager.set(key, []);
|
|
631
|
+
byManager.get(key).push(a);
|
|
632
|
+
}
|
|
633
|
+
function buildTree(parentId) {
|
|
634
|
+
const children = byManager.get(parentId) || [];
|
|
635
|
+
return children.map((a) => ({ agent: a, reports: buildTree(a.id) }));
|
|
636
|
+
}
|
|
637
|
+
return buildTree(null);
|
|
638
|
+
}
|
|
639
|
+
var init_agents = __esm(() => {
|
|
640
|
+
init_database();
|
|
641
|
+
});
|
|
642
|
+
|
|
512
643
|
// src/db/webhooks.ts
|
|
513
644
|
var exports_webhooks = {};
|
|
514
645
|
__export(exports_webhooks, {
|
|
@@ -5399,54 +5530,8 @@ function deletePlan(id, db) {
|
|
|
5399
5530
|
return result.changes > 0;
|
|
5400
5531
|
}
|
|
5401
5532
|
|
|
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
|
-
}
|
|
5533
|
+
// src/mcp/index.ts
|
|
5534
|
+
init_agents();
|
|
5450
5535
|
|
|
5451
5536
|
// src/db/task-lists.ts
|
|
5452
5537
|
init_database();
|
|
@@ -6971,6 +7056,50 @@ In Progress:`);
|
|
|
6971
7056
|
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
6972
7057
|
}
|
|
6973
7058
|
});
|
|
7059
|
+
server.tool("get_org_chart", "Get agent org chart \u2014 who reports to who.", {}, async () => {
|
|
7060
|
+
try {
|
|
7061
|
+
let render = function(nodes, indent = 0) {
|
|
7062
|
+
return nodes.map((n) => {
|
|
7063
|
+
const prefix = " ".repeat(indent);
|
|
7064
|
+
const role = n.agent.role ? ` (${n.agent.role})` : "";
|
|
7065
|
+
const line = `${prefix}${n.agent.name}${role} [${n.agent.id}]`;
|
|
7066
|
+
const children = n.reports.length > 0 ? `
|
|
7067
|
+
` + render(n.reports, indent + 1) : "";
|
|
7068
|
+
return line + children;
|
|
7069
|
+
}).join(`
|
|
7070
|
+
`);
|
|
7071
|
+
};
|
|
7072
|
+
const { getOrgChart: getOrgChart2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
7073
|
+
const tree = getOrgChart2();
|
|
7074
|
+
const text = tree.length > 0 ? render(tree) : "No agents registered.";
|
|
7075
|
+
return { content: [{ type: "text", text }] };
|
|
7076
|
+
} catch (e) {
|
|
7077
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
7078
|
+
}
|
|
7079
|
+
});
|
|
7080
|
+
server.tool("set_reports_to", "Set who an agent reports to in the org chart.", {
|
|
7081
|
+
agent_name: exports_external.string(),
|
|
7082
|
+
manager_name: exports_external.string().optional()
|
|
7083
|
+
}, async ({ agent_name, manager_name }) => {
|
|
7084
|
+
try {
|
|
7085
|
+
const agent = getAgentByName(agent_name);
|
|
7086
|
+
if (!agent)
|
|
7087
|
+
return { content: [{ type: "text", text: `Agent not found: ${agent_name}` }], isError: true };
|
|
7088
|
+
let managerId = null;
|
|
7089
|
+
if (manager_name) {
|
|
7090
|
+
const manager = getAgentByName(manager_name);
|
|
7091
|
+
if (!manager)
|
|
7092
|
+
return { content: [{ type: "text", text: `Manager not found: ${manager_name}` }], isError: true };
|
|
7093
|
+
managerId = manager.id;
|
|
7094
|
+
}
|
|
7095
|
+
const { updateAgent: updateAgent2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
7096
|
+
updateAgent2(agent.id, { reports_to: managerId });
|
|
7097
|
+
const result = managerId ? `${agent_name} now reports to ${manager_name}` : `${agent_name} reports to no one (top-level)`;
|
|
7098
|
+
return { content: [{ type: "text", text: result }] };
|
|
7099
|
+
} catch (e) {
|
|
7100
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
7101
|
+
}
|
|
7102
|
+
});
|
|
6974
7103
|
server.tool("search_tools", "List tool names matching a query.", { query: exports_external.string().optional() }, async ({ query }) => {
|
|
6975
7104
|
const all = [
|
|
6976
7105
|
"create_task",
|
package/dist/server/index.js
CHANGED
|
@@ -249,6 +249,7 @@ 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");
|
|
252
253
|
ensureColumn("plans", "task_list_id", "TEXT");
|
|
253
254
|
ensureColumn("plans", "agent_id", "TEXT");
|
|
254
255
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_plan ON tasks(plan_id)");
|
|
@@ -526,6 +527,10 @@ var init_database = __esm(() => {
|
|
|
526
527
|
ALTER TABLE agents ADD COLUMN permissions TEXT DEFAULT '["*"]';
|
|
527
528
|
|
|
528
529
|
INSERT OR IGNORE INTO _migrations (id) VALUES (10);
|
|
530
|
+
`,
|
|
531
|
+
`
|
|
532
|
+
ALTER TABLE agents ADD COLUMN reports_to TEXT;
|
|
533
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (11);
|
|
529
534
|
`
|
|
530
535
|
];
|
|
531
536
|
});
|
|
@@ -680,6 +685,8 @@ __export(exports_agents, {
|
|
|
680
685
|
updateAgent: () => updateAgent,
|
|
681
686
|
registerAgent: () => registerAgent,
|
|
682
687
|
listAgents: () => listAgents,
|
|
688
|
+
getOrgChart: () => getOrgChart,
|
|
689
|
+
getDirectReports: () => getDirectReports,
|
|
683
690
|
getAgentByName: () => getAgentByName,
|
|
684
691
|
getAgent: () => getAgent,
|
|
685
692
|
deleteAgent: () => deleteAgent
|
|
@@ -703,13 +710,14 @@ function registerAgent(input, db) {
|
|
|
703
710
|
}
|
|
704
711
|
const id = shortUuid();
|
|
705
712
|
const timestamp = now();
|
|
706
|
-
d.run(`INSERT INTO agents (id, name, description, role, permissions, metadata, created_at, last_seen_at)
|
|
707
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
713
|
+
d.run(`INSERT INTO agents (id, name, description, role, permissions, reports_to, metadata, created_at, last_seen_at)
|
|
714
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
708
715
|
id,
|
|
709
716
|
input.name,
|
|
710
717
|
input.description || null,
|
|
711
718
|
input.role || "agent",
|
|
712
719
|
JSON.stringify(input.permissions || ["*"]),
|
|
720
|
+
input.reports_to || null,
|
|
713
721
|
JSON.stringify(input.metadata || {}),
|
|
714
722
|
timestamp,
|
|
715
723
|
timestamp
|
|
@@ -757,6 +765,10 @@ function updateAgent(id, input, db) {
|
|
|
757
765
|
sets.push("permissions = ?");
|
|
758
766
|
params.push(JSON.stringify(input.permissions));
|
|
759
767
|
}
|
|
768
|
+
if (input.reports_to !== undefined) {
|
|
769
|
+
sets.push("reports_to = ?");
|
|
770
|
+
params.push(input.reports_to);
|
|
771
|
+
}
|
|
760
772
|
if (input.metadata !== undefined) {
|
|
761
773
|
sets.push("metadata = ?");
|
|
762
774
|
params.push(JSON.stringify(input.metadata));
|
|
@@ -769,6 +781,25 @@ function deleteAgent(id, db) {
|
|
|
769
781
|
const d = db || getDatabase();
|
|
770
782
|
return d.run("DELETE FROM agents WHERE id = ?", [id]).changes > 0;
|
|
771
783
|
}
|
|
784
|
+
function getDirectReports(agentId, db) {
|
|
785
|
+
const d = db || getDatabase();
|
|
786
|
+
return d.query("SELECT * FROM agents WHERE reports_to = ? ORDER BY name").all(agentId).map(rowToAgent);
|
|
787
|
+
}
|
|
788
|
+
function getOrgChart(db) {
|
|
789
|
+
const agents = listAgents(db);
|
|
790
|
+
const byManager = new Map;
|
|
791
|
+
for (const a of agents) {
|
|
792
|
+
const key = a.reports_to;
|
|
793
|
+
if (!byManager.has(key))
|
|
794
|
+
byManager.set(key, []);
|
|
795
|
+
byManager.get(key).push(a);
|
|
796
|
+
}
|
|
797
|
+
function buildTree(parentId) {
|
|
798
|
+
const children = byManager.get(parentId) || [];
|
|
799
|
+
return children.map((a) => ({ agent: a, reports: buildTree(a.id) }));
|
|
800
|
+
}
|
|
801
|
+
return buildTree(null);
|
|
802
|
+
}
|
|
772
803
|
var init_agents = __esm(() => {
|
|
773
804
|
init_database();
|
|
774
805
|
});
|
|
@@ -1751,6 +1782,16 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
1751
1782
|
return json({ error: e instanceof Error ? e.message : "Failed to claim" }, 500, port);
|
|
1752
1783
|
}
|
|
1753
1784
|
}
|
|
1785
|
+
if (path === "/api/org" && method === "GET") {
|
|
1786
|
+
const { getOrgChart: getOrgChart2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
1787
|
+
return json(getOrgChart2(), 200, port);
|
|
1788
|
+
}
|
|
1789
|
+
const teamMatch = path.match(/^\/api\/agents\/([^/]+)\/team$/);
|
|
1790
|
+
if (teamMatch && method === "GET") {
|
|
1791
|
+
const agentId = decodeURIComponent(teamMatch[1]);
|
|
1792
|
+
const { getDirectReports: getDirectReports2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
1793
|
+
return json(getDirectReports2(agentId), 200, port);
|
|
1794
|
+
}
|
|
1754
1795
|
if (path === "/api/agents" && method === "GET") {
|
|
1755
1796
|
return json(listAgents(), 200, port);
|
|
1756
1797
|
}
|