@hasna/todos 0.9.52 → 0.9.54
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 +67 -35
- package/dist/mcp/index.js +22 -3
- package/dist/server/index.js +13 -0
- package/dist/server/serve.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -9154,6 +9154,18 @@ var init_zod = __esm(() => {
|
|
|
9154
9154
|
var exports_mcp = {};
|
|
9155
9155
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9156
9156
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
9157
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
9158
|
+
import { join as join6, dirname as dirname2 } from "path";
|
|
9159
|
+
import { fileURLToPath } from "url";
|
|
9160
|
+
function getMcpVersion() {
|
|
9161
|
+
try {
|
|
9162
|
+
const __dir = dirname2(fileURLToPath(import.meta.url));
|
|
9163
|
+
const pkgPath = join6(__dir, "..", "package.json");
|
|
9164
|
+
return JSON.parse(readFileSync3(pkgPath, "utf-8")).version || "0.0.0";
|
|
9165
|
+
} catch {
|
|
9166
|
+
return "0.0.0";
|
|
9167
|
+
}
|
|
9168
|
+
}
|
|
9157
9169
|
function shouldRegisterTool(name) {
|
|
9158
9170
|
if (TODOS_PROFILE === "minimal")
|
|
9159
9171
|
return MINIMAL_TOOLS.has(name);
|
|
@@ -9273,7 +9285,7 @@ var init_mcp = __esm(() => {
|
|
|
9273
9285
|
init_types();
|
|
9274
9286
|
server = new McpServer({
|
|
9275
9287
|
name: "todos",
|
|
9276
|
-
version:
|
|
9288
|
+
version: getMcpVersion()
|
|
9277
9289
|
});
|
|
9278
9290
|
TODOS_PROFILE = (process.env["TODOS_PROFILE"] || "full").toLowerCase();
|
|
9279
9291
|
MINIMAL_TOOLS = new Set([
|
|
@@ -10331,8 +10343,15 @@ Retry task created: ${formatTask(result.retryTask)}`;
|
|
|
10331
10343
|
}, async ({ agent_name }) => {
|
|
10332
10344
|
try {
|
|
10333
10345
|
const agent = registerAgent({ name: agent_name });
|
|
10334
|
-
const
|
|
10335
|
-
const
|
|
10346
|
+
const byName = listTasks({ assigned_to: agent_name });
|
|
10347
|
+
const byId = listTasks({ agent_id: agent.id });
|
|
10348
|
+
const seen = new Set;
|
|
10349
|
+
const myTasks = [...byName, ...byId].filter((t) => {
|
|
10350
|
+
if (seen.has(t.id))
|
|
10351
|
+
return false;
|
|
10352
|
+
seen.add(t.id);
|
|
10353
|
+
return true;
|
|
10354
|
+
});
|
|
10336
10355
|
const pending = myTasks.filter((t) => t.status === "pending");
|
|
10337
10356
|
const inProgress = myTasks.filter((t) => t.status === "in_progress");
|
|
10338
10357
|
const completed = myTasks.filter((t) => t.status === "completed");
|
|
@@ -11222,26 +11241,26 @@ __export(exports_serve, {
|
|
|
11222
11241
|
startServer: () => startServer
|
|
11223
11242
|
});
|
|
11224
11243
|
import { existsSync as existsSync6 } from "fs";
|
|
11225
|
-
import { join as
|
|
11226
|
-
import { fileURLToPath } from "url";
|
|
11244
|
+
import { join as join7, dirname as dirname3, extname, resolve as resolve2, sep } from "path";
|
|
11245
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
11227
11246
|
function resolveDashboardDir() {
|
|
11228
11247
|
const candidates = [];
|
|
11229
11248
|
try {
|
|
11230
|
-
const scriptDir =
|
|
11231
|
-
candidates.push(
|
|
11232
|
-
candidates.push(
|
|
11249
|
+
const scriptDir = dirname3(fileURLToPath2(import.meta.url));
|
|
11250
|
+
candidates.push(join7(scriptDir, "..", "dashboard", "dist"));
|
|
11251
|
+
candidates.push(join7(scriptDir, "..", "..", "dashboard", "dist"));
|
|
11233
11252
|
} catch {}
|
|
11234
11253
|
if (process.argv[1]) {
|
|
11235
|
-
const mainDir =
|
|
11236
|
-
candidates.push(
|
|
11237
|
-
candidates.push(
|
|
11254
|
+
const mainDir = dirname3(process.argv[1]);
|
|
11255
|
+
candidates.push(join7(mainDir, "..", "dashboard", "dist"));
|
|
11256
|
+
candidates.push(join7(mainDir, "..", "..", "dashboard", "dist"));
|
|
11238
11257
|
}
|
|
11239
|
-
candidates.push(
|
|
11258
|
+
candidates.push(join7(process.cwd(), "dashboard", "dist"));
|
|
11240
11259
|
for (const candidate of candidates) {
|
|
11241
11260
|
if (existsSync6(candidate))
|
|
11242
11261
|
return candidate;
|
|
11243
11262
|
}
|
|
11244
|
-
return
|
|
11263
|
+
return join7(process.cwd(), "dashboard", "dist");
|
|
11245
11264
|
}
|
|
11246
11265
|
function json(data, status = 200, port) {
|
|
11247
11266
|
return new Response(JSON.stringify(data), {
|
|
@@ -11641,6 +11660,19 @@ data: ${JSON.stringify({ type: "connected", agent_id: agentId, timestamp: new Da
|
|
|
11641
11660
|
return json({ error: e instanceof Error ? e.message : "Failed to start task" }, 500, port);
|
|
11642
11661
|
}
|
|
11643
11662
|
}
|
|
11663
|
+
const failMatch = path.match(/^\/api\/tasks\/([^/]+)\/fail$/);
|
|
11664
|
+
if (failMatch && method === "POST") {
|
|
11665
|
+
const id = failMatch[1];
|
|
11666
|
+
try {
|
|
11667
|
+
const body = await req.json().catch(() => ({}));
|
|
11668
|
+
const { failTask: failTask2 } = await Promise.resolve().then(() => (init_tasks(), exports_tasks));
|
|
11669
|
+
const result = failTask2(id, body.agent_id, body.reason, { retry: body.retry, error_code: body.error_code });
|
|
11670
|
+
broadcastEvent({ type: "task", task_id: id, action: "failed", agent_id: body.agent_id || null });
|
|
11671
|
+
return json({ task: taskToSummary(result.task), retry_task: result.retryTask ? taskToSummary(result.retryTask) : null }, 200, port);
|
|
11672
|
+
} catch (e) {
|
|
11673
|
+
return json({ error: e instanceof Error ? e.message : "Failed to fail task" }, 500, port);
|
|
11674
|
+
}
|
|
11675
|
+
}
|
|
11644
11676
|
const completeMatch = path.match(/^\/api\/tasks\/([^/]+)\/complete$/);
|
|
11645
11677
|
if (completeMatch && method === "POST") {
|
|
11646
11678
|
const id = completeMatch[1];
|
|
@@ -11953,7 +11985,7 @@ data: ${JSON.stringify({ type: "connected", agent_id: agentId, timestamp: new Da
|
|
|
11953
11985
|
}
|
|
11954
11986
|
if (dashboardExists && (method === "GET" || method === "HEAD")) {
|
|
11955
11987
|
if (path !== "/") {
|
|
11956
|
-
const filePath =
|
|
11988
|
+
const filePath = join7(dashboardDir, path);
|
|
11957
11989
|
const resolvedFile = resolve2(filePath);
|
|
11958
11990
|
const resolvedBase = resolve2(dashboardDir);
|
|
11959
11991
|
if (!resolvedFile.startsWith(resolvedBase + sep) && resolvedFile !== resolvedBase) {
|
|
@@ -11963,7 +11995,7 @@ data: ${JSON.stringify({ type: "connected", agent_id: agentId, timestamp: new Da
|
|
|
11963
11995
|
if (res2)
|
|
11964
11996
|
return res2;
|
|
11965
11997
|
}
|
|
11966
|
-
const indexPath =
|
|
11998
|
+
const indexPath = join7(dashboardDir, "index.html");
|
|
11967
11999
|
const res = serveStaticFile(indexPath);
|
|
11968
12000
|
if (res)
|
|
11969
12001
|
return res;
|
|
@@ -13098,13 +13130,13 @@ init_sync();
|
|
|
13098
13130
|
init_config();
|
|
13099
13131
|
import chalk from "chalk";
|
|
13100
13132
|
import { execSync } from "child_process";
|
|
13101
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as
|
|
13102
|
-
import { basename, dirname as
|
|
13103
|
-
import { fileURLToPath as
|
|
13133
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
13134
|
+
import { basename, dirname as dirname4, join as join8, resolve as resolve3 } from "path";
|
|
13135
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
13104
13136
|
function getPackageVersion() {
|
|
13105
13137
|
try {
|
|
13106
|
-
const pkgPath =
|
|
13107
|
-
return JSON.parse(
|
|
13138
|
+
const pkgPath = join8(dirname4(fileURLToPath3(import.meta.url)), "..", "..", "package.json");
|
|
13139
|
+
return JSON.parse(readFileSync4(pkgPath, "utf-8")).version || "0.0.0";
|
|
13108
13140
|
} catch {
|
|
13109
13141
|
return "0.0.0";
|
|
13110
13142
|
}
|
|
@@ -14009,7 +14041,7 @@ hooks.command("install").description("Install Claude Code hooks for auto-sync").
|
|
|
14009
14041
|
if (p)
|
|
14010
14042
|
todosBin = p;
|
|
14011
14043
|
} catch {}
|
|
14012
|
-
const hooksDir =
|
|
14044
|
+
const hooksDir = join8(process.cwd(), ".claude", "hooks");
|
|
14013
14045
|
if (!existsSync7(hooksDir))
|
|
14014
14046
|
mkdirSync3(hooksDir, { recursive: true });
|
|
14015
14047
|
const hookScript = `#!/usr/bin/env bash
|
|
@@ -14035,11 +14067,11 @@ esac
|
|
|
14035
14067
|
|
|
14036
14068
|
exit 0
|
|
14037
14069
|
`;
|
|
14038
|
-
const hookPath =
|
|
14070
|
+
const hookPath = join8(hooksDir, "todos-sync.sh");
|
|
14039
14071
|
writeFileSync3(hookPath, hookScript);
|
|
14040
14072
|
execSync(`chmod +x "${hookPath}"`);
|
|
14041
14073
|
console.log(chalk.green(`Hook script created: ${hookPath}`));
|
|
14042
|
-
const settingsPath =
|
|
14074
|
+
const settingsPath = join8(process.cwd(), ".claude", "settings.json");
|
|
14043
14075
|
const settings = readJsonFile2(settingsPath);
|
|
14044
14076
|
if (!settings["hooks"]) {
|
|
14045
14077
|
settings["hooks"] = {};
|
|
@@ -14086,7 +14118,7 @@ function getMcpBinaryPath() {
|
|
|
14086
14118
|
if (p)
|
|
14087
14119
|
return p;
|
|
14088
14120
|
} catch {}
|
|
14089
|
-
const bunBin =
|
|
14121
|
+
const bunBin = join8(HOME2, ".bun", "bin", "todos-mcp");
|
|
14090
14122
|
if (existsSync7(bunBin))
|
|
14091
14123
|
return bunBin;
|
|
14092
14124
|
return "todos-mcp";
|
|
@@ -14095,13 +14127,13 @@ function readJsonFile2(path) {
|
|
|
14095
14127
|
if (!existsSync7(path))
|
|
14096
14128
|
return {};
|
|
14097
14129
|
try {
|
|
14098
|
-
return JSON.parse(
|
|
14130
|
+
return JSON.parse(readFileSync4(path, "utf-8"));
|
|
14099
14131
|
} catch {
|
|
14100
14132
|
return {};
|
|
14101
14133
|
}
|
|
14102
14134
|
}
|
|
14103
14135
|
function writeJsonFile2(path, data) {
|
|
14104
|
-
const dir =
|
|
14136
|
+
const dir = dirname4(path);
|
|
14105
14137
|
if (!existsSync7(dir))
|
|
14106
14138
|
mkdirSync3(dir, { recursive: true });
|
|
14107
14139
|
writeFileSync3(path, JSON.stringify(data, null, 2) + `
|
|
@@ -14110,10 +14142,10 @@ function writeJsonFile2(path, data) {
|
|
|
14110
14142
|
function readTomlFile(path) {
|
|
14111
14143
|
if (!existsSync7(path))
|
|
14112
14144
|
return "";
|
|
14113
|
-
return
|
|
14145
|
+
return readFileSync4(path, "utf-8");
|
|
14114
14146
|
}
|
|
14115
14147
|
function writeTomlFile(path, content) {
|
|
14116
|
-
const dir =
|
|
14148
|
+
const dir = dirname4(path);
|
|
14117
14149
|
if (!existsSync7(dir))
|
|
14118
14150
|
mkdirSync3(dir, { recursive: true });
|
|
14119
14151
|
writeFileSync3(path, content);
|
|
@@ -14141,7 +14173,7 @@ function unregisterClaude(_global) {
|
|
|
14141
14173
|
}
|
|
14142
14174
|
}
|
|
14143
14175
|
function registerCodex(binPath) {
|
|
14144
|
-
const configPath =
|
|
14176
|
+
const configPath = join8(HOME2, ".codex", "config.toml");
|
|
14145
14177
|
let content = readTomlFile(configPath);
|
|
14146
14178
|
content = removeTomlBlock(content, "mcp_servers.todos");
|
|
14147
14179
|
const block = `
|
|
@@ -14155,7 +14187,7 @@ args = []
|
|
|
14155
14187
|
console.log(chalk.green(`Codex CLI: registered in ${configPath}`));
|
|
14156
14188
|
}
|
|
14157
14189
|
function unregisterCodex() {
|
|
14158
|
-
const configPath =
|
|
14190
|
+
const configPath = join8(HOME2, ".codex", "config.toml");
|
|
14159
14191
|
let content = readTomlFile(configPath);
|
|
14160
14192
|
if (!content.includes("[mcp_servers.todos]")) {
|
|
14161
14193
|
console.log(chalk.dim(`Codex CLI: todos not found in ${configPath}`));
|
|
@@ -14188,7 +14220,7 @@ function removeTomlBlock(content, blockName) {
|
|
|
14188
14220
|
`);
|
|
14189
14221
|
}
|
|
14190
14222
|
function registerGemini(binPath) {
|
|
14191
|
-
const configPath =
|
|
14223
|
+
const configPath = join8(HOME2, ".gemini", "settings.json");
|
|
14192
14224
|
const config = readJsonFile2(configPath);
|
|
14193
14225
|
if (!config["mcpServers"]) {
|
|
14194
14226
|
config["mcpServers"] = {};
|
|
@@ -14202,7 +14234,7 @@ function registerGemini(binPath) {
|
|
|
14202
14234
|
console.log(chalk.green(`Gemini CLI: registered in ${configPath}`));
|
|
14203
14235
|
}
|
|
14204
14236
|
function unregisterGemini() {
|
|
14205
|
-
const configPath =
|
|
14237
|
+
const configPath = join8(HOME2, ".gemini", "settings.json");
|
|
14206
14238
|
const config = readJsonFile2(configPath);
|
|
14207
14239
|
const servers = config["mcpServers"];
|
|
14208
14240
|
if (!servers || !("todos" in servers)) {
|
|
@@ -14415,7 +14447,7 @@ Updated to ${latestVersion}!`));
|
|
|
14415
14447
|
});
|
|
14416
14448
|
program2.command("config").description("View or update configuration").option("--get <key>", "Get a config value").option("--set <key=value>", "Set a config value (e.g. completion_guard.enabled=true)").action((opts) => {
|
|
14417
14449
|
const globalOpts = program2.opts();
|
|
14418
|
-
const configPath =
|
|
14450
|
+
const configPath = join8(process.env["HOME"] || "~", ".todos", "config.json");
|
|
14419
14451
|
if (opts.get) {
|
|
14420
14452
|
const config2 = loadConfig();
|
|
14421
14453
|
const keys = opts.get.split(".");
|
|
@@ -14441,7 +14473,7 @@ program2.command("config").description("View or update configuration").option("-
|
|
|
14441
14473
|
}
|
|
14442
14474
|
let config2 = {};
|
|
14443
14475
|
try {
|
|
14444
|
-
config2 = JSON.parse(
|
|
14476
|
+
config2 = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
14445
14477
|
} catch {}
|
|
14446
14478
|
const keys = key.split(".");
|
|
14447
14479
|
let obj = config2;
|
|
@@ -14451,7 +14483,7 @@ program2.command("config").description("View or update configuration").option("-
|
|
|
14451
14483
|
obj = obj[keys[i]];
|
|
14452
14484
|
}
|
|
14453
14485
|
obj[keys[keys.length - 1]] = parsedValue;
|
|
14454
|
-
const dir =
|
|
14486
|
+
const dir = dirname4(configPath);
|
|
14455
14487
|
if (!existsSync7(dir))
|
|
14456
14488
|
mkdirSync3(dir, { recursive: true });
|
|
14457
14489
|
writeFileSync3(configPath, JSON.stringify(config2, null, 2));
|
package/dist/mcp/index.js
CHANGED
|
@@ -6946,9 +6946,21 @@ function syncWithAgents(agents, taskListIdByAgent, projectId, direction = "both"
|
|
|
6946
6946
|
|
|
6947
6947
|
// src/mcp/index.ts
|
|
6948
6948
|
init_database();
|
|
6949
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
6950
|
+
import { join as join6, dirname as dirname2 } from "path";
|
|
6951
|
+
import { fileURLToPath } from "url";
|
|
6952
|
+
function getMcpVersion() {
|
|
6953
|
+
try {
|
|
6954
|
+
const __dir = dirname2(fileURLToPath(import.meta.url));
|
|
6955
|
+
const pkgPath = join6(__dir, "..", "package.json");
|
|
6956
|
+
return JSON.parse(readFileSync3(pkgPath, "utf-8")).version || "0.0.0";
|
|
6957
|
+
} catch {
|
|
6958
|
+
return "0.0.0";
|
|
6959
|
+
}
|
|
6960
|
+
}
|
|
6949
6961
|
var server = new McpServer({
|
|
6950
6962
|
name: "todos",
|
|
6951
|
-
version:
|
|
6963
|
+
version: getMcpVersion()
|
|
6952
6964
|
});
|
|
6953
6965
|
var TODOS_PROFILE = (process.env["TODOS_PROFILE"] || "full").toLowerCase();
|
|
6954
6966
|
var MINIMAL_TOOLS = new Set([
|
|
@@ -8105,8 +8117,15 @@ if (shouldRegisterTool("get_my_tasks")) {
|
|
|
8105
8117
|
}, async ({ agent_name }) => {
|
|
8106
8118
|
try {
|
|
8107
8119
|
const agent = registerAgent({ name: agent_name });
|
|
8108
|
-
const
|
|
8109
|
-
const
|
|
8120
|
+
const byName = listTasks({ assigned_to: agent_name });
|
|
8121
|
+
const byId = listTasks({ agent_id: agent.id });
|
|
8122
|
+
const seen = new Set;
|
|
8123
|
+
const myTasks = [...byName, ...byId].filter((t) => {
|
|
8124
|
+
if (seen.has(t.id))
|
|
8125
|
+
return false;
|
|
8126
|
+
seen.add(t.id);
|
|
8127
|
+
return true;
|
|
8128
|
+
});
|
|
8110
8129
|
const pending = myTasks.filter((t) => t.status === "pending");
|
|
8111
8130
|
const inProgress = myTasks.filter((t) => t.status === "in_progress");
|
|
8112
8131
|
const completed = myTasks.filter((t) => t.status === "completed");
|
package/dist/server/index.js
CHANGED
|
@@ -2855,6 +2855,19 @@ data: ${JSON.stringify({ type: "connected", agent_id: agentId, timestamp: new Da
|
|
|
2855
2855
|
return json({ error: e instanceof Error ? e.message : "Failed to start task" }, 500, port);
|
|
2856
2856
|
}
|
|
2857
2857
|
}
|
|
2858
|
+
const failMatch = path.match(/^\/api\/tasks\/([^/]+)\/fail$/);
|
|
2859
|
+
if (failMatch && method === "POST") {
|
|
2860
|
+
const id = failMatch[1];
|
|
2861
|
+
try {
|
|
2862
|
+
const body = await req.json().catch(() => ({}));
|
|
2863
|
+
const { failTask: failTask2 } = await Promise.resolve().then(() => (init_tasks(), exports_tasks));
|
|
2864
|
+
const result = failTask2(id, body.agent_id, body.reason, { retry: body.retry, error_code: body.error_code });
|
|
2865
|
+
broadcastEvent({ type: "task", task_id: id, action: "failed", agent_id: body.agent_id || null });
|
|
2866
|
+
return json({ task: taskToSummary(result.task), retry_task: result.retryTask ? taskToSummary(result.retryTask) : null }, 200, port);
|
|
2867
|
+
} catch (e) {
|
|
2868
|
+
return json({ error: e instanceof Error ? e.message : "Failed to fail task" }, 500, port);
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2858
2871
|
const completeMatch = path.match(/^\/api\/tasks\/([^/]+)\/complete$/);
|
|
2859
2872
|
if (completeMatch && method === "POST") {
|
|
2860
2873
|
const id = completeMatch[1];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/server/serve.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAiHH,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/server/serve.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAiHH,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4wB1G"}
|