foreman-ai 1.0.0
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/README.md +56 -0
- package/dist/db.d.ts +3 -0
- package/dist/db.js +68 -0
- package/dist/db.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/items.d.ts +2 -0
- package/dist/tools/items.js +157 -0
- package/dist/tools/items.js.map +1 -0
- package/dist/tools/projects.d.ts +2 -0
- package/dist/tools/projects.js +34 -0
- package/dist/tools/projects.js.map +1 -0
- package/dist/tools/smart.d.ts +2 -0
- package/dist/tools/smart.js +118 -0
- package/dist/tools/smart.js.map +1 -0
- package/dist/types.d.ts +41 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# foreman-ai
|
|
2
|
+
|
|
3
|
+
AI Project Manager MCP server — persistent, cross-project backlog management for Claude Code.
|
|
4
|
+
|
|
5
|
+
Foreman gives Claude Code a shared backlog across all your projects. Add work items, track priorities, and ask "what should I work on next?" from any session.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g foreman-ai
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Configure
|
|
14
|
+
|
|
15
|
+
Add to your Claude Code MCP config (`~/.claude/settings.json` or project `.mcp.json`):
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"mcpServers": {
|
|
20
|
+
"foreman": {
|
|
21
|
+
"command": "foreman-ai",
|
|
22
|
+
"args": ["--db", "~/.foreman/foreman.db"]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Tools
|
|
29
|
+
|
|
30
|
+
### Project Management
|
|
31
|
+
- **pm_register_project** — Register a project (run once per project)
|
|
32
|
+
- **pm_list_projects** — List all registered projects
|
|
33
|
+
|
|
34
|
+
### Backlog CRUD
|
|
35
|
+
- **pm_add_item** — Add a work item (required: project_id, title)
|
|
36
|
+
- **pm_update_item** — Update any field on an item
|
|
37
|
+
- **pm_list_items** — List items with filters (project, status, category, tag)
|
|
38
|
+
- **pm_get_item** — Get full detail on one item
|
|
39
|
+
- **pm_delete_item** — Remove an item
|
|
40
|
+
|
|
41
|
+
### Smart Operations
|
|
42
|
+
- **pm_next_work** — "What should I work on?" Top unblocked items by priority and ROI
|
|
43
|
+
- **pm_prioritize** — Re-score items with new ROI scores
|
|
44
|
+
- **pm_bulk_import** — Import items from JSON array
|
|
45
|
+
|
|
46
|
+
## Data Model
|
|
47
|
+
|
|
48
|
+
Items have: title, description, status (backlog/ready/in_progress/done/archived), priority, category (feature/bug/research/chore), ROI score (1-10), effort (small/medium/large), blocked_by, tags, and source tracking.
|
|
49
|
+
|
|
50
|
+
## Database
|
|
51
|
+
|
|
52
|
+
SQLite, stored at `~/.foreman/foreman.db` by default. Override with `--db <path>`.
|
|
53
|
+
|
|
54
|
+
## License
|
|
55
|
+
|
|
56
|
+
MIT
|
package/dist/db.d.ts
ADDED
package/dist/db.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
let db;
|
|
5
|
+
export function getDb() {
|
|
6
|
+
if (!db) {
|
|
7
|
+
throw new Error("Database not initialized. Call initDb() first.");
|
|
8
|
+
}
|
|
9
|
+
return db;
|
|
10
|
+
}
|
|
11
|
+
export function initDb(dbPath) {
|
|
12
|
+
const dir = path.dirname(dbPath);
|
|
13
|
+
if (!fs.existsSync(dir)) {
|
|
14
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
db = new Database(dbPath);
|
|
17
|
+
db.pragma("journal_mode = WAL");
|
|
18
|
+
db.pragma("foreign_keys = ON");
|
|
19
|
+
migrate(db);
|
|
20
|
+
return db;
|
|
21
|
+
}
|
|
22
|
+
function migrate(db) {
|
|
23
|
+
db.exec(`
|
|
24
|
+
CREATE TABLE IF NOT EXISTS projects (
|
|
25
|
+
id TEXT PRIMARY KEY,
|
|
26
|
+
name TEXT NOT NULL,
|
|
27
|
+
description TEXT NOT NULL DEFAULT '',
|
|
28
|
+
repo_path TEXT NOT NULL DEFAULT '',
|
|
29
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
30
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
CREATE TABLE IF NOT EXISTS items (
|
|
34
|
+
id TEXT PRIMARY KEY,
|
|
35
|
+
project_id TEXT NOT NULL REFERENCES projects(id),
|
|
36
|
+
title TEXT NOT NULL,
|
|
37
|
+
description TEXT NOT NULL DEFAULT '',
|
|
38
|
+
status TEXT NOT NULL DEFAULT 'backlog',
|
|
39
|
+
priority INTEGER NOT NULL DEFAULT 100,
|
|
40
|
+
category TEXT NOT NULL DEFAULT 'feature',
|
|
41
|
+
roi_score INTEGER,
|
|
42
|
+
roi_reason TEXT NOT NULL DEFAULT '',
|
|
43
|
+
effort TEXT,
|
|
44
|
+
blocked_by TEXT NOT NULL DEFAULT '[]',
|
|
45
|
+
tags TEXT NOT NULL DEFAULT '[]',
|
|
46
|
+
source TEXT NOT NULL DEFAULT 'user',
|
|
47
|
+
execution_mode TEXT NOT NULL DEFAULT 'manual',
|
|
48
|
+
assigned_to TEXT NOT NULL DEFAULT '',
|
|
49
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
50
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
51
|
+
completed_at TEXT
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
55
|
+
id TEXT PRIMARY KEY,
|
|
56
|
+
project_id TEXT NOT NULL REFERENCES projects(id),
|
|
57
|
+
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
58
|
+
ended_at TEXT,
|
|
59
|
+
summary TEXT NOT NULL DEFAULT '',
|
|
60
|
+
items_touched TEXT NOT NULL DEFAULT '[]'
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
CREATE INDEX IF NOT EXISTS idx_items_project ON items(project_id);
|
|
64
|
+
CREATE INDEX IF NOT EXISTS idx_items_status ON items(status);
|
|
65
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_id);
|
|
66
|
+
`);
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=db.js.map
|
package/dist/db.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,IAAI,EAAqB,CAAC;AAE1B,MAAM,UAAU,KAAK;IACnB,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,MAAc;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC1B,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAChC,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAE/B,OAAO,CAAC,EAAE,CAAC,CAAC;IACZ,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,OAAO,CAAC,EAAqB;IACpC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CP,CAAC,CAAC;AACL,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { initDb } from "./db.js";
|
|
5
|
+
import { registerProjectTools } from "./tools/projects.js";
|
|
6
|
+
import { registerItemTools } from "./tools/items.js";
|
|
7
|
+
import { registerSmartTools } from "./tools/smart.js";
|
|
8
|
+
import path from "path";
|
|
9
|
+
import os from "os";
|
|
10
|
+
function getDbPath() {
|
|
11
|
+
const args = process.argv.slice(2);
|
|
12
|
+
const dbIndex = args.indexOf("--db");
|
|
13
|
+
if (dbIndex !== -1 && args[dbIndex + 1]) {
|
|
14
|
+
const raw = args[dbIndex + 1];
|
|
15
|
+
if (raw.startsWith("~")) {
|
|
16
|
+
return path.join(os.homedir(), raw.slice(1));
|
|
17
|
+
}
|
|
18
|
+
return path.resolve(raw);
|
|
19
|
+
}
|
|
20
|
+
return path.join(os.homedir(), ".foreman", "foreman.db");
|
|
21
|
+
}
|
|
22
|
+
async function main() {
|
|
23
|
+
const dbPath = getDbPath();
|
|
24
|
+
initDb(dbPath);
|
|
25
|
+
const server = new McpServer({
|
|
26
|
+
name: "foreman-ai",
|
|
27
|
+
version: "1.0.0",
|
|
28
|
+
});
|
|
29
|
+
registerProjectTools(server);
|
|
30
|
+
registerItemTools(server);
|
|
31
|
+
registerSmartTools(server);
|
|
32
|
+
const transport = new StdioServerTransport();
|
|
33
|
+
await server.connect(transport);
|
|
34
|
+
}
|
|
35
|
+
main().catch((err) => {
|
|
36
|
+
console.error("Foreman failed to start:", err);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
});
|
|
39
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,SAAS,SAAS;IAChB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,OAAO,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;QAC9B,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/C,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;AAC3D,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,CAAC,MAAM,CAAC,CAAC;IAEf,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAE3B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,GAAG,CAAC,CAAC;IAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { v4 as uuidv4 } from "uuid";
|
|
3
|
+
import { getDb } from "../db.js";
|
|
4
|
+
const StatusEnum = z.enum(["backlog", "ready", "in_progress", "done", "archived"]);
|
|
5
|
+
const CategoryEnum = z.enum(["feature", "bug", "research", "chore"]);
|
|
6
|
+
const EffortEnum = z.enum(["small", "medium", "large"]);
|
|
7
|
+
const SourceEnum = z.enum(["user", "claude", "auto"]);
|
|
8
|
+
const ExecutionModeEnum = z.enum(["manual", "auto"]);
|
|
9
|
+
function rowToItem(row) {
|
|
10
|
+
return {
|
|
11
|
+
...row,
|
|
12
|
+
blocked_by: JSON.parse(row.blocked_by),
|
|
13
|
+
tags: JSON.parse(row.tags),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function registerItemTools(server) {
|
|
17
|
+
server.tool("pm_add_item", "Add a work item to the backlog.", {
|
|
18
|
+
project_id: z.string().describe("Project slug"),
|
|
19
|
+
title: z.string().describe("Item title"),
|
|
20
|
+
description: z.string().optional(),
|
|
21
|
+
status: StatusEnum.optional(),
|
|
22
|
+
priority: z.number().int().optional().describe("Lower = higher priority"),
|
|
23
|
+
category: CategoryEnum.optional(),
|
|
24
|
+
roi_score: z.number().int().min(1).max(10).optional(),
|
|
25
|
+
roi_reason: z.string().optional(),
|
|
26
|
+
effort: EffortEnum.optional(),
|
|
27
|
+
blocked_by: z.array(z.string()).optional(),
|
|
28
|
+
tags: z.array(z.string()).optional(),
|
|
29
|
+
source: SourceEnum.optional(),
|
|
30
|
+
execution_mode: ExecutionModeEnum.optional(),
|
|
31
|
+
assigned_to: z.string().optional(),
|
|
32
|
+
}, async (args) => {
|
|
33
|
+
const db = getDb();
|
|
34
|
+
const id = uuidv4();
|
|
35
|
+
const now = new Date().toISOString();
|
|
36
|
+
db.prepare(`
|
|
37
|
+
INSERT INTO items (id, project_id, title, description, status, priority, category,
|
|
38
|
+
roi_score, roi_reason, effort, blocked_by, tags, source, execution_mode,
|
|
39
|
+
assigned_to, created_at, updated_at)
|
|
40
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
41
|
+
`).run(id, args.project_id, args.title, args.description ?? "", args.status ?? "backlog", args.priority ?? 100, args.category ?? "feature", args.roi_score ?? null, args.roi_reason ?? "", args.effort ?? null, JSON.stringify(args.blocked_by ?? []), JSON.stringify(args.tags ?? []), args.source ?? "user", args.execution_mode ?? "manual", args.assigned_to ?? "", now, now);
|
|
42
|
+
return { content: [{ type: "text", text: `Item '${args.title}' added (${id}).` }] };
|
|
43
|
+
});
|
|
44
|
+
server.tool("pm_update_item", "Update any fields on a work item.", {
|
|
45
|
+
id: z.string().describe("Item UUID"),
|
|
46
|
+
title: z.string().optional(),
|
|
47
|
+
description: z.string().optional(),
|
|
48
|
+
status: StatusEnum.optional(),
|
|
49
|
+
priority: z.number().int().optional(),
|
|
50
|
+
category: CategoryEnum.optional(),
|
|
51
|
+
roi_score: z.number().int().min(1).max(10).optional(),
|
|
52
|
+
roi_reason: z.string().optional(),
|
|
53
|
+
effort: EffortEnum.optional(),
|
|
54
|
+
blocked_by: z.array(z.string()).optional(),
|
|
55
|
+
tags: z.array(z.string()).optional(),
|
|
56
|
+
source: SourceEnum.optional(),
|
|
57
|
+
execution_mode: ExecutionModeEnum.optional(),
|
|
58
|
+
assigned_to: z.string().optional(),
|
|
59
|
+
}, async (args) => {
|
|
60
|
+
const db = getDb();
|
|
61
|
+
const { id, ...updates } = args;
|
|
62
|
+
const now = new Date().toISOString();
|
|
63
|
+
const sets = [];
|
|
64
|
+
const values = [];
|
|
65
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
66
|
+
if (value === undefined)
|
|
67
|
+
continue;
|
|
68
|
+
if (key === "blocked_by" || key === "tags") {
|
|
69
|
+
sets.push(`${key} = ?`);
|
|
70
|
+
values.push(JSON.stringify(value));
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
sets.push(`${key} = ?`);
|
|
74
|
+
values.push(value);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (sets.length === 0) {
|
|
78
|
+
return { content: [{ type: "text", text: "No fields to update." }] };
|
|
79
|
+
}
|
|
80
|
+
// Set completed_at when moving to done
|
|
81
|
+
if (updates.status === "done") {
|
|
82
|
+
sets.push("completed_at = ?");
|
|
83
|
+
values.push(now);
|
|
84
|
+
}
|
|
85
|
+
sets.push("updated_at = ?");
|
|
86
|
+
values.push(now);
|
|
87
|
+
values.push(id);
|
|
88
|
+
db.prepare(`UPDATE items SET ${sets.join(", ")} WHERE id = ?`).run(...values);
|
|
89
|
+
return { content: [{ type: "text", text: `Item ${id} updated.` }] };
|
|
90
|
+
});
|
|
91
|
+
server.tool("pm_list_items", "List backlog items with optional filters. Defaults to current project, non-archived.", {
|
|
92
|
+
project_id: z.string().optional().describe("Filter by project"),
|
|
93
|
+
status: StatusEnum.optional().describe("Filter by status"),
|
|
94
|
+
category: CategoryEnum.optional().describe("Filter by category"),
|
|
95
|
+
tag: z.string().optional().describe("Filter by tag"),
|
|
96
|
+
}, async (args) => {
|
|
97
|
+
const db = getDb();
|
|
98
|
+
const conditions = [];
|
|
99
|
+
const params = [];
|
|
100
|
+
if (args.project_id) {
|
|
101
|
+
conditions.push("project_id = ?");
|
|
102
|
+
params.push(args.project_id);
|
|
103
|
+
}
|
|
104
|
+
if (args.status) {
|
|
105
|
+
conditions.push("status = ?");
|
|
106
|
+
params.push(args.status);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
conditions.push("status != 'archived'");
|
|
110
|
+
}
|
|
111
|
+
if (args.category) {
|
|
112
|
+
conditions.push("category = ?");
|
|
113
|
+
params.push(args.category);
|
|
114
|
+
}
|
|
115
|
+
if (args.tag) {
|
|
116
|
+
conditions.push("tags LIKE ?");
|
|
117
|
+
params.push(`%"${args.tag}"%`);
|
|
118
|
+
}
|
|
119
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
120
|
+
const rows = db
|
|
121
|
+
.prepare(`SELECT * FROM items ${where} ORDER BY priority ASC, roi_score DESC`)
|
|
122
|
+
.all(...params);
|
|
123
|
+
if (rows.length === 0) {
|
|
124
|
+
return { content: [{ type: "text", text: "No items found." }] };
|
|
125
|
+
}
|
|
126
|
+
const items = rows.map(rowToItem);
|
|
127
|
+
const text = items
|
|
128
|
+
.map((i) => `[${i.status}] **${i.title}** (${i.id.slice(0, 8)})\n Project: ${i.project_id} | Priority: ${i.priority} | ROI: ${i.roi_score ?? "?"}/10 | ${i.category} | ${i.effort ?? "unsized"}`)
|
|
129
|
+
.join("\n\n");
|
|
130
|
+
return { content: [{ type: "text", text: `${items.length} items:\n\n${text}` }] };
|
|
131
|
+
});
|
|
132
|
+
server.tool("pm_get_item", "Get full details of a single work item.", {
|
|
133
|
+
id: z.string().describe("Item UUID (full or prefix)"),
|
|
134
|
+
}, async ({ id }) => {
|
|
135
|
+
const db = getDb();
|
|
136
|
+
const row = db
|
|
137
|
+
.prepare("SELECT * FROM items WHERE id = ? OR id LIKE ?")
|
|
138
|
+
.get(id, `${id}%`);
|
|
139
|
+
if (!row) {
|
|
140
|
+
return { content: [{ type: "text", text: `Item '${id}' not found.` }] };
|
|
141
|
+
}
|
|
142
|
+
const item = rowToItem(row);
|
|
143
|
+
const text = JSON.stringify(item, null, 2);
|
|
144
|
+
return { content: [{ type: "text", text }] };
|
|
145
|
+
});
|
|
146
|
+
server.tool("pm_delete_item", "Delete a work item.", {
|
|
147
|
+
id: z.string().describe("Item UUID"),
|
|
148
|
+
}, async ({ id }) => {
|
|
149
|
+
const db = getDb();
|
|
150
|
+
const result = db.prepare("DELETE FROM items WHERE id = ?").run(id);
|
|
151
|
+
if (result.changes === 0) {
|
|
152
|
+
return { content: [{ type: "text", text: `Item '${id}' not found.` }] };
|
|
153
|
+
}
|
|
154
|
+
return { content: [{ type: "text", text: `Item ${id} deleted.` }] };
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=items.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"items.js","sourceRoot":"","sources":["../../src/tools/items.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getDb } from "../db.js";
|
|
3
|
+
export function registerProjectTools(server) {
|
|
4
|
+
server.tool("pm_register_project", "Register a project with Foreman. Run once per project to enable backlog tracking.", {
|
|
5
|
+
id: z.string().describe("Slug ID for the project, e.g. 'paris-bets'"),
|
|
6
|
+
name: z.string().describe("Display name"),
|
|
7
|
+
description: z.string().optional().describe("Project description"),
|
|
8
|
+
repo_path: z.string().optional().describe("Filesystem path to repo root"),
|
|
9
|
+
}, async ({ id, name, description, repo_path }) => {
|
|
10
|
+
const db = getDb();
|
|
11
|
+
const now = new Date().toISOString();
|
|
12
|
+
const existing = db
|
|
13
|
+
.prepare("SELECT id FROM projects WHERE id = ?")
|
|
14
|
+
.get(id);
|
|
15
|
+
if (existing) {
|
|
16
|
+
db.prepare("UPDATE projects SET name = ?, description = ?, repo_path = ?, updated_at = ? WHERE id = ?").run(name, description ?? "", repo_path ?? "", now, id);
|
|
17
|
+
return { content: [{ type: "text", text: `Project '${id}' updated.` }] };
|
|
18
|
+
}
|
|
19
|
+
db.prepare("INSERT INTO projects (id, name, description, repo_path, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)").run(id, name, description ?? "", repo_path ?? "", now, now);
|
|
20
|
+
return { content: [{ type: "text", text: `Project '${id}' registered.` }] };
|
|
21
|
+
});
|
|
22
|
+
server.tool("pm_list_projects", "List all registered projects.", {}, async () => {
|
|
23
|
+
const db = getDb();
|
|
24
|
+
const projects = db.prepare("SELECT * FROM projects ORDER BY name").all();
|
|
25
|
+
if (projects.length === 0) {
|
|
26
|
+
return { content: [{ type: "text", text: "No projects registered. Use pm_register_project first." }] };
|
|
27
|
+
}
|
|
28
|
+
const text = projects
|
|
29
|
+
.map((p) => `**${p.name}** (${p.id})\n ${p.description || "No description"}\n Path: ${p.repo_path || "not set"}`)
|
|
30
|
+
.join("\n\n");
|
|
31
|
+
return { content: [{ type: "text", text }] };
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=projects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/tools/projects.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAGjC,MAAM,UAAU,oBAAoB,CAAC,MAAiB;IACpD,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,mFAAmF,EACnF;QACE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;QACrE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;QACzC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QAClE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;KAC1E,EACD,KAAK,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,EAAE;QAC7C,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAErC,MAAM,QAAQ,GAAG,EAAE;aAChB,OAAO,CAAC,sCAAsC,CAAC;aAC/C,GAAG,CAAC,EAAE,CAAwB,CAAC;QAElC,IAAI,QAAQ,EAAE,CAAC;YACb,EAAE,CAAC,OAAO,CACR,2FAA2F,CAC5F,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,IAAI,EAAE,EAAE,SAAS,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YAEzD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;QACpF,CAAC;QAED,EAAE,CAAC,OAAO,CACR,2GAA2G,CAC5G,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,IAAI,EAAE,EAAE,SAAS,IAAI,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAE9D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,YAAY,EAAE,eAAe,EAAE,CAAC,EAAE,CAAC;IACvF,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,+BAA+B,EAC/B,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;QACnB,MAAM,QAAQ,GAAG,EAAE,CAAC,OAAO,CAAC,sCAAsC,CAAC,CAAC,GAAG,EAAe,CAAC;QAEvF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,wDAAwD,EAAE,CAAC,EAAE,CAAC;QAClH,CAAC;QAED,MAAM,IAAI,GAAG,QAAQ;aAClB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,WAAW,IAAI,gBAAgB,aAAa,CAAC,CAAC,SAAS,IAAI,SAAS,EAAE,CAAC;aAClH,IAAI,CAAC,MAAM,CAAC,CAAC;QAEhB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IACxD,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { v4 as uuidv4 } from "uuid";
|
|
3
|
+
import { getDb } from "../db.js";
|
|
4
|
+
function rowToItem(row) {
|
|
5
|
+
return {
|
|
6
|
+
...row,
|
|
7
|
+
blocked_by: JSON.parse(row.blocked_by),
|
|
8
|
+
tags: JSON.parse(row.tags),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function registerSmartTools(server) {
|
|
12
|
+
server.tool("pm_next_work", "What should I work on next? Returns top unblocked items sorted by priority and ROI. This is the killer feature.", {
|
|
13
|
+
project_id: z.string().optional().describe("Filter by project (omit for all projects)"),
|
|
14
|
+
limit: z.number().int().min(1).max(20).optional().describe("Number of items to return (default 5)"),
|
|
15
|
+
}, async ({ project_id, limit }) => {
|
|
16
|
+
const db = getDb();
|
|
17
|
+
const max = limit ?? 5;
|
|
18
|
+
// Get all non-archived, non-done items
|
|
19
|
+
let query = `SELECT * FROM items WHERE status NOT IN ('done', 'archived')`;
|
|
20
|
+
const params = [];
|
|
21
|
+
if (project_id) {
|
|
22
|
+
query += " AND project_id = ?";
|
|
23
|
+
params.push(project_id);
|
|
24
|
+
}
|
|
25
|
+
const rows = db.prepare(query).all(...params);
|
|
26
|
+
const items = rows.map(rowToItem);
|
|
27
|
+
// Filter out blocked items: an item is blocked if any of its blocked_by IDs
|
|
28
|
+
// correspond to items that are NOT done
|
|
29
|
+
const doneIds = new Set(db.prepare("SELECT id FROM items WHERE status = 'done'").all().map((r) => r.id));
|
|
30
|
+
const unblocked = items.filter((item) => item.blocked_by.every((blockerId) => doneIds.has(blockerId)));
|
|
31
|
+
// Sort: lower priority number first, then higher ROI score, then ready before backlog
|
|
32
|
+
const statusOrder = { in_progress: 0, ready: 1, backlog: 2 };
|
|
33
|
+
unblocked.sort((a, b) => {
|
|
34
|
+
const statusDiff = (statusOrder[a.status] ?? 3) - (statusOrder[b.status] ?? 3);
|
|
35
|
+
if (statusDiff !== 0)
|
|
36
|
+
return statusDiff;
|
|
37
|
+
const priDiff = a.priority - b.priority;
|
|
38
|
+
if (priDiff !== 0)
|
|
39
|
+
return priDiff;
|
|
40
|
+
return (b.roi_score ?? 0) - (a.roi_score ?? 0);
|
|
41
|
+
});
|
|
42
|
+
const top = unblocked.slice(0, max);
|
|
43
|
+
if (top.length === 0) {
|
|
44
|
+
return {
|
|
45
|
+
content: [
|
|
46
|
+
{
|
|
47
|
+
type: "text",
|
|
48
|
+
text: "No actionable items found. Either everything is done, blocked, or archived.",
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const text = top
|
|
54
|
+
.map((i, idx) => `${idx + 1}. **${i.title}** (${i.id.slice(0, 8)})\n Status: ${i.status} | Priority: ${i.priority} | ROI: ${i.roi_score ?? "?"}/10 | ${i.category} | ${i.effort ?? "unsized"}\n ${i.description ? i.description.slice(0, 120) : "No description"}${i.roi_reason ? `\n ROI reason: ${i.roi_reason}` : ""}`)
|
|
55
|
+
.join("\n\n");
|
|
56
|
+
return {
|
|
57
|
+
content: [{ type: "text", text: `Top ${top.length} items to work on:\n\n${text}` }],
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
server.tool("pm_prioritize", "Re-score and re-rank items by ROI. Provide item IDs with new scores.", {
|
|
61
|
+
updates: z
|
|
62
|
+
.array(z.object({
|
|
63
|
+
id: z.string(),
|
|
64
|
+
roi_score: z.number().int().min(1).max(10),
|
|
65
|
+
roi_reason: z.string().optional(),
|
|
66
|
+
priority: z.number().int().optional(),
|
|
67
|
+
}))
|
|
68
|
+
.describe("Array of items with new ROI scores"),
|
|
69
|
+
}, async ({ updates }) => {
|
|
70
|
+
const db = getDb();
|
|
71
|
+
const now = new Date().toISOString();
|
|
72
|
+
const stmt = db.prepare("UPDATE items SET roi_score = ?, roi_reason = COALESCE(?, roi_reason), priority = COALESCE(?, priority), updated_at = ? WHERE id = ?");
|
|
73
|
+
let updated = 0;
|
|
74
|
+
for (const u of updates) {
|
|
75
|
+
const result = stmt.run(u.roi_score, u.roi_reason ?? null, u.priority ?? null, now, u.id);
|
|
76
|
+
updated += result.changes;
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
content: [{ type: "text", text: `Updated ${updated} of ${updates.length} items.` }],
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
server.tool("pm_bulk_import", "Import items from a JSON array. Each object needs at minimum: project_id and title.", {
|
|
83
|
+
items: z
|
|
84
|
+
.array(z.object({
|
|
85
|
+
project_id: z.string(),
|
|
86
|
+
title: z.string(),
|
|
87
|
+
description: z.string().optional(),
|
|
88
|
+
status: z.string().optional(),
|
|
89
|
+
priority: z.number().int().optional(),
|
|
90
|
+
category: z.string().optional(),
|
|
91
|
+
roi_score: z.number().int().optional(),
|
|
92
|
+
roi_reason: z.string().optional(),
|
|
93
|
+
effort: z.string().optional(),
|
|
94
|
+
blocked_by: z.array(z.string()).optional(),
|
|
95
|
+
tags: z.array(z.string()).optional(),
|
|
96
|
+
source: z.string().optional(),
|
|
97
|
+
}))
|
|
98
|
+
.describe("Array of items to import"),
|
|
99
|
+
}, async ({ items }) => {
|
|
100
|
+
const db = getDb();
|
|
101
|
+
const now = new Date().toISOString();
|
|
102
|
+
const stmt = db.prepare(`
|
|
103
|
+
INSERT INTO items (id, project_id, title, description, status, priority, category,
|
|
104
|
+
roi_score, roi_reason, effort, blocked_by, tags, source, execution_mode,
|
|
105
|
+
assigned_to, created_at, updated_at)
|
|
106
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'manual', '', ?, ?)
|
|
107
|
+
`);
|
|
108
|
+
let imported = 0;
|
|
109
|
+
for (const item of items) {
|
|
110
|
+
stmt.run(uuidv4(), item.project_id, item.title, item.description ?? "", item.status ?? "backlog", item.priority ?? 100, item.category ?? "feature", item.roi_score ?? null, item.roi_reason ?? "", item.effort ?? null, JSON.stringify(item.blocked_by ?? []), JSON.stringify(item.tags ?? []), item.source ?? "auto", now, now);
|
|
111
|
+
imported++;
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
content: [{ type: "text", text: `Imported ${imported} items.` }],
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=smart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smart.js","sourceRoot":"","sources":["../../src/tools/smart.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export type Status = "backlog" | "ready" | "in_progress" | "done" | "archived";
|
|
2
|
+
export type Category = "feature" | "bug" | "research" | "chore";
|
|
3
|
+
export type Effort = "small" | "medium" | "large";
|
|
4
|
+
export type Source = "user" | "claude" | "auto";
|
|
5
|
+
export type ExecutionMode = "manual" | "auto";
|
|
6
|
+
export interface Project {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
repo_path: string;
|
|
11
|
+
created_at: string;
|
|
12
|
+
updated_at: string;
|
|
13
|
+
}
|
|
14
|
+
export interface Item {
|
|
15
|
+
id: string;
|
|
16
|
+
project_id: string;
|
|
17
|
+
title: string;
|
|
18
|
+
description: string;
|
|
19
|
+
status: Status;
|
|
20
|
+
priority: number;
|
|
21
|
+
category: Category;
|
|
22
|
+
roi_score: number | null;
|
|
23
|
+
roi_reason: string;
|
|
24
|
+
effort: Effort | null;
|
|
25
|
+
blocked_by: string[];
|
|
26
|
+
tags: string[];
|
|
27
|
+
source: Source;
|
|
28
|
+
execution_mode: ExecutionMode;
|
|
29
|
+
assigned_to: string;
|
|
30
|
+
created_at: string;
|
|
31
|
+
updated_at: string;
|
|
32
|
+
completed_at: string | null;
|
|
33
|
+
}
|
|
34
|
+
export interface Session {
|
|
35
|
+
id: string;
|
|
36
|
+
project_id: string;
|
|
37
|
+
started_at: string;
|
|
38
|
+
ended_at: string | null;
|
|
39
|
+
summary: string;
|
|
40
|
+
items_touched: string[];
|
|
41
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "foreman-ai",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "AI Project Manager MCP server — persistent, cross-project backlog management for Claude Code",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"foreman-ai": "dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"dev": "tsc --watch",
|
|
14
|
+
"start": "node dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"mcp",
|
|
18
|
+
"claude",
|
|
19
|
+
"project-management",
|
|
20
|
+
"backlog",
|
|
21
|
+
"ai"
|
|
22
|
+
],
|
|
23
|
+
"author": "Mitchell",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"README.md"
|
|
28
|
+
],
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@modelcontextprotocol/sdk": "^1.28.0",
|
|
31
|
+
"better-sqlite3": "^12.8.0",
|
|
32
|
+
"uuid": "^13.0.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
36
|
+
"@types/node": "^25.5.0",
|
|
37
|
+
"@types/uuid": "^10.0.0",
|
|
38
|
+
"typescript": "^6.0.2"
|
|
39
|
+
}
|
|
40
|
+
}
|