@hasna/todos 0.7.0 → 0.8.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/dist/cli/index.js +95 -65
- package/dist/index.js +76 -47
- package/dist/mcp/index.js +81 -52
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2966,7 +2966,7 @@ var init_search = __esm(() => {
|
|
|
2966
2966
|
});
|
|
2967
2967
|
|
|
2968
2968
|
// src/lib/sync-utils.ts
|
|
2969
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, readdirSync
|
|
2969
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
2970
2970
|
import { join as join2 } from "path";
|
|
2971
2971
|
function ensureDir2(dir) {
|
|
2972
2972
|
if (!existsSync2(dir))
|
|
@@ -2975,7 +2975,7 @@ function ensureDir2(dir) {
|
|
|
2975
2975
|
function listJsonFiles(dir) {
|
|
2976
2976
|
if (!existsSync2(dir))
|
|
2977
2977
|
return [];
|
|
2978
|
-
return
|
|
2978
|
+
return readdirSync(dir).filter((f) => f.endsWith(".json"));
|
|
2979
2979
|
}
|
|
2980
2980
|
function readJsonFile(path) {
|
|
2981
2981
|
try {
|
|
@@ -3021,17 +3021,64 @@ var init_sync_utils = __esm(() => {
|
|
|
3021
3021
|
HOME = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
3022
3022
|
});
|
|
3023
3023
|
|
|
3024
|
-
// src/lib/
|
|
3024
|
+
// src/lib/config.ts
|
|
3025
3025
|
import { existsSync as existsSync3 } from "fs";
|
|
3026
3026
|
import { join as join3 } from "path";
|
|
3027
|
+
function normalizeAgent(agent) {
|
|
3028
|
+
return agent.trim().toLowerCase();
|
|
3029
|
+
}
|
|
3030
|
+
function loadConfig() {
|
|
3031
|
+
if (cached)
|
|
3032
|
+
return cached;
|
|
3033
|
+
if (!existsSync3(CONFIG_PATH)) {
|
|
3034
|
+
cached = {};
|
|
3035
|
+
return cached;
|
|
3036
|
+
}
|
|
3037
|
+
const config = readJsonFile(CONFIG_PATH) || {};
|
|
3038
|
+
if (typeof config.sync_agents === "string") {
|
|
3039
|
+
config.sync_agents = config.sync_agents.split(",").map((a) => a.trim()).filter(Boolean);
|
|
3040
|
+
}
|
|
3041
|
+
cached = config;
|
|
3042
|
+
return cached;
|
|
3043
|
+
}
|
|
3044
|
+
function getSyncAgentsFromConfig() {
|
|
3045
|
+
const config = loadConfig();
|
|
3046
|
+
const agents = config.sync_agents;
|
|
3047
|
+
if (Array.isArray(agents) && agents.length > 0)
|
|
3048
|
+
return agents.map(normalizeAgent);
|
|
3049
|
+
return null;
|
|
3050
|
+
}
|
|
3051
|
+
function getAgentTaskListId(agent) {
|
|
3052
|
+
const config = loadConfig();
|
|
3053
|
+
const key = normalizeAgent(agent);
|
|
3054
|
+
return config.agents?.[key]?.task_list_id || config.task_list_id || null;
|
|
3055
|
+
}
|
|
3056
|
+
function getAgentTasksDir(agent) {
|
|
3057
|
+
const config = loadConfig();
|
|
3058
|
+
const key = normalizeAgent(agent);
|
|
3059
|
+
return config.agents?.[key]?.tasks_dir || config.agent_tasks_dir || null;
|
|
3060
|
+
}
|
|
3061
|
+
function getTaskPrefixConfig() {
|
|
3062
|
+
const config = loadConfig();
|
|
3063
|
+
return config.task_prefix || null;
|
|
3064
|
+
}
|
|
3065
|
+
var CONFIG_PATH, cached = null;
|
|
3066
|
+
var init_config = __esm(() => {
|
|
3067
|
+
init_sync_utils();
|
|
3068
|
+
CONFIG_PATH = join3(HOME, ".todos", "config.json");
|
|
3069
|
+
});
|
|
3070
|
+
|
|
3071
|
+
// src/lib/claude-tasks.ts
|
|
3072
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, readdirSync as readdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
3073
|
+
import { join as join4 } from "path";
|
|
3027
3074
|
function getTaskListDir(taskListId) {
|
|
3028
|
-
return
|
|
3075
|
+
return join4(HOME, ".claude", "tasks", taskListId);
|
|
3029
3076
|
}
|
|
3030
3077
|
function readClaudeTask(dir, filename) {
|
|
3031
|
-
return readJsonFile(
|
|
3078
|
+
return readJsonFile(join4(dir, filename));
|
|
3032
3079
|
}
|
|
3033
3080
|
function writeClaudeTask(dir, task) {
|
|
3034
|
-
writeJsonFile(
|
|
3081
|
+
writeJsonFile(join4(dir, `${task.id}.json`), task);
|
|
3035
3082
|
}
|
|
3036
3083
|
function toClaudeStatus(status) {
|
|
3037
3084
|
if (status === "pending" || status === "in_progress" || status === "completed") {
|
|
@@ -3042,6 +3089,20 @@ function toClaudeStatus(status) {
|
|
|
3042
3089
|
function toSqliteStatus(status) {
|
|
3043
3090
|
return status;
|
|
3044
3091
|
}
|
|
3092
|
+
function readPrefixCounter(dir) {
|
|
3093
|
+
const path = join4(dir, ".prefix-counter");
|
|
3094
|
+
if (!existsSync4(path))
|
|
3095
|
+
return 0;
|
|
3096
|
+
const val = parseInt(readFileSync2(path, "utf-8").trim(), 10);
|
|
3097
|
+
return isNaN(val) ? 0 : val;
|
|
3098
|
+
}
|
|
3099
|
+
function writePrefixCounter(dir, value) {
|
|
3100
|
+
writeFileSync2(join4(dir, ".prefix-counter"), String(value));
|
|
3101
|
+
}
|
|
3102
|
+
function formatPrefixedSubject(title, prefix, counter) {
|
|
3103
|
+
const padded = String(counter).padStart(5, "0");
|
|
3104
|
+
return `${prefix}-${padded}: ${title}`;
|
|
3105
|
+
}
|
|
3045
3106
|
function taskToClaudeTask(task, claudeTaskId, existingMeta) {
|
|
3046
3107
|
return {
|
|
3047
3108
|
id: claudeTaskId,
|
|
@@ -3063,7 +3124,7 @@ function taskToClaudeTask(task, claudeTaskId, existingMeta) {
|
|
|
3063
3124
|
}
|
|
3064
3125
|
function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
3065
3126
|
const dir = getTaskListDir(taskListId);
|
|
3066
|
-
if (!
|
|
3127
|
+
if (!existsSync4(dir))
|
|
3067
3128
|
ensureDir2(dir);
|
|
3068
3129
|
const filter = {};
|
|
3069
3130
|
if (projectId)
|
|
@@ -3072,7 +3133,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
3072
3133
|
const existingByTodosId = new Map;
|
|
3073
3134
|
const files = listJsonFiles(dir);
|
|
3074
3135
|
for (const f of files) {
|
|
3075
|
-
const path =
|
|
3136
|
+
const path = join4(dir, f);
|
|
3076
3137
|
const ct = readClaudeTask(dir, f);
|
|
3077
3138
|
if (ct?.metadata?.["todos_id"]) {
|
|
3078
3139
|
existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -3082,6 +3143,11 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
3082
3143
|
let pushed = 0;
|
|
3083
3144
|
const errors = [];
|
|
3084
3145
|
const prefer = options.prefer || "remote";
|
|
3146
|
+
const prefixConfig = getTaskPrefixConfig();
|
|
3147
|
+
let prefixCounter = prefixConfig ? readPrefixCounter(dir) : 0;
|
|
3148
|
+
if (prefixConfig?.start_from && prefixCounter < prefixConfig.start_from) {
|
|
3149
|
+
prefixCounter = prefixConfig.start_from - 1;
|
|
3150
|
+
}
|
|
3085
3151
|
for (const task of tasks) {
|
|
3086
3152
|
try {
|
|
3087
3153
|
const existing = existingByTodosId.get(task.id);
|
|
@@ -3131,6 +3197,10 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
3131
3197
|
const claudeId = String(hwm);
|
|
3132
3198
|
hwm++;
|
|
3133
3199
|
const ct = taskToClaudeTask(task, claudeId);
|
|
3200
|
+
if (prefixConfig) {
|
|
3201
|
+
prefixCounter++;
|
|
3202
|
+
ct.subject = formatPrefixedSubject(task.title, prefixConfig.prefix, prefixCounter);
|
|
3203
|
+
}
|
|
3134
3204
|
writeClaudeTask(dir, ct);
|
|
3135
3205
|
const current = getTask(task.id);
|
|
3136
3206
|
if (current) {
|
|
@@ -3144,14 +3214,16 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
3144
3214
|
}
|
|
3145
3215
|
}
|
|
3146
3216
|
writeHighWaterMark(dir, hwm);
|
|
3217
|
+
if (prefixConfig)
|
|
3218
|
+
writePrefixCounter(dir, prefixCounter);
|
|
3147
3219
|
return { pushed, pulled: 0, errors };
|
|
3148
3220
|
}
|
|
3149
3221
|
function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
3150
3222
|
const dir = getTaskListDir(taskListId);
|
|
3151
|
-
if (!
|
|
3223
|
+
if (!existsSync4(dir)) {
|
|
3152
3224
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
3153
3225
|
}
|
|
3154
|
-
const files =
|
|
3226
|
+
const files = readdirSync2(dir).filter((f) => f.endsWith(".json"));
|
|
3155
3227
|
let pulled = 0;
|
|
3156
3228
|
const errors = [];
|
|
3157
3229
|
const prefer = options.prefer || "remote";
|
|
@@ -3168,7 +3240,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
3168
3240
|
}
|
|
3169
3241
|
for (const f of files) {
|
|
3170
3242
|
try {
|
|
3171
|
-
const filePath =
|
|
3243
|
+
const filePath = join4(dir, f);
|
|
3172
3244
|
const ct = readClaudeTask(dir, f);
|
|
3173
3245
|
if (!ct)
|
|
3174
3246
|
continue;
|
|
@@ -3236,52 +3308,10 @@ function syncClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
3236
3308
|
}
|
|
3237
3309
|
var init_claude_tasks = __esm(() => {
|
|
3238
3310
|
init_tasks();
|
|
3311
|
+
init_config();
|
|
3239
3312
|
init_sync_utils();
|
|
3240
3313
|
});
|
|
3241
3314
|
|
|
3242
|
-
// src/lib/config.ts
|
|
3243
|
-
import { existsSync as existsSync4 } from "fs";
|
|
3244
|
-
import { join as join4 } from "path";
|
|
3245
|
-
function normalizeAgent(agent) {
|
|
3246
|
-
return agent.trim().toLowerCase();
|
|
3247
|
-
}
|
|
3248
|
-
function loadConfig() {
|
|
3249
|
-
if (cached)
|
|
3250
|
-
return cached;
|
|
3251
|
-
if (!existsSync4(CONFIG_PATH)) {
|
|
3252
|
-
cached = {};
|
|
3253
|
-
return cached;
|
|
3254
|
-
}
|
|
3255
|
-
const config = readJsonFile(CONFIG_PATH) || {};
|
|
3256
|
-
if (typeof config.sync_agents === "string") {
|
|
3257
|
-
config.sync_agents = config.sync_agents.split(",").map((a) => a.trim()).filter(Boolean);
|
|
3258
|
-
}
|
|
3259
|
-
cached = config;
|
|
3260
|
-
return cached;
|
|
3261
|
-
}
|
|
3262
|
-
function getSyncAgentsFromConfig() {
|
|
3263
|
-
const config = loadConfig();
|
|
3264
|
-
const agents = config.sync_agents;
|
|
3265
|
-
if (Array.isArray(agents) && agents.length > 0)
|
|
3266
|
-
return agents.map(normalizeAgent);
|
|
3267
|
-
return null;
|
|
3268
|
-
}
|
|
3269
|
-
function getAgentTaskListId(agent) {
|
|
3270
|
-
const config = loadConfig();
|
|
3271
|
-
const key = normalizeAgent(agent);
|
|
3272
|
-
return config.agents?.[key]?.task_list_id || config.task_list_id || null;
|
|
3273
|
-
}
|
|
3274
|
-
function getAgentTasksDir(agent) {
|
|
3275
|
-
const config = loadConfig();
|
|
3276
|
-
const key = normalizeAgent(agent);
|
|
3277
|
-
return config.agents?.[key]?.tasks_dir || config.agent_tasks_dir || null;
|
|
3278
|
-
}
|
|
3279
|
-
var CONFIG_PATH, cached = null;
|
|
3280
|
-
var init_config = __esm(() => {
|
|
3281
|
-
init_sync_utils();
|
|
3282
|
-
CONFIG_PATH = join4(HOME, ".todos", "config.json");
|
|
3283
|
-
});
|
|
3284
|
-
|
|
3285
3315
|
// src/lib/agent-tasks.ts
|
|
3286
3316
|
import { existsSync as existsSync5 } from "fs";
|
|
3287
3317
|
import { join as join5 } from "path";
|
|
@@ -8267,7 +8297,7 @@ var init_rate_limit = __esm(() => {
|
|
|
8267
8297
|
});
|
|
8268
8298
|
|
|
8269
8299
|
// src/lib/env.ts
|
|
8270
|
-
import { existsSync as existsSync6, readFileSync as
|
|
8300
|
+
import { existsSync as existsSync6, readFileSync as readFileSync3 } from "fs";
|
|
8271
8301
|
import { join as join6 } from "path";
|
|
8272
8302
|
function loadEnv() {
|
|
8273
8303
|
const paths = [
|
|
@@ -8277,7 +8307,7 @@ function loadEnv() {
|
|
|
8277
8307
|
for (const path of paths) {
|
|
8278
8308
|
if (!existsSync6(path))
|
|
8279
8309
|
continue;
|
|
8280
|
-
const content =
|
|
8310
|
+
const content = readFileSync3(path, "utf-8");
|
|
8281
8311
|
for (const line of content.split(`
|
|
8282
8312
|
`)) {
|
|
8283
8313
|
const trimmed = line.trim();
|
|
@@ -14230,7 +14260,7 @@ __export(exports_serve, {
|
|
|
14230
14260
|
createFetchHandler: () => createFetchHandler
|
|
14231
14261
|
});
|
|
14232
14262
|
import { execSync } from "child_process";
|
|
14233
|
-
import { existsSync as existsSync7, readFileSync as
|
|
14263
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
|
|
14234
14264
|
import { join as join7, dirname as dirname2, extname } from "path";
|
|
14235
14265
|
import { fileURLToPath } from "url";
|
|
14236
14266
|
function resolveDashboardDir() {
|
|
@@ -14268,7 +14298,7 @@ function json(data, status = 200, port) {
|
|
|
14268
14298
|
function getPackageVersion() {
|
|
14269
14299
|
try {
|
|
14270
14300
|
const pkgPath = join7(dirname2(fileURLToPath(import.meta.url)), "..", "..", "package.json");
|
|
14271
|
-
return JSON.parse(
|
|
14301
|
+
return JSON.parse(readFileSync4(pkgPath, "utf-8")).version || "0.0.0";
|
|
14272
14302
|
} catch {
|
|
14273
14303
|
return "0.0.0";
|
|
14274
14304
|
}
|
|
@@ -16186,13 +16216,13 @@ init_sync();
|
|
|
16186
16216
|
init_config();
|
|
16187
16217
|
import chalk from "chalk";
|
|
16188
16218
|
import { execSync as execSync2 } from "child_process";
|
|
16189
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as
|
|
16219
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
16190
16220
|
import { basename, dirname as dirname3, join as join8, resolve as resolve2 } from "path";
|
|
16191
16221
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
16192
16222
|
function getPackageVersion2() {
|
|
16193
16223
|
try {
|
|
16194
16224
|
const pkgPath = join8(dirname3(fileURLToPath2(import.meta.url)), "..", "..", "package.json");
|
|
16195
|
-
return JSON.parse(
|
|
16225
|
+
return JSON.parse(readFileSync5(pkgPath, "utf-8")).version || "0.0.0";
|
|
16196
16226
|
} catch {
|
|
16197
16227
|
return "0.0.0";
|
|
16198
16228
|
}
|
|
@@ -16835,7 +16865,7 @@ esac
|
|
|
16835
16865
|
exit 0
|
|
16836
16866
|
`;
|
|
16837
16867
|
const hookPath = join8(hooksDir, "todos-sync.sh");
|
|
16838
|
-
|
|
16868
|
+
writeFileSync3(hookPath, hookScript);
|
|
16839
16869
|
execSync2(`chmod +x "${hookPath}"`);
|
|
16840
16870
|
console.log(chalk.green(`Hook script created: ${hookPath}`));
|
|
16841
16871
|
const settingsPath = join8(process.cwd(), ".claude", "settings.json");
|
|
@@ -16894,7 +16924,7 @@ function readJsonFile2(path) {
|
|
|
16894
16924
|
if (!existsSync8(path))
|
|
16895
16925
|
return {};
|
|
16896
16926
|
try {
|
|
16897
|
-
return JSON.parse(
|
|
16927
|
+
return JSON.parse(readFileSync5(path, "utf-8"));
|
|
16898
16928
|
} catch {
|
|
16899
16929
|
return {};
|
|
16900
16930
|
}
|
|
@@ -16903,19 +16933,19 @@ function writeJsonFile2(path, data) {
|
|
|
16903
16933
|
const dir = dirname3(path);
|
|
16904
16934
|
if (!existsSync8(dir))
|
|
16905
16935
|
mkdirSync3(dir, { recursive: true });
|
|
16906
|
-
|
|
16936
|
+
writeFileSync3(path, JSON.stringify(data, null, 2) + `
|
|
16907
16937
|
`);
|
|
16908
16938
|
}
|
|
16909
16939
|
function readTomlFile(path) {
|
|
16910
16940
|
if (!existsSync8(path))
|
|
16911
16941
|
return "";
|
|
16912
|
-
return
|
|
16942
|
+
return readFileSync5(path, "utf-8");
|
|
16913
16943
|
}
|
|
16914
16944
|
function writeTomlFile(path, content) {
|
|
16915
16945
|
const dir = dirname3(path);
|
|
16916
16946
|
if (!existsSync8(dir))
|
|
16917
16947
|
mkdirSync3(dir, { recursive: true });
|
|
16918
|
-
|
|
16948
|
+
writeFileSync3(path, content);
|
|
16919
16949
|
}
|
|
16920
16950
|
function registerClaude(binPath, global) {
|
|
16921
16951
|
const configPath = global ? join8(HOME2, ".claude", ".mcp.json") : join8(process.cwd(), ".mcp.json");
|
package/dist/index.js
CHANGED
|
@@ -1008,11 +1008,15 @@ function searchTasks(query, projectId, db) {
|
|
|
1008
1008
|
return rows.map(rowToTask2);
|
|
1009
1009
|
}
|
|
1010
1010
|
// src/lib/claude-tasks.ts
|
|
1011
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, readdirSync as readdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
1012
|
+
import { join as join4 } from "path";
|
|
1013
|
+
|
|
1014
|
+
// src/lib/config.ts
|
|
1011
1015
|
import { existsSync as existsSync3 } from "fs";
|
|
1012
1016
|
import { join as join3 } from "path";
|
|
1013
1017
|
|
|
1014
1018
|
// src/lib/sync-utils.ts
|
|
1015
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, readdirSync
|
|
1019
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
1016
1020
|
import { join as join2 } from "path";
|
|
1017
1021
|
var HOME = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
1018
1022
|
function ensureDir2(dir) {
|
|
@@ -1022,7 +1026,7 @@ function ensureDir2(dir) {
|
|
|
1022
1026
|
function listJsonFiles(dir) {
|
|
1023
1027
|
if (!existsSync2(dir))
|
|
1024
1028
|
return [];
|
|
1025
|
-
return
|
|
1029
|
+
return readdirSync(dir).filter((f) => f.endsWith(".json"));
|
|
1026
1030
|
}
|
|
1027
1031
|
function readJsonFile(path) {
|
|
1028
1032
|
try {
|
|
@@ -1064,15 +1068,52 @@ function appendSyncConflict(metadata, conflict, limit = 5) {
|
|
|
1064
1068
|
return { ...metadata, sync_conflicts: next };
|
|
1065
1069
|
}
|
|
1066
1070
|
|
|
1071
|
+
// src/lib/config.ts
|
|
1072
|
+
var CONFIG_PATH = join3(HOME, ".todos", "config.json");
|
|
1073
|
+
var cached = null;
|
|
1074
|
+
function normalizeAgent(agent) {
|
|
1075
|
+
return agent.trim().toLowerCase();
|
|
1076
|
+
}
|
|
1077
|
+
function loadConfig() {
|
|
1078
|
+
if (cached)
|
|
1079
|
+
return cached;
|
|
1080
|
+
if (!existsSync3(CONFIG_PATH)) {
|
|
1081
|
+
cached = {};
|
|
1082
|
+
return cached;
|
|
1083
|
+
}
|
|
1084
|
+
const config = readJsonFile(CONFIG_PATH) || {};
|
|
1085
|
+
if (typeof config.sync_agents === "string") {
|
|
1086
|
+
config.sync_agents = config.sync_agents.split(",").map((a) => a.trim()).filter(Boolean);
|
|
1087
|
+
}
|
|
1088
|
+
cached = config;
|
|
1089
|
+
return cached;
|
|
1090
|
+
}
|
|
1091
|
+
function getSyncAgentsFromConfig() {
|
|
1092
|
+
const config = loadConfig();
|
|
1093
|
+
const agents = config.sync_agents;
|
|
1094
|
+
if (Array.isArray(agents) && agents.length > 0)
|
|
1095
|
+
return agents.map(normalizeAgent);
|
|
1096
|
+
return null;
|
|
1097
|
+
}
|
|
1098
|
+
function getAgentTasksDir(agent) {
|
|
1099
|
+
const config = loadConfig();
|
|
1100
|
+
const key = normalizeAgent(agent);
|
|
1101
|
+
return config.agents?.[key]?.tasks_dir || config.agent_tasks_dir || null;
|
|
1102
|
+
}
|
|
1103
|
+
function getTaskPrefixConfig() {
|
|
1104
|
+
const config = loadConfig();
|
|
1105
|
+
return config.task_prefix || null;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1067
1108
|
// src/lib/claude-tasks.ts
|
|
1068
1109
|
function getTaskListDir(taskListId) {
|
|
1069
|
-
return
|
|
1110
|
+
return join4(HOME, ".claude", "tasks", taskListId);
|
|
1070
1111
|
}
|
|
1071
1112
|
function readClaudeTask(dir, filename) {
|
|
1072
|
-
return readJsonFile(
|
|
1113
|
+
return readJsonFile(join4(dir, filename));
|
|
1073
1114
|
}
|
|
1074
1115
|
function writeClaudeTask(dir, task) {
|
|
1075
|
-
writeJsonFile(
|
|
1116
|
+
writeJsonFile(join4(dir, `${task.id}.json`), task);
|
|
1076
1117
|
}
|
|
1077
1118
|
function toClaudeStatus(status) {
|
|
1078
1119
|
if (status === "pending" || status === "in_progress" || status === "completed") {
|
|
@@ -1083,6 +1124,20 @@ function toClaudeStatus(status) {
|
|
|
1083
1124
|
function toSqliteStatus(status) {
|
|
1084
1125
|
return status;
|
|
1085
1126
|
}
|
|
1127
|
+
function readPrefixCounter(dir) {
|
|
1128
|
+
const path = join4(dir, ".prefix-counter");
|
|
1129
|
+
if (!existsSync4(path))
|
|
1130
|
+
return 0;
|
|
1131
|
+
const val = parseInt(readFileSync2(path, "utf-8").trim(), 10);
|
|
1132
|
+
return isNaN(val) ? 0 : val;
|
|
1133
|
+
}
|
|
1134
|
+
function writePrefixCounter(dir, value) {
|
|
1135
|
+
writeFileSync2(join4(dir, ".prefix-counter"), String(value));
|
|
1136
|
+
}
|
|
1137
|
+
function formatPrefixedSubject(title, prefix, counter) {
|
|
1138
|
+
const padded = String(counter).padStart(5, "0");
|
|
1139
|
+
return `${prefix}-${padded}: ${title}`;
|
|
1140
|
+
}
|
|
1086
1141
|
function taskToClaudeTask(task, claudeTaskId, existingMeta) {
|
|
1087
1142
|
return {
|
|
1088
1143
|
id: claudeTaskId,
|
|
@@ -1104,7 +1159,7 @@ function taskToClaudeTask(task, claudeTaskId, existingMeta) {
|
|
|
1104
1159
|
}
|
|
1105
1160
|
function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
1106
1161
|
const dir = getTaskListDir(taskListId);
|
|
1107
|
-
if (!
|
|
1162
|
+
if (!existsSync4(dir))
|
|
1108
1163
|
ensureDir2(dir);
|
|
1109
1164
|
const filter = {};
|
|
1110
1165
|
if (projectId)
|
|
@@ -1113,7 +1168,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
1113
1168
|
const existingByTodosId = new Map;
|
|
1114
1169
|
const files = listJsonFiles(dir);
|
|
1115
1170
|
for (const f of files) {
|
|
1116
|
-
const path =
|
|
1171
|
+
const path = join4(dir, f);
|
|
1117
1172
|
const ct = readClaudeTask(dir, f);
|
|
1118
1173
|
if (ct?.metadata?.["todos_id"]) {
|
|
1119
1174
|
existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -1123,6 +1178,11 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
1123
1178
|
let pushed = 0;
|
|
1124
1179
|
const errors = [];
|
|
1125
1180
|
const prefer = options.prefer || "remote";
|
|
1181
|
+
const prefixConfig = getTaskPrefixConfig();
|
|
1182
|
+
let prefixCounter = prefixConfig ? readPrefixCounter(dir) : 0;
|
|
1183
|
+
if (prefixConfig?.start_from && prefixCounter < prefixConfig.start_from) {
|
|
1184
|
+
prefixCounter = prefixConfig.start_from - 1;
|
|
1185
|
+
}
|
|
1126
1186
|
for (const task of tasks) {
|
|
1127
1187
|
try {
|
|
1128
1188
|
const existing = existingByTodosId.get(task.id);
|
|
@@ -1172,6 +1232,10 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
1172
1232
|
const claudeId = String(hwm);
|
|
1173
1233
|
hwm++;
|
|
1174
1234
|
const ct = taskToClaudeTask(task, claudeId);
|
|
1235
|
+
if (prefixConfig) {
|
|
1236
|
+
prefixCounter++;
|
|
1237
|
+
ct.subject = formatPrefixedSubject(task.title, prefixConfig.prefix, prefixCounter);
|
|
1238
|
+
}
|
|
1175
1239
|
writeClaudeTask(dir, ct);
|
|
1176
1240
|
const current = getTask(task.id);
|
|
1177
1241
|
if (current) {
|
|
@@ -1185,14 +1249,16 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
1185
1249
|
}
|
|
1186
1250
|
}
|
|
1187
1251
|
writeHighWaterMark(dir, hwm);
|
|
1252
|
+
if (prefixConfig)
|
|
1253
|
+
writePrefixCounter(dir, prefixCounter);
|
|
1188
1254
|
return { pushed, pulled: 0, errors };
|
|
1189
1255
|
}
|
|
1190
1256
|
function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
1191
1257
|
const dir = getTaskListDir(taskListId);
|
|
1192
|
-
if (!
|
|
1258
|
+
if (!existsSync4(dir)) {
|
|
1193
1259
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
1194
1260
|
}
|
|
1195
|
-
const files =
|
|
1261
|
+
const files = readdirSync2(dir).filter((f) => f.endsWith(".json"));
|
|
1196
1262
|
let pulled = 0;
|
|
1197
1263
|
const errors = [];
|
|
1198
1264
|
const prefer = options.prefer || "remote";
|
|
@@ -1209,7 +1275,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
1209
1275
|
}
|
|
1210
1276
|
for (const f of files) {
|
|
1211
1277
|
try {
|
|
1212
|
-
const filePath =
|
|
1278
|
+
const filePath = join4(dir, f);
|
|
1213
1279
|
const ct = readClaudeTask(dir, f);
|
|
1214
1280
|
if (!ct)
|
|
1215
1281
|
continue;
|
|
@@ -1279,43 +1345,6 @@ function syncClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
1279
1345
|
// src/lib/agent-tasks.ts
|
|
1280
1346
|
import { existsSync as existsSync5 } from "fs";
|
|
1281
1347
|
import { join as join5 } from "path";
|
|
1282
|
-
|
|
1283
|
-
// src/lib/config.ts
|
|
1284
|
-
import { existsSync as existsSync4 } from "fs";
|
|
1285
|
-
import { join as join4 } from "path";
|
|
1286
|
-
var CONFIG_PATH = join4(HOME, ".todos", "config.json");
|
|
1287
|
-
var cached = null;
|
|
1288
|
-
function normalizeAgent(agent) {
|
|
1289
|
-
return agent.trim().toLowerCase();
|
|
1290
|
-
}
|
|
1291
|
-
function loadConfig() {
|
|
1292
|
-
if (cached)
|
|
1293
|
-
return cached;
|
|
1294
|
-
if (!existsSync4(CONFIG_PATH)) {
|
|
1295
|
-
cached = {};
|
|
1296
|
-
return cached;
|
|
1297
|
-
}
|
|
1298
|
-
const config = readJsonFile(CONFIG_PATH) || {};
|
|
1299
|
-
if (typeof config.sync_agents === "string") {
|
|
1300
|
-
config.sync_agents = config.sync_agents.split(",").map((a) => a.trim()).filter(Boolean);
|
|
1301
|
-
}
|
|
1302
|
-
cached = config;
|
|
1303
|
-
return cached;
|
|
1304
|
-
}
|
|
1305
|
-
function getSyncAgentsFromConfig() {
|
|
1306
|
-
const config = loadConfig();
|
|
1307
|
-
const agents = config.sync_agents;
|
|
1308
|
-
if (Array.isArray(agents) && agents.length > 0)
|
|
1309
|
-
return agents.map(normalizeAgent);
|
|
1310
|
-
return null;
|
|
1311
|
-
}
|
|
1312
|
-
function getAgentTasksDir(agent) {
|
|
1313
|
-
const config = loadConfig();
|
|
1314
|
-
const key = normalizeAgent(agent);
|
|
1315
|
-
return config.agents?.[key]?.tasks_dir || config.agent_tasks_dir || null;
|
|
1316
|
-
}
|
|
1317
|
-
|
|
1318
|
-
// src/lib/agent-tasks.ts
|
|
1319
1348
|
function agentBaseDir(agent) {
|
|
1320
1349
|
const key = `TODOS_${agent.toUpperCase()}_TASKS_DIR`;
|
|
1321
1350
|
return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join5(HOME, ".todos", "agents");
|
package/dist/mcp/index.js
CHANGED
|
@@ -4818,11 +4818,15 @@ function searchTasks(query, projectId, db) {
|
|
|
4818
4818
|
}
|
|
4819
4819
|
|
|
4820
4820
|
// src/lib/claude-tasks.ts
|
|
4821
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, readdirSync as readdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
4822
|
+
import { join as join4 } from "path";
|
|
4823
|
+
|
|
4824
|
+
// src/lib/config.ts
|
|
4821
4825
|
import { existsSync as existsSync3 } from "fs";
|
|
4822
4826
|
import { join as join3 } from "path";
|
|
4823
4827
|
|
|
4824
4828
|
// src/lib/sync-utils.ts
|
|
4825
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, readdirSync
|
|
4829
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
4826
4830
|
import { join as join2 } from "path";
|
|
4827
4831
|
var HOME = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
4828
4832
|
function ensureDir2(dir) {
|
|
@@ -4832,7 +4836,7 @@ function ensureDir2(dir) {
|
|
|
4832
4836
|
function listJsonFiles(dir) {
|
|
4833
4837
|
if (!existsSync2(dir))
|
|
4834
4838
|
return [];
|
|
4835
|
-
return
|
|
4839
|
+
return readdirSync(dir).filter((f) => f.endsWith(".json"));
|
|
4836
4840
|
}
|
|
4837
4841
|
function readJsonFile(path) {
|
|
4838
4842
|
try {
|
|
@@ -4874,15 +4878,57 @@ function appendSyncConflict(metadata, conflict, limit = 5) {
|
|
|
4874
4878
|
return { ...metadata, sync_conflicts: next };
|
|
4875
4879
|
}
|
|
4876
4880
|
|
|
4881
|
+
// src/lib/config.ts
|
|
4882
|
+
var CONFIG_PATH = join3(HOME, ".todos", "config.json");
|
|
4883
|
+
var cached = null;
|
|
4884
|
+
function normalizeAgent(agent) {
|
|
4885
|
+
return agent.trim().toLowerCase();
|
|
4886
|
+
}
|
|
4887
|
+
function loadConfig() {
|
|
4888
|
+
if (cached)
|
|
4889
|
+
return cached;
|
|
4890
|
+
if (!existsSync3(CONFIG_PATH)) {
|
|
4891
|
+
cached = {};
|
|
4892
|
+
return cached;
|
|
4893
|
+
}
|
|
4894
|
+
const config = readJsonFile(CONFIG_PATH) || {};
|
|
4895
|
+
if (typeof config.sync_agents === "string") {
|
|
4896
|
+
config.sync_agents = config.sync_agents.split(",").map((a) => a.trim()).filter(Boolean);
|
|
4897
|
+
}
|
|
4898
|
+
cached = config;
|
|
4899
|
+
return cached;
|
|
4900
|
+
}
|
|
4901
|
+
function getSyncAgentsFromConfig() {
|
|
4902
|
+
const config = loadConfig();
|
|
4903
|
+
const agents = config.sync_agents;
|
|
4904
|
+
if (Array.isArray(agents) && agents.length > 0)
|
|
4905
|
+
return agents.map(normalizeAgent);
|
|
4906
|
+
return null;
|
|
4907
|
+
}
|
|
4908
|
+
function getAgentTaskListId(agent) {
|
|
4909
|
+
const config = loadConfig();
|
|
4910
|
+
const key = normalizeAgent(agent);
|
|
4911
|
+
return config.agents?.[key]?.task_list_id || config.task_list_id || null;
|
|
4912
|
+
}
|
|
4913
|
+
function getAgentTasksDir(agent) {
|
|
4914
|
+
const config = loadConfig();
|
|
4915
|
+
const key = normalizeAgent(agent);
|
|
4916
|
+
return config.agents?.[key]?.tasks_dir || config.agent_tasks_dir || null;
|
|
4917
|
+
}
|
|
4918
|
+
function getTaskPrefixConfig() {
|
|
4919
|
+
const config = loadConfig();
|
|
4920
|
+
return config.task_prefix || null;
|
|
4921
|
+
}
|
|
4922
|
+
|
|
4877
4923
|
// src/lib/claude-tasks.ts
|
|
4878
4924
|
function getTaskListDir(taskListId) {
|
|
4879
|
-
return
|
|
4925
|
+
return join4(HOME, ".claude", "tasks", taskListId);
|
|
4880
4926
|
}
|
|
4881
4927
|
function readClaudeTask(dir, filename) {
|
|
4882
|
-
return readJsonFile(
|
|
4928
|
+
return readJsonFile(join4(dir, filename));
|
|
4883
4929
|
}
|
|
4884
4930
|
function writeClaudeTask(dir, task) {
|
|
4885
|
-
writeJsonFile(
|
|
4931
|
+
writeJsonFile(join4(dir, `${task.id}.json`), task);
|
|
4886
4932
|
}
|
|
4887
4933
|
function toClaudeStatus(status) {
|
|
4888
4934
|
if (status === "pending" || status === "in_progress" || status === "completed") {
|
|
@@ -4893,6 +4939,20 @@ function toClaudeStatus(status) {
|
|
|
4893
4939
|
function toSqliteStatus(status) {
|
|
4894
4940
|
return status;
|
|
4895
4941
|
}
|
|
4942
|
+
function readPrefixCounter(dir) {
|
|
4943
|
+
const path = join4(dir, ".prefix-counter");
|
|
4944
|
+
if (!existsSync4(path))
|
|
4945
|
+
return 0;
|
|
4946
|
+
const val = parseInt(readFileSync2(path, "utf-8").trim(), 10);
|
|
4947
|
+
return isNaN(val) ? 0 : val;
|
|
4948
|
+
}
|
|
4949
|
+
function writePrefixCounter(dir, value) {
|
|
4950
|
+
writeFileSync2(join4(dir, ".prefix-counter"), String(value));
|
|
4951
|
+
}
|
|
4952
|
+
function formatPrefixedSubject(title, prefix, counter) {
|
|
4953
|
+
const padded = String(counter).padStart(5, "0");
|
|
4954
|
+
return `${prefix}-${padded}: ${title}`;
|
|
4955
|
+
}
|
|
4896
4956
|
function taskToClaudeTask(task, claudeTaskId, existingMeta) {
|
|
4897
4957
|
return {
|
|
4898
4958
|
id: claudeTaskId,
|
|
@@ -4914,7 +4974,7 @@ function taskToClaudeTask(task, claudeTaskId, existingMeta) {
|
|
|
4914
4974
|
}
|
|
4915
4975
|
function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
4916
4976
|
const dir = getTaskListDir(taskListId);
|
|
4917
|
-
if (!
|
|
4977
|
+
if (!existsSync4(dir))
|
|
4918
4978
|
ensureDir2(dir);
|
|
4919
4979
|
const filter = {};
|
|
4920
4980
|
if (projectId)
|
|
@@ -4923,7 +4983,7 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
4923
4983
|
const existingByTodosId = new Map;
|
|
4924
4984
|
const files = listJsonFiles(dir);
|
|
4925
4985
|
for (const f of files) {
|
|
4926
|
-
const path =
|
|
4986
|
+
const path = join4(dir, f);
|
|
4927
4987
|
const ct = readClaudeTask(dir, f);
|
|
4928
4988
|
if (ct?.metadata?.["todos_id"]) {
|
|
4929
4989
|
existingByTodosId.set(ct.metadata["todos_id"], { task: ct, mtimeMs: getFileMtimeMs(path) });
|
|
@@ -4933,6 +4993,11 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
4933
4993
|
let pushed = 0;
|
|
4934
4994
|
const errors2 = [];
|
|
4935
4995
|
const prefer = options.prefer || "remote";
|
|
4996
|
+
const prefixConfig = getTaskPrefixConfig();
|
|
4997
|
+
let prefixCounter = prefixConfig ? readPrefixCounter(dir) : 0;
|
|
4998
|
+
if (prefixConfig?.start_from && prefixCounter < prefixConfig.start_from) {
|
|
4999
|
+
prefixCounter = prefixConfig.start_from - 1;
|
|
5000
|
+
}
|
|
4936
5001
|
for (const task of tasks) {
|
|
4937
5002
|
try {
|
|
4938
5003
|
const existing = existingByTodosId.get(task.id);
|
|
@@ -4982,6 +5047,10 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
4982
5047
|
const claudeId = String(hwm);
|
|
4983
5048
|
hwm++;
|
|
4984
5049
|
const ct = taskToClaudeTask(task, claudeId);
|
|
5050
|
+
if (prefixConfig) {
|
|
5051
|
+
prefixCounter++;
|
|
5052
|
+
ct.subject = formatPrefixedSubject(task.title, prefixConfig.prefix, prefixCounter);
|
|
5053
|
+
}
|
|
4985
5054
|
writeClaudeTask(dir, ct);
|
|
4986
5055
|
const current = getTask(task.id);
|
|
4987
5056
|
if (current) {
|
|
@@ -4995,14 +5064,16 @@ function pushToClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
4995
5064
|
}
|
|
4996
5065
|
}
|
|
4997
5066
|
writeHighWaterMark(dir, hwm);
|
|
5067
|
+
if (prefixConfig)
|
|
5068
|
+
writePrefixCounter(dir, prefixCounter);
|
|
4998
5069
|
return { pushed, pulled: 0, errors: errors2 };
|
|
4999
5070
|
}
|
|
5000
5071
|
function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
5001
5072
|
const dir = getTaskListDir(taskListId);
|
|
5002
|
-
if (!
|
|
5073
|
+
if (!existsSync4(dir)) {
|
|
5003
5074
|
return { pushed: 0, pulled: 0, errors: [`Task list directory not found: ${dir}`] };
|
|
5004
5075
|
}
|
|
5005
|
-
const files =
|
|
5076
|
+
const files = readdirSync2(dir).filter((f) => f.endsWith(".json"));
|
|
5006
5077
|
let pulled = 0;
|
|
5007
5078
|
const errors2 = [];
|
|
5008
5079
|
const prefer = options.prefer || "remote";
|
|
@@ -5019,7 +5090,7 @@ function pullFromClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
5019
5090
|
}
|
|
5020
5091
|
for (const f of files) {
|
|
5021
5092
|
try {
|
|
5022
|
-
const filePath =
|
|
5093
|
+
const filePath = join4(dir, f);
|
|
5023
5094
|
const ct = readClaudeTask(dir, f);
|
|
5024
5095
|
if (!ct)
|
|
5025
5096
|
continue;
|
|
@@ -5089,48 +5160,6 @@ function syncClaudeTaskList(taskListId, projectId, options = {}) {
|
|
|
5089
5160
|
// src/lib/agent-tasks.ts
|
|
5090
5161
|
import { existsSync as existsSync5 } from "fs";
|
|
5091
5162
|
import { join as join5 } from "path";
|
|
5092
|
-
|
|
5093
|
-
// src/lib/config.ts
|
|
5094
|
-
import { existsSync as existsSync4 } from "fs";
|
|
5095
|
-
import { join as join4 } from "path";
|
|
5096
|
-
var CONFIG_PATH = join4(HOME, ".todos", "config.json");
|
|
5097
|
-
var cached = null;
|
|
5098
|
-
function normalizeAgent(agent) {
|
|
5099
|
-
return agent.trim().toLowerCase();
|
|
5100
|
-
}
|
|
5101
|
-
function loadConfig() {
|
|
5102
|
-
if (cached)
|
|
5103
|
-
return cached;
|
|
5104
|
-
if (!existsSync4(CONFIG_PATH)) {
|
|
5105
|
-
cached = {};
|
|
5106
|
-
return cached;
|
|
5107
|
-
}
|
|
5108
|
-
const config = readJsonFile(CONFIG_PATH) || {};
|
|
5109
|
-
if (typeof config.sync_agents === "string") {
|
|
5110
|
-
config.sync_agents = config.sync_agents.split(",").map((a) => a.trim()).filter(Boolean);
|
|
5111
|
-
}
|
|
5112
|
-
cached = config;
|
|
5113
|
-
return cached;
|
|
5114
|
-
}
|
|
5115
|
-
function getSyncAgentsFromConfig() {
|
|
5116
|
-
const config = loadConfig();
|
|
5117
|
-
const agents = config.sync_agents;
|
|
5118
|
-
if (Array.isArray(agents) && agents.length > 0)
|
|
5119
|
-
return agents.map(normalizeAgent);
|
|
5120
|
-
return null;
|
|
5121
|
-
}
|
|
5122
|
-
function getAgentTaskListId(agent) {
|
|
5123
|
-
const config = loadConfig();
|
|
5124
|
-
const key = normalizeAgent(agent);
|
|
5125
|
-
return config.agents?.[key]?.task_list_id || config.task_list_id || null;
|
|
5126
|
-
}
|
|
5127
|
-
function getAgentTasksDir(agent) {
|
|
5128
|
-
const config = loadConfig();
|
|
5129
|
-
const key = normalizeAgent(agent);
|
|
5130
|
-
return config.agents?.[key]?.tasks_dir || config.agent_tasks_dir || null;
|
|
5131
|
-
}
|
|
5132
|
-
|
|
5133
|
-
// src/lib/agent-tasks.ts
|
|
5134
5163
|
function agentBaseDir(agent) {
|
|
5135
5164
|
const key = `TODOS_${agent.toUpperCase()}_TASKS_DIR`;
|
|
5136
5165
|
return process.env[key] || getAgentTasksDir(agent) || process.env["TODOS_AGENT_TASKS_DIR"] || join5(HOME, ".todos", "agents");
|