@hasna/todos 0.10.17 → 0.10.19
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 +157 -1
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/task-commits.d.ts +31 -0
- package/dist/db/task-commits.d.ts.map +1 -0
- package/dist/db/task-files.d.ts +13 -0
- package/dist/db/task-files.d.ts.map +1 -1
- package/dist/index.js +17 -1
- package/dist/mcp/index.js +157 -1
- package/dist/server/index.js +17 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2911,6 +2911,22 @@ var init_database = __esm(() => {
|
|
|
2911
2911
|
CREATE INDEX IF NOT EXISTS idx_project_agent_roles_project ON project_agent_roles(project_id);
|
|
2912
2912
|
CREATE INDEX IF NOT EXISTS idx_project_agent_roles_agent ON project_agent_roles(agent_id);
|
|
2913
2913
|
INSERT OR IGNORE INTO _migrations (id) VALUES (31);
|
|
2914
|
+
`,
|
|
2915
|
+
`
|
|
2916
|
+
CREATE TABLE IF NOT EXISTS task_commits (
|
|
2917
|
+
id TEXT PRIMARY KEY,
|
|
2918
|
+
task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
|
2919
|
+
sha TEXT NOT NULL,
|
|
2920
|
+
message TEXT,
|
|
2921
|
+
author TEXT,
|
|
2922
|
+
files_changed TEXT,
|
|
2923
|
+
committed_at TEXT,
|
|
2924
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
2925
|
+
UNIQUE(task_id, sha)
|
|
2926
|
+
);
|
|
2927
|
+
CREATE INDEX IF NOT EXISTS idx_task_commits_task ON task_commits(task_id);
|
|
2928
|
+
CREATE INDEX IF NOT EXISTS idx_task_commits_sha ON task_commits(sha);
|
|
2929
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (32);
|
|
2914
2930
|
`,
|
|
2915
2931
|
`
|
|
2916
2932
|
CREATE TABLE IF NOT EXISTS file_locks (
|
|
@@ -2924,7 +2940,7 @@ var init_database = __esm(() => {
|
|
|
2924
2940
|
CREATE INDEX IF NOT EXISTS idx_file_locks_path ON file_locks(path);
|
|
2925
2941
|
CREATE INDEX IF NOT EXISTS idx_file_locks_agent ON file_locks(agent_id);
|
|
2926
2942
|
CREATE INDEX IF NOT EXISTS idx_file_locks_expires ON file_locks(expires_at);
|
|
2927
|
-
INSERT OR IGNORE INTO _migrations (id) VALUES (
|
|
2943
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (33);
|
|
2928
2944
|
`
|
|
2929
2945
|
];
|
|
2930
2946
|
});
|
|
@@ -9817,6 +9833,50 @@ var init_zod = __esm(() => {
|
|
|
9817
9833
|
init_external();
|
|
9818
9834
|
});
|
|
9819
9835
|
|
|
9836
|
+
// src/db/task-commits.ts
|
|
9837
|
+
var exports_task_commits = {};
|
|
9838
|
+
__export(exports_task_commits, {
|
|
9839
|
+
unlinkTaskCommit: () => unlinkTaskCommit,
|
|
9840
|
+
linkTaskToCommit: () => linkTaskToCommit,
|
|
9841
|
+
getTaskCommits: () => getTaskCommits,
|
|
9842
|
+
findTaskByCommit: () => findTaskByCommit
|
|
9843
|
+
});
|
|
9844
|
+
function rowToCommit(row) {
|
|
9845
|
+
return {
|
|
9846
|
+
...row,
|
|
9847
|
+
files_changed: row.files_changed ? JSON.parse(row.files_changed) : null
|
|
9848
|
+
};
|
|
9849
|
+
}
|
|
9850
|
+
function linkTaskToCommit(input, db) {
|
|
9851
|
+
const d = db || getDatabase();
|
|
9852
|
+
const existing = d.query("SELECT * FROM task_commits WHERE task_id = ? AND sha = ?").get(input.task_id, input.sha);
|
|
9853
|
+
if (existing) {
|
|
9854
|
+
d.run("UPDATE task_commits SET message = COALESCE(?, message), author = COALESCE(?, author), files_changed = COALESCE(?, files_changed), committed_at = COALESCE(?, committed_at) WHERE id = ?", [input.message ?? null, input.author ?? null, input.files_changed ? JSON.stringify(input.files_changed) : null, input.committed_at ?? null, existing.id]);
|
|
9855
|
+
return rowToCommit(d.query("SELECT * FROM task_commits WHERE id = ?").get(existing.id));
|
|
9856
|
+
}
|
|
9857
|
+
const id = uuid();
|
|
9858
|
+
d.run("INSERT INTO task_commits (id, task_id, sha, message, author, files_changed, committed_at, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", [id, input.task_id, input.sha, input.message ?? null, input.author ?? null, input.files_changed ? JSON.stringify(input.files_changed) : null, input.committed_at ?? null, now()]);
|
|
9859
|
+
return rowToCommit(d.query("SELECT * FROM task_commits WHERE id = ?").get(id));
|
|
9860
|
+
}
|
|
9861
|
+
function getTaskCommits(taskId, db) {
|
|
9862
|
+
const d = db || getDatabase();
|
|
9863
|
+
return d.query("SELECT * FROM task_commits WHERE task_id = ? ORDER BY committed_at DESC, created_at DESC").all(taskId).map(rowToCommit);
|
|
9864
|
+
}
|
|
9865
|
+
function findTaskByCommit(sha, db) {
|
|
9866
|
+
const d = db || getDatabase();
|
|
9867
|
+
const row = d.query("SELECT * FROM task_commits WHERE sha = ? OR sha LIKE ? LIMIT 1").get(sha, `${sha}%`);
|
|
9868
|
+
if (!row)
|
|
9869
|
+
return null;
|
|
9870
|
+
return { task_id: row.task_id, commit: rowToCommit(row) };
|
|
9871
|
+
}
|
|
9872
|
+
function unlinkTaskCommit(taskId, sha, db) {
|
|
9873
|
+
const d = db || getDatabase();
|
|
9874
|
+
return d.run("DELETE FROM task_commits WHERE task_id = ? AND (sha = ? OR sha LIKE ?)", [taskId, sha, `${sha}%`]).changes > 0;
|
|
9875
|
+
}
|
|
9876
|
+
var init_task_commits = __esm(() => {
|
|
9877
|
+
init_database();
|
|
9878
|
+
});
|
|
9879
|
+
|
|
9820
9880
|
// src/lib/auto-assign.ts
|
|
9821
9881
|
var exports_auto_assign = {};
|
|
9822
9882
|
__export(exports_auto_assign, {
|
|
@@ -9980,6 +10040,7 @@ __export(exports_task_files, {
|
|
|
9980
10040
|
listTaskFiles: () => listTaskFiles,
|
|
9981
10041
|
listActiveFiles: () => listActiveFiles,
|
|
9982
10042
|
getTaskFile: () => getTaskFile,
|
|
10043
|
+
getFileHeatMap: () => getFileHeatMap,
|
|
9983
10044
|
findTasksByFile: () => findTasksByFile,
|
|
9984
10045
|
detectFileConflicts: () => detectFileConflicts,
|
|
9985
10046
|
bulkFindTasksByFiles: () => bulkFindTasksByFiles,
|
|
@@ -10092,6 +10153,36 @@ function listActiveFiles(db) {
|
|
|
10092
10153
|
ORDER BY tf.updated_at DESC
|
|
10093
10154
|
`).all();
|
|
10094
10155
|
}
|
|
10156
|
+
function getFileHeatMap(opts, db) {
|
|
10157
|
+
const d = db || getDatabase();
|
|
10158
|
+
const limit = opts?.limit ?? 20;
|
|
10159
|
+
const minEdits = opts?.min_edits ?? 1;
|
|
10160
|
+
const rows = d.query(`
|
|
10161
|
+
SELECT
|
|
10162
|
+
tf.path,
|
|
10163
|
+
COUNT(*) AS edit_count,
|
|
10164
|
+
COUNT(DISTINCT COALESCE(tf.agent_id, t.assigned_to)) AS unique_agents,
|
|
10165
|
+
GROUP_CONCAT(DISTINCT COALESCE(tf.agent_id, t.assigned_to)) AS agent_ids,
|
|
10166
|
+
MAX(tf.updated_at) AS last_edited_at,
|
|
10167
|
+
SUM(CASE WHEN t.status = 'in_progress' THEN 1 ELSE 0 END) AS active_task_count
|
|
10168
|
+
FROM task_files tf
|
|
10169
|
+
JOIN tasks t ON tf.task_id = t.id
|
|
10170
|
+
WHERE tf.status != 'removed'
|
|
10171
|
+
${opts?.project_id ? `AND t.project_id = '${opts.project_id}'` : ""}
|
|
10172
|
+
GROUP BY tf.path
|
|
10173
|
+
HAVING edit_count >= ${minEdits}
|
|
10174
|
+
ORDER BY edit_count DESC, last_edited_at DESC
|
|
10175
|
+
LIMIT ${limit}
|
|
10176
|
+
`).all();
|
|
10177
|
+
return rows.map((r) => ({
|
|
10178
|
+
path: r.path,
|
|
10179
|
+
edit_count: r.edit_count,
|
|
10180
|
+
unique_agents: r.unique_agents,
|
|
10181
|
+
agent_ids: r.agent_ids ? r.agent_ids.split(",").filter(Boolean) : [],
|
|
10182
|
+
last_edited_at: r.last_edited_at,
|
|
10183
|
+
active_task_count: r.active_task_count
|
|
10184
|
+
}));
|
|
10185
|
+
}
|
|
10095
10186
|
function bulkAddTaskFiles(taskId, paths, agentId, db) {
|
|
10096
10187
|
const d = db || getDatabase();
|
|
10097
10188
|
const results = [];
|
|
@@ -11354,6 +11445,12 @@ Checklist (${done}/${task.checklist.length}):`);
|
|
|
11354
11445
|
const resolvedId = resolveId(id);
|
|
11355
11446
|
const evidence = files_changed || test_results || commit_hash || notes || attachment_ids ? { files_changed, test_results, commit_hash, notes, attachment_ids } : undefined;
|
|
11356
11447
|
const task = completeTask(resolvedId, agent_id, undefined, { skip_recurrence, confidence, ...evidence });
|
|
11448
|
+
if (commit_hash) {
|
|
11449
|
+
try {
|
|
11450
|
+
const { linkTaskToCommit: linkTaskToCommit2 } = (init_task_commits(), __toCommonJS(exports_task_commits));
|
|
11451
|
+
linkTaskToCommit2({ task_id: resolvedId, sha: commit_hash, files_changed });
|
|
11452
|
+
} catch {}
|
|
11453
|
+
}
|
|
11357
11454
|
let text = `completed: ${formatTask(task)}`;
|
|
11358
11455
|
if (task.metadata._next_recurrence) {
|
|
11359
11456
|
const next = task.metadata._next_recurrence;
|
|
@@ -13760,6 +13857,22 @@ ${lines.join(`
|
|
|
13760
13857
|
}
|
|
13761
13858
|
});
|
|
13762
13859
|
}
|
|
13860
|
+
if (shouldRegisterTool("get_file_heat_map")) {
|
|
13861
|
+
server.tool("get_file_heat_map", "Aggregate file edit frequency across all tasks and agents. Returns hottest files with edit count, unique agents, and last edit. Hot files = high coordination risk, good candidates for extra test coverage.", {
|
|
13862
|
+
limit: exports_external.number().optional().describe("Max files to return (default: 20)"),
|
|
13863
|
+
project_id: exports_external.string().optional().describe("Filter to a specific project"),
|
|
13864
|
+
min_edits: exports_external.number().optional().describe("Minimum edit count to include (default: 1)")
|
|
13865
|
+
}, async ({ limit, project_id, min_edits }) => {
|
|
13866
|
+
try {
|
|
13867
|
+
const { getFileHeatMap: getFileHeatMap2 } = (init_task_files(), __toCommonJS(exports_task_files));
|
|
13868
|
+
const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
|
|
13869
|
+
const results = getFileHeatMap2({ limit, project_id: resolvedProjectId, min_edits });
|
|
13870
|
+
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
|
|
13871
|
+
} catch (e) {
|
|
13872
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
13873
|
+
}
|
|
13874
|
+
});
|
|
13875
|
+
}
|
|
13763
13876
|
if (shouldRegisterTool("bulk_find_tasks_by_files")) {
|
|
13764
13877
|
server.tool("bulk_find_tasks_by_files", "Check multiple file paths at once for task/agent collisions. Returns per-path task list, in-progress count, and conflict flag.", {
|
|
13765
13878
|
paths: exports_external.array(exports_external.string()).describe("Array of file paths to check")
|
|
@@ -13816,6 +13929,49 @@ ${lines.join(`
|
|
|
13816
13929
|
}
|
|
13817
13930
|
});
|
|
13818
13931
|
}
|
|
13932
|
+
if (shouldRegisterTool("link_task_to_commit")) {
|
|
13933
|
+
server.tool("link_task_to_commit", "Link a git commit SHA to a task. Creates an audit trail: task \u2192 commits. Upserts on same task+sha.", {
|
|
13934
|
+
task_id: exports_external.string().describe("Task ID"),
|
|
13935
|
+
sha: exports_external.string().describe("Git commit SHA (full or short)"),
|
|
13936
|
+
message: exports_external.string().optional().describe("Commit message"),
|
|
13937
|
+
author: exports_external.string().optional().describe("Commit author"),
|
|
13938
|
+
files_changed: exports_external.array(exports_external.string()).optional().describe("Files changed in this commit"),
|
|
13939
|
+
committed_at: exports_external.string().optional().describe("ISO timestamp of commit")
|
|
13940
|
+
}, async ({ task_id, sha, message, author, files_changed, committed_at }) => {
|
|
13941
|
+
try {
|
|
13942
|
+
const { linkTaskToCommit: linkTaskToCommit2 } = (init_task_commits(), __toCommonJS(exports_task_commits));
|
|
13943
|
+
const resolvedId = resolveId(task_id);
|
|
13944
|
+
const commit = linkTaskToCommit2({ task_id: resolvedId, sha, message, author, files_changed, committed_at });
|
|
13945
|
+
return { content: [{ type: "text", text: JSON.stringify(commit, null, 2) }] };
|
|
13946
|
+
} catch (e) {
|
|
13947
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
13948
|
+
}
|
|
13949
|
+
});
|
|
13950
|
+
}
|
|
13951
|
+
if (shouldRegisterTool("get_task_commits")) {
|
|
13952
|
+
server.tool("get_task_commits", "Get all git commits linked to a task.", { task_id: exports_external.string().describe("Task ID") }, async ({ task_id }) => {
|
|
13953
|
+
try {
|
|
13954
|
+
const { getTaskCommits: getTaskCommits2 } = (init_task_commits(), __toCommonJS(exports_task_commits));
|
|
13955
|
+
const commits = getTaskCommits2(resolveId(task_id));
|
|
13956
|
+
return { content: [{ type: "text", text: JSON.stringify(commits, null, 2) }] };
|
|
13957
|
+
} catch (e) {
|
|
13958
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
13959
|
+
}
|
|
13960
|
+
});
|
|
13961
|
+
}
|
|
13962
|
+
if (shouldRegisterTool("find_task_by_commit")) {
|
|
13963
|
+
server.tool("find_task_by_commit", "Find which task a git commit SHA is linked to. Supports prefix matching.", { sha: exports_external.string().describe("Git commit SHA (full or short prefix)") }, async ({ sha }) => {
|
|
13964
|
+
try {
|
|
13965
|
+
const { findTaskByCommit: findTaskByCommit2 } = (init_task_commits(), __toCommonJS(exports_task_commits));
|
|
13966
|
+
const result = findTaskByCommit2(sha);
|
|
13967
|
+
if (!result)
|
|
13968
|
+
return { content: [{ type: "text", text: `No task linked to commit ${sha}` }] };
|
|
13969
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
13970
|
+
} catch (e) {
|
|
13971
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
13972
|
+
}
|
|
13973
|
+
});
|
|
13974
|
+
}
|
|
13819
13975
|
if (shouldRegisterTool("lock_file")) {
|
|
13820
13976
|
server.tool("lock_file", "Acquire an exclusive lock on a file path. Throws if another agent holds an active lock. Same agent re-locks refreshes the TTL.", {
|
|
13821
13977
|
path: exports_external.string().describe("File path to lock"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC,eAAO,MAAM,mBAAmB,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AA6jBtC,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAkBrD;AAyRD,wBAAgB,aAAa,IAAI,IAAI,CAKpC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED,wBAAgB,GAAG,IAAI,MAAM,CAE5B;AAED,wBAAgB,IAAI,IAAI,MAAM,CAE7B;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAK9D;AAED,wBAAgB,gBAAgB,CAAC,KAAK,SAAa,GAAG,MAAM,CAG3D;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAGpD;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA0B9F"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite";
|
|
2
|
+
export interface TaskCommit {
|
|
3
|
+
id: string;
|
|
4
|
+
task_id: string;
|
|
5
|
+
sha: string;
|
|
6
|
+
message: string | null;
|
|
7
|
+
author: string | null;
|
|
8
|
+
files_changed: string[] | null;
|
|
9
|
+
committed_at: string | null;
|
|
10
|
+
created_at: string;
|
|
11
|
+
}
|
|
12
|
+
export interface LinkTaskToCommitInput {
|
|
13
|
+
task_id: string;
|
|
14
|
+
sha: string;
|
|
15
|
+
message?: string;
|
|
16
|
+
author?: string;
|
|
17
|
+
files_changed?: string[];
|
|
18
|
+
committed_at?: string;
|
|
19
|
+
}
|
|
20
|
+
/** Link a git commit SHA to a task. Upserts on same task+sha. */
|
|
21
|
+
export declare function linkTaskToCommit(input: LinkTaskToCommitInput, db?: Database): TaskCommit;
|
|
22
|
+
/** Get all commits linked to a task. */
|
|
23
|
+
export declare function getTaskCommits(taskId: string, db?: Database): TaskCommit[];
|
|
24
|
+
/** Find which task a commit SHA is linked to. */
|
|
25
|
+
export declare function findTaskByCommit(sha: string, db?: Database): {
|
|
26
|
+
task_id: string;
|
|
27
|
+
commit: TaskCommit;
|
|
28
|
+
} | null;
|
|
29
|
+
/** Remove a commit link. */
|
|
30
|
+
export declare function unlinkTaskCommit(taskId: string, sha: string, db?: Database): boolean;
|
|
31
|
+
//# sourceMappingURL=task-commits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-commits.d.ts","sourceRoot":"","sources":["../../src/db/task-commits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3C,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,aAAa,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACpB;AAoBD,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,iEAAiE;AACjE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,UAAU,CAoBxF;AAED,wCAAwC;AACxC,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,UAAU,EAAE,CAG1E;AAED,iDAAiD;AACjD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAAG,IAAI,CAM3G;AAED,4BAA4B;AAC5B,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAGpF"}
|
package/dist/db/task-files.d.ts
CHANGED
|
@@ -57,5 +57,18 @@ export interface ActiveFileInfo {
|
|
|
57
57
|
agent_name: string | null;
|
|
58
58
|
}
|
|
59
59
|
export declare function listActiveFiles(db?: Database): ActiveFileInfo[];
|
|
60
|
+
export interface FileHeatMapEntry {
|
|
61
|
+
path: string;
|
|
62
|
+
edit_count: number;
|
|
63
|
+
unique_agents: number;
|
|
64
|
+
agent_ids: string[];
|
|
65
|
+
last_edited_at: string;
|
|
66
|
+
active_task_count: number;
|
|
67
|
+
}
|
|
68
|
+
export declare function getFileHeatMap(opts?: {
|
|
69
|
+
limit?: number;
|
|
70
|
+
project_id?: string;
|
|
71
|
+
min_edits?: number;
|
|
72
|
+
}, db?: Database): FileHeatMapEntry[];
|
|
60
73
|
export declare function bulkAddTaskFiles(taskId: string, paths: string[], agentId?: string, db?: Database): TaskFile[];
|
|
61
74
|
//# sourceMappingURL=task-files.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-files.d.ts","sourceRoot":"","sources":["../../src/db/task-files.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"task-files.d.ts","sourceRoot":"","sources":["../../src/db/task-files.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -718,6 +718,22 @@ var MIGRATIONS = [
|
|
|
718
718
|
INSERT OR IGNORE INTO _migrations (id) VALUES (31);
|
|
719
719
|
`,
|
|
720
720
|
`
|
|
721
|
+
CREATE TABLE IF NOT EXISTS task_commits (
|
|
722
|
+
id TEXT PRIMARY KEY,
|
|
723
|
+
task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
|
724
|
+
sha TEXT NOT NULL,
|
|
725
|
+
message TEXT,
|
|
726
|
+
author TEXT,
|
|
727
|
+
files_changed TEXT,
|
|
728
|
+
committed_at TEXT,
|
|
729
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
730
|
+
UNIQUE(task_id, sha)
|
|
731
|
+
);
|
|
732
|
+
CREATE INDEX IF NOT EXISTS idx_task_commits_task ON task_commits(task_id);
|
|
733
|
+
CREATE INDEX IF NOT EXISTS idx_task_commits_sha ON task_commits(sha);
|
|
734
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (32);
|
|
735
|
+
`,
|
|
736
|
+
`
|
|
721
737
|
CREATE TABLE IF NOT EXISTS file_locks (
|
|
722
738
|
id TEXT PRIMARY KEY,
|
|
723
739
|
path TEXT NOT NULL UNIQUE,
|
|
@@ -729,7 +745,7 @@ var MIGRATIONS = [
|
|
|
729
745
|
CREATE INDEX IF NOT EXISTS idx_file_locks_path ON file_locks(path);
|
|
730
746
|
CREATE INDEX IF NOT EXISTS idx_file_locks_agent ON file_locks(agent_id);
|
|
731
747
|
CREATE INDEX IF NOT EXISTS idx_file_locks_expires ON file_locks(expires_at);
|
|
732
|
-
INSERT OR IGNORE INTO _migrations (id) VALUES (
|
|
748
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (33);
|
|
733
749
|
`
|
|
734
750
|
];
|
|
735
751
|
var _db = null;
|
package/dist/mcp/index.js
CHANGED
|
@@ -956,6 +956,22 @@ var init_database = __esm(() => {
|
|
|
956
956
|
CREATE INDEX IF NOT EXISTS idx_project_agent_roles_project ON project_agent_roles(project_id);
|
|
957
957
|
CREATE INDEX IF NOT EXISTS idx_project_agent_roles_agent ON project_agent_roles(agent_id);
|
|
958
958
|
INSERT OR IGNORE INTO _migrations (id) VALUES (31);
|
|
959
|
+
`,
|
|
960
|
+
`
|
|
961
|
+
CREATE TABLE IF NOT EXISTS task_commits (
|
|
962
|
+
id TEXT PRIMARY KEY,
|
|
963
|
+
task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
|
964
|
+
sha TEXT NOT NULL,
|
|
965
|
+
message TEXT,
|
|
966
|
+
author TEXT,
|
|
967
|
+
files_changed TEXT,
|
|
968
|
+
committed_at TEXT,
|
|
969
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
970
|
+
UNIQUE(task_id, sha)
|
|
971
|
+
);
|
|
972
|
+
CREATE INDEX IF NOT EXISTS idx_task_commits_task ON task_commits(task_id);
|
|
973
|
+
CREATE INDEX IF NOT EXISTS idx_task_commits_sha ON task_commits(sha);
|
|
974
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (32);
|
|
959
975
|
`,
|
|
960
976
|
`
|
|
961
977
|
CREATE TABLE IF NOT EXISTS file_locks (
|
|
@@ -969,7 +985,7 @@ var init_database = __esm(() => {
|
|
|
969
985
|
CREATE INDEX IF NOT EXISTS idx_file_locks_path ON file_locks(path);
|
|
970
986
|
CREATE INDEX IF NOT EXISTS idx_file_locks_agent ON file_locks(agent_id);
|
|
971
987
|
CREATE INDEX IF NOT EXISTS idx_file_locks_expires ON file_locks(expires_at);
|
|
972
|
-
INSERT OR IGNORE INTO _migrations (id) VALUES (
|
|
988
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (33);
|
|
973
989
|
`
|
|
974
990
|
];
|
|
975
991
|
});
|
|
@@ -2868,6 +2884,50 @@ var init_agents = __esm(() => {
|
|
|
2868
2884
|
AGENT_ACTIVE_WINDOW_MS = 30 * 60 * 1000;
|
|
2869
2885
|
});
|
|
2870
2886
|
|
|
2887
|
+
// src/db/task-commits.ts
|
|
2888
|
+
var exports_task_commits = {};
|
|
2889
|
+
__export(exports_task_commits, {
|
|
2890
|
+
unlinkTaskCommit: () => unlinkTaskCommit,
|
|
2891
|
+
linkTaskToCommit: () => linkTaskToCommit,
|
|
2892
|
+
getTaskCommits: () => getTaskCommits,
|
|
2893
|
+
findTaskByCommit: () => findTaskByCommit
|
|
2894
|
+
});
|
|
2895
|
+
function rowToCommit(row) {
|
|
2896
|
+
return {
|
|
2897
|
+
...row,
|
|
2898
|
+
files_changed: row.files_changed ? JSON.parse(row.files_changed) : null
|
|
2899
|
+
};
|
|
2900
|
+
}
|
|
2901
|
+
function linkTaskToCommit(input, db) {
|
|
2902
|
+
const d = db || getDatabase();
|
|
2903
|
+
const existing = d.query("SELECT * FROM task_commits WHERE task_id = ? AND sha = ?").get(input.task_id, input.sha);
|
|
2904
|
+
if (existing) {
|
|
2905
|
+
d.run("UPDATE task_commits SET message = COALESCE(?, message), author = COALESCE(?, author), files_changed = COALESCE(?, files_changed), committed_at = COALESCE(?, committed_at) WHERE id = ?", [input.message ?? null, input.author ?? null, input.files_changed ? JSON.stringify(input.files_changed) : null, input.committed_at ?? null, existing.id]);
|
|
2906
|
+
return rowToCommit(d.query("SELECT * FROM task_commits WHERE id = ?").get(existing.id));
|
|
2907
|
+
}
|
|
2908
|
+
const id = uuid();
|
|
2909
|
+
d.run("INSERT INTO task_commits (id, task_id, sha, message, author, files_changed, committed_at, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", [id, input.task_id, input.sha, input.message ?? null, input.author ?? null, input.files_changed ? JSON.stringify(input.files_changed) : null, input.committed_at ?? null, now()]);
|
|
2910
|
+
return rowToCommit(d.query("SELECT * FROM task_commits WHERE id = ?").get(id));
|
|
2911
|
+
}
|
|
2912
|
+
function getTaskCommits(taskId, db) {
|
|
2913
|
+
const d = db || getDatabase();
|
|
2914
|
+
return d.query("SELECT * FROM task_commits WHERE task_id = ? ORDER BY committed_at DESC, created_at DESC").all(taskId).map(rowToCommit);
|
|
2915
|
+
}
|
|
2916
|
+
function findTaskByCommit(sha, db) {
|
|
2917
|
+
const d = db || getDatabase();
|
|
2918
|
+
const row = d.query("SELECT * FROM task_commits WHERE sha = ? OR sha LIKE ? LIMIT 1").get(sha, `${sha}%`);
|
|
2919
|
+
if (!row)
|
|
2920
|
+
return null;
|
|
2921
|
+
return { task_id: row.task_id, commit: rowToCommit(row) };
|
|
2922
|
+
}
|
|
2923
|
+
function unlinkTaskCommit(taskId, sha, db) {
|
|
2924
|
+
const d = db || getDatabase();
|
|
2925
|
+
return d.run("DELETE FROM task_commits WHERE task_id = ? AND (sha = ? OR sha LIKE ?)", [taskId, sha, `${sha}%`]).changes > 0;
|
|
2926
|
+
}
|
|
2927
|
+
var init_task_commits = __esm(() => {
|
|
2928
|
+
init_database();
|
|
2929
|
+
});
|
|
2930
|
+
|
|
2871
2931
|
// src/lib/auto-assign.ts
|
|
2872
2932
|
var exports_auto_assign = {};
|
|
2873
2933
|
__export(exports_auto_assign, {
|
|
@@ -3031,6 +3091,7 @@ __export(exports_task_files, {
|
|
|
3031
3091
|
listTaskFiles: () => listTaskFiles,
|
|
3032
3092
|
listActiveFiles: () => listActiveFiles,
|
|
3033
3093
|
getTaskFile: () => getTaskFile,
|
|
3094
|
+
getFileHeatMap: () => getFileHeatMap,
|
|
3034
3095
|
findTasksByFile: () => findTasksByFile,
|
|
3035
3096
|
detectFileConflicts: () => detectFileConflicts,
|
|
3036
3097
|
bulkFindTasksByFiles: () => bulkFindTasksByFiles,
|
|
@@ -3143,6 +3204,36 @@ function listActiveFiles(db) {
|
|
|
3143
3204
|
ORDER BY tf.updated_at DESC
|
|
3144
3205
|
`).all();
|
|
3145
3206
|
}
|
|
3207
|
+
function getFileHeatMap(opts, db) {
|
|
3208
|
+
const d = db || getDatabase();
|
|
3209
|
+
const limit = opts?.limit ?? 20;
|
|
3210
|
+
const minEdits = opts?.min_edits ?? 1;
|
|
3211
|
+
const rows = d.query(`
|
|
3212
|
+
SELECT
|
|
3213
|
+
tf.path,
|
|
3214
|
+
COUNT(*) AS edit_count,
|
|
3215
|
+
COUNT(DISTINCT COALESCE(tf.agent_id, t.assigned_to)) AS unique_agents,
|
|
3216
|
+
GROUP_CONCAT(DISTINCT COALESCE(tf.agent_id, t.assigned_to)) AS agent_ids,
|
|
3217
|
+
MAX(tf.updated_at) AS last_edited_at,
|
|
3218
|
+
SUM(CASE WHEN t.status = 'in_progress' THEN 1 ELSE 0 END) AS active_task_count
|
|
3219
|
+
FROM task_files tf
|
|
3220
|
+
JOIN tasks t ON tf.task_id = t.id
|
|
3221
|
+
WHERE tf.status != 'removed'
|
|
3222
|
+
${opts?.project_id ? `AND t.project_id = '${opts.project_id}'` : ""}
|
|
3223
|
+
GROUP BY tf.path
|
|
3224
|
+
HAVING edit_count >= ${minEdits}
|
|
3225
|
+
ORDER BY edit_count DESC, last_edited_at DESC
|
|
3226
|
+
LIMIT ${limit}
|
|
3227
|
+
`).all();
|
|
3228
|
+
return rows.map((r) => ({
|
|
3229
|
+
path: r.path,
|
|
3230
|
+
edit_count: r.edit_count,
|
|
3231
|
+
unique_agents: r.unique_agents,
|
|
3232
|
+
agent_ids: r.agent_ids ? r.agent_ids.split(",").filter(Boolean) : [],
|
|
3233
|
+
last_edited_at: r.last_edited_at,
|
|
3234
|
+
active_task_count: r.active_task_count
|
|
3235
|
+
}));
|
|
3236
|
+
}
|
|
3146
3237
|
function bulkAddTaskFiles(taskId, paths, agentId, db) {
|
|
3147
3238
|
const d = db || getDatabase();
|
|
3148
3239
|
const results = [];
|
|
@@ -9166,6 +9257,12 @@ if (shouldRegisterTool("complete_task")) {
|
|
|
9166
9257
|
const resolvedId = resolveId(id);
|
|
9167
9258
|
const evidence = files_changed || test_results || commit_hash || notes || attachment_ids ? { files_changed, test_results, commit_hash, notes, attachment_ids } : undefined;
|
|
9168
9259
|
const task = completeTask(resolvedId, agent_id, undefined, { skip_recurrence, confidence, ...evidence });
|
|
9260
|
+
if (commit_hash) {
|
|
9261
|
+
try {
|
|
9262
|
+
const { linkTaskToCommit: linkTaskToCommit2 } = (init_task_commits(), __toCommonJS(exports_task_commits));
|
|
9263
|
+
linkTaskToCommit2({ task_id: resolvedId, sha: commit_hash, files_changed });
|
|
9264
|
+
} catch {}
|
|
9265
|
+
}
|
|
9169
9266
|
let text = `completed: ${formatTask(task)}`;
|
|
9170
9267
|
if (task.metadata._next_recurrence) {
|
|
9171
9268
|
const next = task.metadata._next_recurrence;
|
|
@@ -11572,6 +11669,22 @@ ${lines.join(`
|
|
|
11572
11669
|
}
|
|
11573
11670
|
});
|
|
11574
11671
|
}
|
|
11672
|
+
if (shouldRegisterTool("get_file_heat_map")) {
|
|
11673
|
+
server.tool("get_file_heat_map", "Aggregate file edit frequency across all tasks and agents. Returns hottest files with edit count, unique agents, and last edit. Hot files = high coordination risk, good candidates for extra test coverage.", {
|
|
11674
|
+
limit: exports_external.number().optional().describe("Max files to return (default: 20)"),
|
|
11675
|
+
project_id: exports_external.string().optional().describe("Filter to a specific project"),
|
|
11676
|
+
min_edits: exports_external.number().optional().describe("Minimum edit count to include (default: 1)")
|
|
11677
|
+
}, async ({ limit, project_id, min_edits }) => {
|
|
11678
|
+
try {
|
|
11679
|
+
const { getFileHeatMap: getFileHeatMap2 } = (init_task_files(), __toCommonJS(exports_task_files));
|
|
11680
|
+
const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
|
|
11681
|
+
const results = getFileHeatMap2({ limit, project_id: resolvedProjectId, min_edits });
|
|
11682
|
+
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
|
|
11683
|
+
} catch (e) {
|
|
11684
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
11685
|
+
}
|
|
11686
|
+
});
|
|
11687
|
+
}
|
|
11575
11688
|
if (shouldRegisterTool("bulk_find_tasks_by_files")) {
|
|
11576
11689
|
server.tool("bulk_find_tasks_by_files", "Check multiple file paths at once for task/agent collisions. Returns per-path task list, in-progress count, and conflict flag.", {
|
|
11577
11690
|
paths: exports_external.array(exports_external.string()).describe("Array of file paths to check")
|
|
@@ -11628,6 +11741,49 @@ if (shouldRegisterTool("list_active_files")) {
|
|
|
11628
11741
|
}
|
|
11629
11742
|
});
|
|
11630
11743
|
}
|
|
11744
|
+
if (shouldRegisterTool("link_task_to_commit")) {
|
|
11745
|
+
server.tool("link_task_to_commit", "Link a git commit SHA to a task. Creates an audit trail: task \u2192 commits. Upserts on same task+sha.", {
|
|
11746
|
+
task_id: exports_external.string().describe("Task ID"),
|
|
11747
|
+
sha: exports_external.string().describe("Git commit SHA (full or short)"),
|
|
11748
|
+
message: exports_external.string().optional().describe("Commit message"),
|
|
11749
|
+
author: exports_external.string().optional().describe("Commit author"),
|
|
11750
|
+
files_changed: exports_external.array(exports_external.string()).optional().describe("Files changed in this commit"),
|
|
11751
|
+
committed_at: exports_external.string().optional().describe("ISO timestamp of commit")
|
|
11752
|
+
}, async ({ task_id, sha, message, author, files_changed, committed_at }) => {
|
|
11753
|
+
try {
|
|
11754
|
+
const { linkTaskToCommit: linkTaskToCommit2 } = (init_task_commits(), __toCommonJS(exports_task_commits));
|
|
11755
|
+
const resolvedId = resolveId(task_id);
|
|
11756
|
+
const commit = linkTaskToCommit2({ task_id: resolvedId, sha, message, author, files_changed, committed_at });
|
|
11757
|
+
return { content: [{ type: "text", text: JSON.stringify(commit, null, 2) }] };
|
|
11758
|
+
} catch (e) {
|
|
11759
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
11760
|
+
}
|
|
11761
|
+
});
|
|
11762
|
+
}
|
|
11763
|
+
if (shouldRegisterTool("get_task_commits")) {
|
|
11764
|
+
server.tool("get_task_commits", "Get all git commits linked to a task.", { task_id: exports_external.string().describe("Task ID") }, async ({ task_id }) => {
|
|
11765
|
+
try {
|
|
11766
|
+
const { getTaskCommits: getTaskCommits2 } = (init_task_commits(), __toCommonJS(exports_task_commits));
|
|
11767
|
+
const commits = getTaskCommits2(resolveId(task_id));
|
|
11768
|
+
return { content: [{ type: "text", text: JSON.stringify(commits, null, 2) }] };
|
|
11769
|
+
} catch (e) {
|
|
11770
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
11771
|
+
}
|
|
11772
|
+
});
|
|
11773
|
+
}
|
|
11774
|
+
if (shouldRegisterTool("find_task_by_commit")) {
|
|
11775
|
+
server.tool("find_task_by_commit", "Find which task a git commit SHA is linked to. Supports prefix matching.", { sha: exports_external.string().describe("Git commit SHA (full or short prefix)") }, async ({ sha }) => {
|
|
11776
|
+
try {
|
|
11777
|
+
const { findTaskByCommit: findTaskByCommit2 } = (init_task_commits(), __toCommonJS(exports_task_commits));
|
|
11778
|
+
const result = findTaskByCommit2(sha);
|
|
11779
|
+
if (!result)
|
|
11780
|
+
return { content: [{ type: "text", text: `No task linked to commit ${sha}` }] };
|
|
11781
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
11782
|
+
} catch (e) {
|
|
11783
|
+
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
11784
|
+
}
|
|
11785
|
+
});
|
|
11786
|
+
}
|
|
11631
11787
|
if (shouldRegisterTool("lock_file")) {
|
|
11632
11788
|
server.tool("lock_file", "Acquire an exclusive lock on a file path. Throws if another agent holds an active lock. Same agent re-locks refreshes the TTL.", {
|
|
11633
11789
|
path: exports_external.string().describe("File path to lock"),
|
package/dist/server/index.js
CHANGED
|
@@ -872,6 +872,22 @@ var init_database = __esm(() => {
|
|
|
872
872
|
CREATE INDEX IF NOT EXISTS idx_project_agent_roles_project ON project_agent_roles(project_id);
|
|
873
873
|
CREATE INDEX IF NOT EXISTS idx_project_agent_roles_agent ON project_agent_roles(agent_id);
|
|
874
874
|
INSERT OR IGNORE INTO _migrations (id) VALUES (31);
|
|
875
|
+
`,
|
|
876
|
+
`
|
|
877
|
+
CREATE TABLE IF NOT EXISTS task_commits (
|
|
878
|
+
id TEXT PRIMARY KEY,
|
|
879
|
+
task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
|
880
|
+
sha TEXT NOT NULL,
|
|
881
|
+
message TEXT,
|
|
882
|
+
author TEXT,
|
|
883
|
+
files_changed TEXT,
|
|
884
|
+
committed_at TEXT,
|
|
885
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
886
|
+
UNIQUE(task_id, sha)
|
|
887
|
+
);
|
|
888
|
+
CREATE INDEX IF NOT EXISTS idx_task_commits_task ON task_commits(task_id);
|
|
889
|
+
CREATE INDEX IF NOT EXISTS idx_task_commits_sha ON task_commits(sha);
|
|
890
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (32);
|
|
875
891
|
`,
|
|
876
892
|
`
|
|
877
893
|
CREATE TABLE IF NOT EXISTS file_locks (
|
|
@@ -885,7 +901,7 @@ var init_database = __esm(() => {
|
|
|
885
901
|
CREATE INDEX IF NOT EXISTS idx_file_locks_path ON file_locks(path);
|
|
886
902
|
CREATE INDEX IF NOT EXISTS idx_file_locks_agent ON file_locks(agent_id);
|
|
887
903
|
CREATE INDEX IF NOT EXISTS idx_file_locks_expires ON file_locks(expires_at);
|
|
888
|
-
INSERT OR IGNORE INTO _migrations (id) VALUES (
|
|
904
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (33);
|
|
889
905
|
`
|
|
890
906
|
];
|
|
891
907
|
});
|