@fukuchang/taskchute-mcp 0.1.2 → 0.2.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/CHANGELOG.md +209 -1
- package/README.md +45 -9
- package/dist/index.js +1802 -91
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1,13 +1,80 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
3
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
|
+
import { Entry } from '@napi-rs/keyring';
|
|
4
5
|
import { argon2id } from 'hash-wasm';
|
|
5
6
|
import '@scure/bip39';
|
|
6
7
|
import '@scure/bip39/wordlists/english.js';
|
|
7
8
|
import { createClient } from '@supabase/supabase-js';
|
|
8
|
-
import { Entry } from '@napi-rs/keyring';
|
|
9
9
|
import { z } from 'zod';
|
|
10
10
|
|
|
11
|
+
// ../node-shared/src/app-context-error.ts
|
|
12
|
+
var AppContextError = class extends Error {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "AppContextError";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// ../node-shared/src/config.ts
|
|
20
|
+
var ENV_URL = "TASKCHUTE_SUPABASE_URL";
|
|
21
|
+
var ENV_KEY = "TASKCHUTE_SUPABASE_PUBLISHABLE_KEY";
|
|
22
|
+
function readSupabaseConfigFromEnv() {
|
|
23
|
+
const url = process.env.TASKCHUTE_SUPABASE_URL;
|
|
24
|
+
const publishableKey = process.env.TASKCHUTE_SUPABASE_PUBLISHABLE_KEY;
|
|
25
|
+
if (!url || !publishableKey) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`Supabase \u306E\u74B0\u5883\u5909\u6570\u304C\u898B\u3064\u304B\u3089\u306A\u3044\u3002${ENV_URL} \u3068 ${ENV_KEY} \u3092\u8A2D\u5B9A\u3057\u3066\u306D\u301C`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
return { url, publishableKey };
|
|
31
|
+
}
|
|
32
|
+
var KEYRING_SERVICE = "taskchute-cli";
|
|
33
|
+
var KEYRING_ACCOUNT = "passphrase";
|
|
34
|
+
var KeyringPassphraseStore = class {
|
|
35
|
+
get() {
|
|
36
|
+
try {
|
|
37
|
+
const entry = new Entry(KEYRING_SERVICE, KEYRING_ACCOUNT);
|
|
38
|
+
return entry.getPassword();
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
set(passphrase) {
|
|
44
|
+
const entry = new Entry(KEYRING_SERVICE, KEYRING_ACCOUNT);
|
|
45
|
+
entry.setPassword(passphrase);
|
|
46
|
+
}
|
|
47
|
+
clear() {
|
|
48
|
+
try {
|
|
49
|
+
const entry = new Entry(KEYRING_SERVICE, KEYRING_ACCOUNT);
|
|
50
|
+
entry.deletePassword();
|
|
51
|
+
} catch {
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
var KEYRING_SERVICE2 = "taskchute-cli";
|
|
56
|
+
var KeyringSessionStore = class {
|
|
57
|
+
getItem(key) {
|
|
58
|
+
try {
|
|
59
|
+
const entry = new Entry(KEYRING_SERVICE2, key);
|
|
60
|
+
return entry.getPassword();
|
|
61
|
+
} catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
setItem(key, value) {
|
|
66
|
+
const entry = new Entry(KEYRING_SERVICE2, key);
|
|
67
|
+
entry.setPassword(value);
|
|
68
|
+
}
|
|
69
|
+
removeItem(key) {
|
|
70
|
+
try {
|
|
71
|
+
const entry = new Entry(KEYRING_SERVICE2, key);
|
|
72
|
+
entry.deletePassword();
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
11
78
|
// ../crypto/src/bytes.ts
|
|
12
79
|
function allocBytes(length) {
|
|
13
80
|
return new Uint8Array(new ArrayBuffer(length));
|
|
@@ -668,6 +735,39 @@ var SupabaseProjectRepository = class {
|
|
|
668
735
|
}
|
|
669
736
|
};
|
|
670
737
|
|
|
738
|
+
// ../infra-supabase/src/supabase-routine-expansion-repository.ts
|
|
739
|
+
function rowToExpansion(row) {
|
|
740
|
+
return {
|
|
741
|
+
routineId: row.routine_id,
|
|
742
|
+
date: row.date,
|
|
743
|
+
status: row.status
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
var SupabaseRoutineExpansionRepository = class {
|
|
747
|
+
supabase;
|
|
748
|
+
constructor(supabase) {
|
|
749
|
+
this.supabase = supabase;
|
|
750
|
+
}
|
|
751
|
+
async findByDate(date) {
|
|
752
|
+
const { data, error } = await this.supabase.from("routine_expansions").select("*").eq("date", date);
|
|
753
|
+
if (error) throw error;
|
|
754
|
+
return data.map(rowToExpansion);
|
|
755
|
+
}
|
|
756
|
+
async recordExpanded(routineId, date) {
|
|
757
|
+
const userId = await getCurrentUserId(this.supabase);
|
|
758
|
+
const { error } = await this.supabase.from("routine_expansions").upsert(
|
|
759
|
+
{
|
|
760
|
+
user_id: userId,
|
|
761
|
+
routine_id: routineId,
|
|
762
|
+
date,
|
|
763
|
+
status: "expanded"
|
|
764
|
+
},
|
|
765
|
+
{ onConflict: "routine_id,date", ignoreDuplicates: true }
|
|
766
|
+
);
|
|
767
|
+
if (error) throw error;
|
|
768
|
+
}
|
|
769
|
+
};
|
|
770
|
+
|
|
671
771
|
// ../infra-supabase/src/supabase-routine-repository.ts
|
|
672
772
|
async function rowToRoutine(row, cryptoSession) {
|
|
673
773
|
const [title, description] = await Promise.all([
|
|
@@ -705,7 +805,6 @@ async function rowToRoutine(row, cryptoSession) {
|
|
|
705
805
|
}
|
|
706
806
|
if (row.start_date !== null) routine.startDate = row.start_date;
|
|
707
807
|
if (row.end_date !== null) routine.endDate = row.end_date;
|
|
708
|
-
if (row.last_expanded_date !== null) routine.lastExpandedDate = row.last_expanded_date;
|
|
709
808
|
return routine;
|
|
710
809
|
}
|
|
711
810
|
function nonEncryptedFieldsToRow3(input) {
|
|
@@ -727,9 +826,6 @@ function nonEncryptedFieldsToRow3(input) {
|
|
|
727
826
|
if ("autoExpand" in input && input.autoExpand !== void 0) {
|
|
728
827
|
row.auto_expand = input.autoExpand;
|
|
729
828
|
}
|
|
730
|
-
if ("lastExpandedDate" in input) {
|
|
731
|
-
row.last_expanded_date = input.lastExpandedDate ?? null;
|
|
732
|
-
}
|
|
733
829
|
if ("status" in input && input.status !== void 0) row.status = input.status;
|
|
734
830
|
return row;
|
|
735
831
|
}
|
|
@@ -1286,6 +1382,13 @@ var SupabaseTaskRepository = class {
|
|
|
1286
1382
|
const { error } = await this.supabase.from("tasks").delete().eq("id", id);
|
|
1287
1383
|
if (error) throw error;
|
|
1288
1384
|
}
|
|
1385
|
+
async deleteWithRoutineSkip(id, today) {
|
|
1386
|
+
const { error } = await this.supabase.rpc("delete_task_and_skip_routine", {
|
|
1387
|
+
p_task_id: id,
|
|
1388
|
+
p_today: today
|
|
1389
|
+
});
|
|
1390
|
+
if (error) throw error;
|
|
1391
|
+
}
|
|
1289
1392
|
};
|
|
1290
1393
|
|
|
1291
1394
|
// ../infra-supabase/src/supabase-time-block-repository.ts
|
|
@@ -1495,6 +1598,13 @@ function toDateString(date) {
|
|
|
1495
1598
|
const day = String(date.getDate()).padStart(2, "0");
|
|
1496
1599
|
return `${year}-${month}-${day}`;
|
|
1497
1600
|
}
|
|
1601
|
+
function fromDateString(dateString) {
|
|
1602
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(dateString);
|
|
1603
|
+
if (!match || !match[1] || !match[2] || !match[3]) {
|
|
1604
|
+
throw new Error(`Invalid date string: ${dateString}`);
|
|
1605
|
+
}
|
|
1606
|
+
return new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]));
|
|
1607
|
+
}
|
|
1498
1608
|
function todayDateString() {
|
|
1499
1609
|
return toDateString(/* @__PURE__ */ new Date());
|
|
1500
1610
|
}
|
|
@@ -1504,7 +1614,32 @@ function toTimeString(date) {
|
|
|
1504
1614
|
return `${hours}:${minutes}`;
|
|
1505
1615
|
}
|
|
1506
1616
|
|
|
1617
|
+
// ../domain/src/task-utils.ts
|
|
1618
|
+
function sessionDurationSeconds(session) {
|
|
1619
|
+
return (session.finishedAt.getTime() - session.startedAt.getTime()) / 1e3;
|
|
1620
|
+
}
|
|
1621
|
+
function completedSessionsTotalSeconds(task) {
|
|
1622
|
+
return task.sessions.reduce((sum, s) => sum + sessionDurationSeconds(s), 0);
|
|
1623
|
+
}
|
|
1624
|
+
function calculateActualSeconds(task, now = /* @__PURE__ */ new Date()) {
|
|
1625
|
+
const completed = completedSessionsTotalSeconds(task);
|
|
1626
|
+
if (task.currentSession) {
|
|
1627
|
+
return completed + (now.getTime() - task.currentSession.startedAt.getTime()) / 1e3;
|
|
1628
|
+
}
|
|
1629
|
+
return completed;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1507
1632
|
// ../domain/src/task-operations.ts
|
|
1633
|
+
var TIME_RE = /^([01]\d|2[0-3]):([0-5]\d)$/;
|
|
1634
|
+
function parseTimeOnDate(dateString, timeString) {
|
|
1635
|
+
const m = TIME_RE.exec(timeString);
|
|
1636
|
+
if (!m || !m[1] || !m[2]) {
|
|
1637
|
+
throw new Error(`Invalid time string: ${timeString}`);
|
|
1638
|
+
}
|
|
1639
|
+
const base = fromDateString(dateString);
|
|
1640
|
+
base.setHours(Number(m[1]), Number(m[2]), 0, 0);
|
|
1641
|
+
return base;
|
|
1642
|
+
}
|
|
1508
1643
|
async function startTask(repo, taskId) {
|
|
1509
1644
|
const task = await repo.findById(taskId);
|
|
1510
1645
|
if (!task) throw new Error(`Task not found: ${taskId}`);
|
|
@@ -1535,6 +1670,30 @@ async function pauseTask(repo, taskId) {
|
|
|
1535
1670
|
currentSession: void 0
|
|
1536
1671
|
});
|
|
1537
1672
|
}
|
|
1673
|
+
async function skipTask(repo, taskId) {
|
|
1674
|
+
const task = await repo.findById(taskId);
|
|
1675
|
+
if (!task) throw new Error(`Task not found: ${taskId}`);
|
|
1676
|
+
const updates = { status: "skipped" };
|
|
1677
|
+
if (task.currentSession) {
|
|
1678
|
+
updates.sessions = [
|
|
1679
|
+
...task.sessions,
|
|
1680
|
+
{
|
|
1681
|
+
startedAt: task.currentSession.startedAt,
|
|
1682
|
+
finishedAt: /* @__PURE__ */ new Date()
|
|
1683
|
+
}
|
|
1684
|
+
];
|
|
1685
|
+
updates.currentSession = void 0;
|
|
1686
|
+
}
|
|
1687
|
+
return repo.update(taskId, updates);
|
|
1688
|
+
}
|
|
1689
|
+
async function reopenTask(repo, taskId) {
|
|
1690
|
+
const task = await repo.findById(taskId);
|
|
1691
|
+
if (!task) throw new Error(`Task not found: ${taskId}`);
|
|
1692
|
+
if (task.status !== "completed" && task.status !== "skipped") {
|
|
1693
|
+
return task;
|
|
1694
|
+
}
|
|
1695
|
+
return repo.update(taskId, { status: "planned" });
|
|
1696
|
+
}
|
|
1538
1697
|
async function completeTask(repo, taskId) {
|
|
1539
1698
|
const task = await repo.findById(taskId);
|
|
1540
1699
|
if (!task) throw new Error(`Task not found: ${taskId}`);
|
|
@@ -1551,6 +1710,115 @@ async function completeTask(repo, taskId) {
|
|
|
1551
1710
|
}
|
|
1552
1711
|
return repo.update(taskId, updates);
|
|
1553
1712
|
}
|
|
1713
|
+
async function interruptTask(repo, params) {
|
|
1714
|
+
const target = await repo.findById(params.targetTaskId);
|
|
1715
|
+
if (!target) throw new Error(`Task not found: ${params.targetTaskId}`);
|
|
1716
|
+
if (!target.currentSession) {
|
|
1717
|
+
throw new Error(`Target task is not currently running`);
|
|
1718
|
+
}
|
|
1719
|
+
const now = /* @__PURE__ */ new Date();
|
|
1720
|
+
const closedSession = {
|
|
1721
|
+
startedAt: target.currentSession.startedAt,
|
|
1722
|
+
finishedAt: now
|
|
1723
|
+
};
|
|
1724
|
+
const finishedOriginal = await repo.update(target.id, {
|
|
1725
|
+
status: "completed",
|
|
1726
|
+
sessions: [...target.sessions, closedSession],
|
|
1727
|
+
currentSession: void 0
|
|
1728
|
+
});
|
|
1729
|
+
const elapsed = calculateActualSeconds(finishedOriginal);
|
|
1730
|
+
const interruptionStartedAt = /* @__PURE__ */ new Date();
|
|
1731
|
+
const interruption = await repo.create({
|
|
1732
|
+
date: target.date,
|
|
1733
|
+
title: params.interruption.title,
|
|
1734
|
+
description: params.interruption.description,
|
|
1735
|
+
estimatedSeconds: params.interruption.estimatedSeconds,
|
|
1736
|
+
sessions: [],
|
|
1737
|
+
currentSession: { startedAt: interruptionStartedAt },
|
|
1738
|
+
status: "running",
|
|
1739
|
+
orderIndex: target.orderIndex + 1,
|
|
1740
|
+
actualStartTime: toTimeString(interruptionStartedAt),
|
|
1741
|
+
projectId: params.interruption.projectId,
|
|
1742
|
+
contextId: params.interruption.contextId,
|
|
1743
|
+
tagIds: params.interruption.tagIds ?? []
|
|
1744
|
+
});
|
|
1745
|
+
const continuation = await repo.create({
|
|
1746
|
+
date: target.date,
|
|
1747
|
+
title: target.title,
|
|
1748
|
+
description: target.description,
|
|
1749
|
+
estimatedSeconds: Math.max(0, Math.floor(target.estimatedSeconds - elapsed)),
|
|
1750
|
+
sessions: [],
|
|
1751
|
+
status: "planned",
|
|
1752
|
+
orderIndex: target.orderIndex + 2,
|
|
1753
|
+
splitFromTaskId: target.id,
|
|
1754
|
+
projectId: target.projectId,
|
|
1755
|
+
contextId: target.contextId,
|
|
1756
|
+
// continuation は「割り込みが片付いた後にやる残作業」。割り込み発生時刻を
|
|
1757
|
+
// 予定時刻にすることで、(1) interruption と同じ effectiveTime になり、
|
|
1758
|
+
// ソート上 orderIndex で interruption の次に並ぶ、(2) 割り込みが TimeBlock
|
|
1759
|
+
// の境界をまたいだ場合は continuation も新しいブロックに移動する、という
|
|
1760
|
+
// 自然な挙動になる。
|
|
1761
|
+
scheduledStartTime: toTimeString(interruptionStartedAt),
|
|
1762
|
+
tagIds: target.tagIds,
|
|
1763
|
+
isBackground: target.isBackground
|
|
1764
|
+
});
|
|
1765
|
+
return { finishedOriginal, interruption, continuation };
|
|
1766
|
+
}
|
|
1767
|
+
async function addParallelTask(repo, input) {
|
|
1768
|
+
const startImmediately = input.startImmediately ?? true;
|
|
1769
|
+
const existing = await repo.findByDate(input.date);
|
|
1770
|
+
const maxOrder = existing.reduce((max, t) => t.orderIndex > max ? t.orderIndex : max, 0);
|
|
1771
|
+
const startedAt = startImmediately ? /* @__PURE__ */ new Date() : void 0;
|
|
1772
|
+
return repo.create({
|
|
1773
|
+
date: input.date,
|
|
1774
|
+
title: input.title,
|
|
1775
|
+
description: input.description,
|
|
1776
|
+
estimatedSeconds: input.estimatedSeconds,
|
|
1777
|
+
sessions: [],
|
|
1778
|
+
currentSession: startedAt ? { startedAt } : void 0,
|
|
1779
|
+
status: startImmediately ? "running" : "planned",
|
|
1780
|
+
orderIndex: maxOrder + 10,
|
|
1781
|
+
actualStartTime: startedAt ? toTimeString(startedAt) : void 0,
|
|
1782
|
+
projectId: input.projectId,
|
|
1783
|
+
contextId: input.contextId,
|
|
1784
|
+
tagIds: input.tagIds ?? [],
|
|
1785
|
+
isBackground: input.isBackground
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
function buildSetActualTimesPatch(task, input) {
|
|
1789
|
+
const startTime = input.startTime?.trim() ? input.startTime.trim() : null;
|
|
1790
|
+
const endTime = input.endTime?.trim() ? input.endTime.trim() : null;
|
|
1791
|
+
if (startTime === null && endTime === null) {
|
|
1792
|
+
return {
|
|
1793
|
+
status: "planned",
|
|
1794
|
+
currentSession: void 0,
|
|
1795
|
+
sessions: [],
|
|
1796
|
+
actualStartTime: void 0
|
|
1797
|
+
};
|
|
1798
|
+
}
|
|
1799
|
+
if (startTime === null && endTime !== null) {
|
|
1800
|
+
throw new Error("endTime requires startTime");
|
|
1801
|
+
}
|
|
1802
|
+
const startedAt = parseTimeOnDate(task.date, startTime);
|
|
1803
|
+
if (endTime === null) {
|
|
1804
|
+
return {
|
|
1805
|
+
status: "running",
|
|
1806
|
+
currentSession: { startedAt },
|
|
1807
|
+
sessions: [],
|
|
1808
|
+
actualStartTime: startTime
|
|
1809
|
+
};
|
|
1810
|
+
}
|
|
1811
|
+
let finishedAt = parseTimeOnDate(task.date, endTime);
|
|
1812
|
+
if (finishedAt.getTime() < startedAt.getTime()) {
|
|
1813
|
+
finishedAt = new Date(finishedAt.getTime() + 24 * 60 * 60 * 1e3);
|
|
1814
|
+
}
|
|
1815
|
+
return {
|
|
1816
|
+
status: "completed",
|
|
1817
|
+
currentSession: void 0,
|
|
1818
|
+
sessions: [{ startedAt, finishedAt }],
|
|
1819
|
+
actualStartTime: startTime
|
|
1820
|
+
};
|
|
1821
|
+
}
|
|
1554
1822
|
|
|
1555
1823
|
// ../domain/src/task-reorder.ts
|
|
1556
1824
|
function computeNextOrderIndex(existingTasks) {
|
|
@@ -1562,6 +1830,70 @@ function computeNextOrderIndex(existingTasks) {
|
|
|
1562
1830
|
return max + 10;
|
|
1563
1831
|
}
|
|
1564
1832
|
|
|
1833
|
+
// ../domain/src/task-suggest.ts
|
|
1834
|
+
function normalizeForSearch(str) {
|
|
1835
|
+
return str.trim().toLowerCase().replace(
|
|
1836
|
+
/[ぁ-ゖ]/g,
|
|
1837
|
+
(ch) => String.fromCharCode(ch.charCodeAt(0) + 96)
|
|
1838
|
+
);
|
|
1839
|
+
}
|
|
1840
|
+
function fuzzyScore(query, target) {
|
|
1841
|
+
const q = query;
|
|
1842
|
+
const t = target;
|
|
1843
|
+
if (q.length === 0) return 0;
|
|
1844
|
+
if (t.length === 0) return null;
|
|
1845
|
+
let qi = 0;
|
|
1846
|
+
let score = 0;
|
|
1847
|
+
let lastMatchIndex = -2;
|
|
1848
|
+
let consecutiveRun = 0;
|
|
1849
|
+
for (let ti = 0; ti < t.length && qi < q.length; ti++) {
|
|
1850
|
+
if (t[ti] === q[qi]) {
|
|
1851
|
+
if (lastMatchIndex === ti - 1) {
|
|
1852
|
+
consecutiveRun += 1;
|
|
1853
|
+
score += 5 + consecutiveRun * 3;
|
|
1854
|
+
} else {
|
|
1855
|
+
consecutiveRun = 0;
|
|
1856
|
+
score += 2;
|
|
1857
|
+
}
|
|
1858
|
+
if (qi === 0) {
|
|
1859
|
+
score += Math.max(0, 8 - ti);
|
|
1860
|
+
}
|
|
1861
|
+
lastMatchIndex = ti;
|
|
1862
|
+
qi += 1;
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
if (qi < q.length) return null;
|
|
1866
|
+
score -= Math.max(0, t.length - q.length) / 4;
|
|
1867
|
+
return score;
|
|
1868
|
+
}
|
|
1869
|
+
function findSimilarTasks(query, tasks, limit = 5) {
|
|
1870
|
+
const q = normalizeForSearch(query);
|
|
1871
|
+
if (q.length === 0) return [];
|
|
1872
|
+
const bestByTitle = /* @__PURE__ */ new Map();
|
|
1873
|
+
for (const task of tasks) {
|
|
1874
|
+
const titleTrimmed = task.title.trim();
|
|
1875
|
+
if (titleTrimmed.length === 0) continue;
|
|
1876
|
+
const titleNormalized = normalizeForSearch(titleTrimmed);
|
|
1877
|
+
const score = fuzzyScore(q, titleNormalized);
|
|
1878
|
+
if (score === null) continue;
|
|
1879
|
+
const existing = bestByTitle.get(titleNormalized);
|
|
1880
|
+
if (!existing) {
|
|
1881
|
+
bestByTitle.set(titleNormalized, { task, score });
|
|
1882
|
+
continue;
|
|
1883
|
+
}
|
|
1884
|
+
const existingNewer = existing.task.updatedAt.getTime();
|
|
1885
|
+
const candidateNewer = task.updatedAt.getTime();
|
|
1886
|
+
if (candidateNewer > existingNewer) {
|
|
1887
|
+
bestByTitle.set(titleNormalized, { task, score });
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
const sorted = Array.from(bestByTitle.values()).sort((a, b) => {
|
|
1891
|
+
if (b.score !== a.score) return b.score - a.score;
|
|
1892
|
+
return b.task.updatedAt.getTime() - a.task.updatedAt.getTime();
|
|
1893
|
+
});
|
|
1894
|
+
return sorted.slice(0, limit).map((s) => s.task);
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1565
1897
|
// ../domain/src/task-change-log.ts
|
|
1566
1898
|
function describeStatusTransition(from, to) {
|
|
1567
1899
|
if (from === "planned" && to === "running") return "\u958B\u59CB";
|
|
@@ -1796,6 +2128,80 @@ function diffTasksToNoteInputs(before, after, lookups) {
|
|
|
1796
2128
|
}
|
|
1797
2129
|
return result;
|
|
1798
2130
|
}
|
|
2131
|
+
function titleOrPlaceholder(task) {
|
|
2132
|
+
return task.title || "\u7121\u984C\u306E\u30BF\u30B9\u30AF";
|
|
2133
|
+
}
|
|
2134
|
+
async function interruptTaskWithAudit(taskRepo, taskNoteRepo, params) {
|
|
2135
|
+
const result = await interruptTask(taskRepo, params);
|
|
2136
|
+
const notes = buildSplitNoteInputs(
|
|
2137
|
+
result.finishedOriginal,
|
|
2138
|
+
result.interruption,
|
|
2139
|
+
result.continuation
|
|
2140
|
+
);
|
|
2141
|
+
try {
|
|
2142
|
+
await Promise.all(notes.map((input) => taskNoteRepo.create(input)));
|
|
2143
|
+
} catch (err) {
|
|
2144
|
+
console.error("[audit] failed to record split notes", {
|
|
2145
|
+
sourceTaskId: result.finishedOriginal.id,
|
|
2146
|
+
err
|
|
2147
|
+
});
|
|
2148
|
+
}
|
|
2149
|
+
return result;
|
|
2150
|
+
}
|
|
2151
|
+
function buildSplitNoteInputs(source, interruption, continuation) {
|
|
2152
|
+
const sourceTitle = titleOrPlaceholder(source);
|
|
2153
|
+
const interruptionTitle = titleOrPlaceholder(interruption);
|
|
2154
|
+
return [
|
|
2155
|
+
{
|
|
2156
|
+
taskId: source.id,
|
|
2157
|
+
type: "split",
|
|
2158
|
+
body: `\u300C${interruptionTitle}\u300D\u306E\u5272\u308A\u8FBC\u307F\u3067\u5206\u5272\u3002\u6B8B\u4F5C\u696D\u306F\u5225\u30BF\u30B9\u30AF\u3067\u7D99\u7D9A\u3002`,
|
|
2159
|
+
metadata: {
|
|
2160
|
+
event: "split-source",
|
|
2161
|
+
interruptionTaskId: interruption.id,
|
|
2162
|
+
continuationTaskId: continuation.id
|
|
2163
|
+
}
|
|
2164
|
+
},
|
|
2165
|
+
{
|
|
2166
|
+
taskId: interruption.id,
|
|
2167
|
+
type: "split",
|
|
2168
|
+
body: `\u300C${sourceTitle}\u300D\u306E\u4F5C\u696D\u4E2D\u306B\u5272\u308A\u8FBC\u307F\u3068\u3057\u3066\u8D77\u7968\u3002`,
|
|
2169
|
+
metadata: {
|
|
2170
|
+
event: "split-interruption",
|
|
2171
|
+
sourceTaskId: source.id,
|
|
2172
|
+
continuationTaskId: continuation.id
|
|
2173
|
+
}
|
|
2174
|
+
},
|
|
2175
|
+
{
|
|
2176
|
+
taskId: continuation.id,
|
|
2177
|
+
type: "split",
|
|
2178
|
+
body: `\u300C${sourceTitle}\u300D\u306E\u6B8B\u4F5C\u696D\u3068\u3057\u3066\u7D99\u7D9A\u3002`,
|
|
2179
|
+
metadata: {
|
|
2180
|
+
event: "split-continuation",
|
|
2181
|
+
sourceTaskId: source.id,
|
|
2182
|
+
interruptionTaskId: interruption.id
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
];
|
|
2186
|
+
}
|
|
2187
|
+
|
|
2188
|
+
// ../domain/src/routine-expansion.ts
|
|
2189
|
+
function buildRoutineTaskPatch(routine) {
|
|
2190
|
+
return {
|
|
2191
|
+
title: routine.title,
|
|
2192
|
+
description: routine.description,
|
|
2193
|
+
estimatedSeconds: routine.estimatedSeconds,
|
|
2194
|
+
projectId: routine.projectId,
|
|
2195
|
+
contextId: routine.contextId,
|
|
2196
|
+
tagIds: routine.tagIds,
|
|
2197
|
+
scheduledStartTime: routine.defaultScheduledStartTime
|
|
2198
|
+
};
|
|
2199
|
+
}
|
|
2200
|
+
function pickPropagationTargets(routine, tasks, today) {
|
|
2201
|
+
return tasks.filter(
|
|
2202
|
+
(t) => t.routineId === routine.id && t.date >= today && t.status === "planned"
|
|
2203
|
+
);
|
|
2204
|
+
}
|
|
1799
2205
|
|
|
1800
2206
|
// ../infra-supabase/src/audit-task-repository.ts
|
|
1801
2207
|
var AuditingTaskRepository = class {
|
|
@@ -1863,17 +2269,23 @@ var AuditingTaskRepository = class {
|
|
|
1863
2269
|
delete(id) {
|
|
1864
2270
|
return this.inner.delete(id);
|
|
1865
2271
|
}
|
|
2272
|
+
deleteWithRoutineSkip(id, today) {
|
|
2273
|
+
return this.inner.deleteWithRoutineSkip(id, today);
|
|
2274
|
+
}
|
|
1866
2275
|
};
|
|
1867
2276
|
|
|
1868
2277
|
// ../infra-supabase/src/composition-root.ts
|
|
1869
2278
|
function buildRepositories(supabaseClient, cryptoSession, getLookups) {
|
|
1870
2279
|
const taskNote = new SupabaseTaskNoteRepository(supabaseClient, cryptoSession);
|
|
1871
2280
|
const rawTask = new SupabaseTaskRepository(supabaseClient, cryptoSession);
|
|
1872
|
-
const
|
|
2281
|
+
const auditingTask = getLookups ? new AuditingTaskRepository(rawTask, taskNote, getLookups) : void 0;
|
|
2282
|
+
const task = auditingTask ?? rawTask;
|
|
1873
2283
|
return {
|
|
1874
2284
|
task,
|
|
2285
|
+
auditingTask,
|
|
1875
2286
|
taskNote,
|
|
1876
2287
|
routine: new SupabaseRoutineRepository(supabaseClient, cryptoSession),
|
|
2288
|
+
routineExpansion: new SupabaseRoutineExpansionRepository(supabaseClient),
|
|
1877
2289
|
project: new SupabaseProjectRepository(supabaseClient, cryptoSession),
|
|
1878
2290
|
tag: new SupabaseTagRepository(supabaseClient, cryptoSession),
|
|
1879
2291
|
context: new SupabaseContextRepository(supabaseClient, cryptoSession),
|
|
@@ -1881,126 +2293,111 @@ function buildRepositories(supabaseClient, cryptoSession, getLookups) {
|
|
|
1881
2293
|
};
|
|
1882
2294
|
}
|
|
1883
2295
|
|
|
1884
|
-
// src/
|
|
1885
|
-
|
|
1886
|
-
var ENV_KEY = "TASKCHUTE_SUPABASE_PUBLISHABLE_KEY";
|
|
1887
|
-
function readSupabaseConfigFromEnv() {
|
|
1888
|
-
const url = process.env.TASKCHUTE_SUPABASE_URL;
|
|
1889
|
-
const publishableKey = process.env.TASKCHUTE_SUPABASE_PUBLISHABLE_KEY;
|
|
1890
|
-
if (!url || !publishableKey) {
|
|
1891
|
-
throw new Error(
|
|
1892
|
-
`Supabase \u306E\u74B0\u5883\u5909\u6570\u304C\u898B\u3064\u304B\u3089\u306A\u3044\u3002${ENV_URL} \u3068 ${ENV_KEY} \u3092 MCP server \u306E env \u306B\u8A2D\u5B9A\u3057\u3066\u306D\u301C`
|
|
1893
|
-
);
|
|
1894
|
-
}
|
|
1895
|
-
return { url, publishableKey };
|
|
1896
|
-
}
|
|
1897
|
-
var KEYRING_SERVICE = "taskchute-cli";
|
|
1898
|
-
var KEYRING_ACCOUNT = "passphrase";
|
|
1899
|
-
var KeyringPassphraseStore = class {
|
|
1900
|
-
get() {
|
|
1901
|
-
try {
|
|
1902
|
-
const entry = new Entry(KEYRING_SERVICE, KEYRING_ACCOUNT);
|
|
1903
|
-
return entry.getPassword();
|
|
1904
|
-
} catch {
|
|
1905
|
-
return null;
|
|
1906
|
-
}
|
|
1907
|
-
}
|
|
1908
|
-
set(passphrase) {
|
|
1909
|
-
const entry = new Entry(KEYRING_SERVICE, KEYRING_ACCOUNT);
|
|
1910
|
-
entry.setPassword(passphrase);
|
|
1911
|
-
}
|
|
1912
|
-
clear() {
|
|
1913
|
-
try {
|
|
1914
|
-
const entry = new Entry(KEYRING_SERVICE, KEYRING_ACCOUNT);
|
|
1915
|
-
entry.deletePassword();
|
|
1916
|
-
} catch {
|
|
1917
|
-
}
|
|
1918
|
-
}
|
|
1919
|
-
};
|
|
1920
|
-
var KEYRING_SERVICE2 = "taskchute-cli";
|
|
1921
|
-
var KeyringSessionStore = class {
|
|
1922
|
-
getItem(key) {
|
|
1923
|
-
try {
|
|
1924
|
-
const entry = new Entry(KEYRING_SERVICE2, key);
|
|
1925
|
-
return entry.getPassword();
|
|
1926
|
-
} catch {
|
|
1927
|
-
return null;
|
|
1928
|
-
}
|
|
1929
|
-
}
|
|
1930
|
-
setItem(key, value) {
|
|
1931
|
-
const entry = new Entry(KEYRING_SERVICE2, key);
|
|
1932
|
-
entry.setPassword(value);
|
|
1933
|
-
}
|
|
1934
|
-
removeItem(key) {
|
|
1935
|
-
try {
|
|
1936
|
-
const entry = new Entry(KEYRING_SERVICE2, key);
|
|
1937
|
-
entry.deletePassword();
|
|
1938
|
-
} catch {
|
|
1939
|
-
}
|
|
1940
|
-
}
|
|
1941
|
-
};
|
|
1942
|
-
|
|
1943
|
-
// src/crypto-context.ts
|
|
1944
|
-
var McpToolError = class extends Error {
|
|
1945
|
-
constructor(message) {
|
|
1946
|
-
super(message);
|
|
1947
|
-
this.name = "McpToolError";
|
|
1948
|
-
}
|
|
1949
|
-
};
|
|
1950
|
-
function resolvePassphrase(store) {
|
|
2296
|
+
// ../node-shared/src/create-node-app-context.ts
|
|
2297
|
+
async function resolvePassphrase(store, promptPassphrase) {
|
|
1951
2298
|
const envPw = process.env.TASKCHUTE_PASSPHRASE;
|
|
1952
2299
|
if (envPw) return envPw;
|
|
1953
2300
|
const stored = store.get();
|
|
1954
2301
|
if (stored) return stored;
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
2302
|
+
if (!promptPassphrase) {
|
|
2303
|
+
throw new AppContextError(
|
|
2304
|
+
"No passphrase available. Set TASKCHUTE_PASSPHRASE env or run `taskchute unlock` from the CLI first."
|
|
2305
|
+
);
|
|
2306
|
+
}
|
|
2307
|
+
return await promptPassphrase();
|
|
1958
2308
|
}
|
|
1959
|
-
async function
|
|
2309
|
+
async function createNodeAppContext(opts = {}) {
|
|
1960
2310
|
const passphraseStore = opts.passphraseStore ?? new KeyringPassphraseStore();
|
|
2311
|
+
const sessionStorage = opts.sessionStorage ?? new KeyringSessionStore();
|
|
1961
2312
|
const supabase = createNodeSupabaseClient(readSupabaseConfigFromEnv(), {
|
|
1962
|
-
storage:
|
|
2313
|
+
storage: sessionStorage
|
|
1963
2314
|
});
|
|
1964
2315
|
const {
|
|
1965
2316
|
data: { user },
|
|
1966
2317
|
error: authError
|
|
1967
2318
|
} = await supabase.auth.getUser();
|
|
1968
2319
|
if (authError || !user || !user.email) {
|
|
1969
|
-
throw new
|
|
2320
|
+
throw new AppContextError(
|
|
1970
2321
|
"Not logged in. Run `taskchute login` from the CLI first (session is shared via OS keyring)."
|
|
1971
2322
|
);
|
|
1972
2323
|
}
|
|
1973
2324
|
const userKeysRepo = new SupabaseUserKeysRepository(supabase);
|
|
1974
2325
|
const snapshot = await userKeysRepo.getOwn();
|
|
1975
2326
|
if (!snapshot) {
|
|
1976
|
-
throw new
|
|
2327
|
+
throw new AppContextError(
|
|
1977
2328
|
"E2EE not set up. Complete setup from the web app first (Settings \u2192 \u30C7\u30FC\u30BF\u306E\u6697\u53F7\u5316)."
|
|
1978
2329
|
);
|
|
1979
2330
|
}
|
|
1980
|
-
const passphrase = resolvePassphrase(passphraseStore);
|
|
2331
|
+
const passphrase = await resolvePassphrase(passphraseStore, opts.promptPassphrase);
|
|
1981
2332
|
let masterKey;
|
|
1982
2333
|
try {
|
|
1983
2334
|
masterKey = await unlockMasterKey(snapshot, { kind: "passphrase", passphrase });
|
|
1984
2335
|
} catch (err) {
|
|
1985
2336
|
if (err instanceof UnlockError) {
|
|
1986
|
-
throw new
|
|
2337
|
+
throw new AppContextError(`Unlock failed: ${err.message}`);
|
|
1987
2338
|
}
|
|
1988
2339
|
throw err;
|
|
1989
2340
|
}
|
|
1990
2341
|
const cryptoSession = new CryptoSession();
|
|
1991
2342
|
cryptoSession.setMasterKey(masterKey, snapshot.currentKeyId);
|
|
1992
|
-
const
|
|
2343
|
+
const lookupsRef = {
|
|
2344
|
+
current: { projects: [], tags: [], contexts: [] }
|
|
2345
|
+
};
|
|
2346
|
+
const repos = buildRepositories(supabase, cryptoSession, () => lookupsRef.current);
|
|
2347
|
+
const refreshLookups = async () => {
|
|
2348
|
+
const [projects, tags, contexts] = await Promise.all([
|
|
2349
|
+
repos.project.findAll(),
|
|
2350
|
+
repos.tag.findAll(),
|
|
2351
|
+
repos.context.findAll()
|
|
2352
|
+
]);
|
|
2353
|
+
lookupsRef.current = { projects, tags, contexts };
|
|
2354
|
+
};
|
|
2355
|
+
try {
|
|
2356
|
+
await refreshLookups();
|
|
2357
|
+
} catch (err) {
|
|
2358
|
+
console.error("[createNodeAppContext] initial refreshLookups failed:", err);
|
|
2359
|
+
}
|
|
1993
2360
|
return {
|
|
1994
2361
|
supabase,
|
|
1995
2362
|
cryptoSession,
|
|
1996
2363
|
repos,
|
|
1997
2364
|
userId: user.id,
|
|
1998
|
-
email: user.email
|
|
2365
|
+
email: user.email,
|
|
2366
|
+
refreshLookups
|
|
1999
2367
|
};
|
|
2000
2368
|
}
|
|
2001
2369
|
|
|
2002
|
-
// src/
|
|
2003
|
-
|
|
2370
|
+
// src/crypto-context.ts
|
|
2371
|
+
var McpToolError = class extends Error {
|
|
2372
|
+
constructor(message) {
|
|
2373
|
+
super(message);
|
|
2374
|
+
this.name = "McpToolError";
|
|
2375
|
+
}
|
|
2376
|
+
};
|
|
2377
|
+
async function wrapDomainErrors(op) {
|
|
2378
|
+
try {
|
|
2379
|
+
return await op();
|
|
2380
|
+
} catch (err) {
|
|
2381
|
+
if (err instanceof McpToolError) throw err;
|
|
2382
|
+
if (err instanceof Error) throw new McpToolError(err.message);
|
|
2383
|
+
throw err;
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
async function createAppContext(opts = {}) {
|
|
2387
|
+
try {
|
|
2388
|
+
return await createNodeAppContext({
|
|
2389
|
+
passphraseStore: opts.passphraseStore
|
|
2390
|
+
});
|
|
2391
|
+
} catch (err) {
|
|
2392
|
+
if (err instanceof AppContextError) {
|
|
2393
|
+
throw new McpToolError(err.message);
|
|
2394
|
+
}
|
|
2395
|
+
throw err;
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
|
|
2399
|
+
// src/format/task-summary.ts
|
|
2400
|
+
function taskSummaryFrom(task) {
|
|
2004
2401
|
const summary = {
|
|
2005
2402
|
id: task.id,
|
|
2006
2403
|
date: task.date,
|
|
@@ -2033,15 +2430,81 @@ function taskSummaryFrom(task) {
|
|
|
2033
2430
|
return summary;
|
|
2034
2431
|
}
|
|
2035
2432
|
|
|
2036
|
-
// src/tools/add-task.ts
|
|
2433
|
+
// src/tools/add-parallel-task.ts
|
|
2434
|
+
var addParallelTaskInputSchema = z.object({
|
|
2435
|
+
title: z.string().min(1, "title must not be empty"),
|
|
2436
|
+
estimated_seconds: z.number().int().positive(),
|
|
2437
|
+
date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "date must be YYYY-MM-DD").optional().describe("\u5BFE\u8C61\u65E5\u3002\u7701\u7565\u6642\u306F\u4ECA\u65E5"),
|
|
2438
|
+
description: z.string().optional(),
|
|
2439
|
+
project_id: z.string().uuid().optional(),
|
|
2440
|
+
context_id: z.string().uuid().optional(),
|
|
2441
|
+
tag_ids: z.array(z.string().uuid()).optional(),
|
|
2442
|
+
is_background: z.boolean().optional(),
|
|
2443
|
+
start_immediately: z.boolean().optional().describe("true (default) \u3067 running \u72B6\u614B + \u5373\u8A08\u6E2C\u958B\u59CB\u3002false \u3067 planned \u4F5C\u6210\u306E\u307F")
|
|
2444
|
+
});
|
|
2445
|
+
async function addParallelTaskHandler(ctx, input) {
|
|
2446
|
+
if (input.project_id) {
|
|
2447
|
+
const p = await ctx.repos.project.findById(input.project_id);
|
|
2448
|
+
if (!p) throw new McpToolError(`Project not found: ${input.project_id}`);
|
|
2449
|
+
}
|
|
2450
|
+
if (input.context_id) {
|
|
2451
|
+
const c = await ctx.repos.context.findById(input.context_id);
|
|
2452
|
+
if (!c) throw new McpToolError(`Context not found: ${input.context_id}`);
|
|
2453
|
+
}
|
|
2454
|
+
if (input.tag_ids && input.tag_ids.length > 0) {
|
|
2455
|
+
const checked = await Promise.all(
|
|
2456
|
+
input.tag_ids.map(async (id) => ({
|
|
2457
|
+
id,
|
|
2458
|
+
exists: await ctx.repos.tag.findById(id) !== null
|
|
2459
|
+
}))
|
|
2460
|
+
);
|
|
2461
|
+
const missing = checked.filter((c) => !c.exists).map((c) => c.id);
|
|
2462
|
+
if (missing.length > 0) throw new McpToolError(`Tag(s) not found: ${missing.join(", ")}`);
|
|
2463
|
+
}
|
|
2464
|
+
const task = await addParallelTask(ctx.repos.task, {
|
|
2465
|
+
date: input.date ?? todayDateString(),
|
|
2466
|
+
title: input.title,
|
|
2467
|
+
estimatedSeconds: input.estimated_seconds,
|
|
2468
|
+
...input.description !== void 0 && { description: input.description },
|
|
2469
|
+
...input.project_id !== void 0 && { projectId: input.project_id },
|
|
2470
|
+
...input.context_id !== void 0 && { contextId: input.context_id },
|
|
2471
|
+
...input.tag_ids !== void 0 && { tagIds: input.tag_ids },
|
|
2472
|
+
...input.is_background !== void 0 && { isBackground: input.is_background },
|
|
2473
|
+
...input.start_immediately !== void 0 && { startImmediately: input.start_immediately }
|
|
2474
|
+
});
|
|
2475
|
+
return { task: taskSummaryFrom(task) };
|
|
2476
|
+
}
|
|
2037
2477
|
var addTaskInputSchema = z.object({
|
|
2038
2478
|
title: z.string().min(1, "title must not be empty"),
|
|
2039
2479
|
date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "date must be YYYY-MM-DD").optional().describe("\u5BFE\u8C61\u65E5 (YYYY-MM-DD)\u3002\u7701\u7565\u6642\u306F\u30B5\u30FC\u30D0\u30FC\u306E\u4ECA\u65E5 (Asia/Tokyo) \u3092\u4F7F\u3046"),
|
|
2040
2480
|
estimated_seconds: z.number().int().positive().optional().describe("\u898B\u7A4D\u3082\u308A\u6642\u9593 (\u79D2)\u3002\u7701\u7565\u6642\u306F 1800 (= 30 \u5206)"),
|
|
2041
|
-
description: z.string().optional()
|
|
2481
|
+
description: z.string().optional(),
|
|
2482
|
+
scheduled_start_time: z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "scheduled_start_time must be HH:MM").optional().describe("\u4E88\u5B9A\u958B\u59CB\u6642\u523B (HH:MM)\u3002\u30BF\u30A4\u30E0\u30D6\u30ED\u30C3\u30AF / \u30BD\u30FC\u30C8\u9806\u306B\u5F71\u97FF"),
|
|
2483
|
+
project_id: z.string().uuid().optional(),
|
|
2484
|
+
context_id: z.string().uuid().optional(),
|
|
2485
|
+
tag_ids: z.array(z.string().uuid()).optional(),
|
|
2486
|
+
notify_at_scheduled_start: z.boolean().optional().describe("true \u306A\u3089 scheduled_start_time \u5230\u9054\u6642\u306B\u901A\u77E5 (Web \u306E\u307F\u52D5\u4F5C)"),
|
|
2487
|
+
is_background: z.boolean().optional().describe("true \u306A\u3089\u4E26\u884C\u9032\u884C\u4E2D\u306E\u30D0\u30C3\u30AF\u30B0\u30E9\u30A6\u30F3\u30C9\u30BF\u30B9\u30AF\u6271\u3044 (\u898B\u7A4D\u3082\u308A\u96C6\u8A08\u304B\u3089\u9664\u5916)")
|
|
2042
2488
|
});
|
|
2043
2489
|
var DEFAULT_ESTIMATED_SECONDS = 30 * 60;
|
|
2044
2490
|
async function addTaskHandler(ctx, input) {
|
|
2491
|
+
if (input.project_id) {
|
|
2492
|
+
const project = await ctx.repos.project.findById(input.project_id);
|
|
2493
|
+
if (!project) throw new McpToolError(`Project not found: ${input.project_id}`);
|
|
2494
|
+
}
|
|
2495
|
+
if (input.context_id) {
|
|
2496
|
+
const context = await ctx.repos.context.findById(input.context_id);
|
|
2497
|
+
if (!context) throw new McpToolError(`Context not found: ${input.context_id}`);
|
|
2498
|
+
}
|
|
2499
|
+
if (input.tag_ids && input.tag_ids.length > 0) {
|
|
2500
|
+
const checked = await Promise.all(
|
|
2501
|
+
input.tag_ids.map(async (id) => ({ id, exists: await ctx.repos.tag.findById(id) !== null }))
|
|
2502
|
+
);
|
|
2503
|
+
const missing = checked.filter((c) => !c.exists).map((c) => c.id);
|
|
2504
|
+
if (missing.length > 0) {
|
|
2505
|
+
throw new McpToolError(`Tag(s) not found: ${missing.join(", ")}`);
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2045
2508
|
const date = input.date ?? todayDateString();
|
|
2046
2509
|
const estimatedSeconds = input.estimated_seconds ?? DEFAULT_ESTIMATED_SECONDS;
|
|
2047
2510
|
const existing = await ctx.repos.task.findByDate(date);
|
|
@@ -2054,10 +2517,430 @@ async function addTaskHandler(ctx, input) {
|
|
|
2054
2517
|
sessions: [],
|
|
2055
2518
|
status: "planned",
|
|
2056
2519
|
orderIndex,
|
|
2057
|
-
tagIds: []
|
|
2520
|
+
tagIds: input.tag_ids ?? [],
|
|
2521
|
+
projectId: input.project_id,
|
|
2522
|
+
contextId: input.context_id,
|
|
2523
|
+
scheduledStartTime: input.scheduled_start_time,
|
|
2524
|
+
notifyAtScheduledStart: input.notify_at_scheduled_start,
|
|
2525
|
+
isBackground: input.is_background
|
|
2058
2526
|
});
|
|
2059
2527
|
return { task: taskSummaryFrom(task) };
|
|
2060
2528
|
}
|
|
2529
|
+
|
|
2530
|
+
// src/format/context-summary.ts
|
|
2531
|
+
function contextSummaryFrom(context) {
|
|
2532
|
+
const summary = {
|
|
2533
|
+
id: context.id,
|
|
2534
|
+
name: context.name,
|
|
2535
|
+
status: context.status,
|
|
2536
|
+
created_at: context.createdAt.toISOString(),
|
|
2537
|
+
updated_at: context.updatedAt.toISOString()
|
|
2538
|
+
};
|
|
2539
|
+
if (context.description !== void 0) summary.description = context.description;
|
|
2540
|
+
if (context.icon !== void 0) summary.icon = context.icon;
|
|
2541
|
+
if (context.color !== void 0) summary.color = context.color;
|
|
2542
|
+
return summary;
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2545
|
+
// src/tools/archive-context.ts
|
|
2546
|
+
var archiveContextInputSchema = z.object({
|
|
2547
|
+
id: z.string().uuid()
|
|
2548
|
+
});
|
|
2549
|
+
async function archiveContextHandler(ctx, input) {
|
|
2550
|
+
const existing = await ctx.repos.context.findById(input.id);
|
|
2551
|
+
if (!existing) {
|
|
2552
|
+
throw new McpToolError(`Context not found: ${input.id}`);
|
|
2553
|
+
}
|
|
2554
|
+
const archived = await ctx.repos.context.archive(input.id);
|
|
2555
|
+
return { context: contextSummaryFrom(archived) };
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2558
|
+
// src/format/project-summary.ts
|
|
2559
|
+
function projectSummaryFrom(project) {
|
|
2560
|
+
const summary = {
|
|
2561
|
+
id: project.id,
|
|
2562
|
+
name: project.name,
|
|
2563
|
+
status: project.status,
|
|
2564
|
+
created_at: project.createdAt.toISOString(),
|
|
2565
|
+
updated_at: project.updatedAt.toISOString()
|
|
2566
|
+
};
|
|
2567
|
+
if (project.description !== void 0) summary.description = project.description;
|
|
2568
|
+
if (project.color !== void 0) summary.color = project.color;
|
|
2569
|
+
if (project.parentProjectId !== void 0) summary.parent_project_id = project.parentProjectId;
|
|
2570
|
+
if (project.goalId !== void 0) summary.goal_id = project.goalId;
|
|
2571
|
+
if (project.startedAt !== void 0) summary.started_at = project.startedAt.toISOString();
|
|
2572
|
+
if (project.targetEndDate !== void 0) {
|
|
2573
|
+
summary.target_end_date = project.targetEndDate.toISOString();
|
|
2574
|
+
}
|
|
2575
|
+
if (project.archivedAt !== void 0) summary.archived_at = project.archivedAt.toISOString();
|
|
2576
|
+
return summary;
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2579
|
+
// src/tools/archive-project.ts
|
|
2580
|
+
var archiveProjectInputSchema = z.object({
|
|
2581
|
+
id: z.string().uuid()
|
|
2582
|
+
});
|
|
2583
|
+
async function archiveProjectHandler(ctx, input) {
|
|
2584
|
+
const existing = await ctx.repos.project.findById(input.id);
|
|
2585
|
+
if (!existing) {
|
|
2586
|
+
throw new McpToolError(`Project not found: ${input.id}`);
|
|
2587
|
+
}
|
|
2588
|
+
const archived = await ctx.repos.project.archive(input.id);
|
|
2589
|
+
return { project: projectSummaryFrom(archived) };
|
|
2590
|
+
}
|
|
2591
|
+
|
|
2592
|
+
// src/format/routine-summary.ts
|
|
2593
|
+
function routineSummaryFrom(routine) {
|
|
2594
|
+
const summary = {
|
|
2595
|
+
id: routine.id,
|
|
2596
|
+
title: routine.title,
|
|
2597
|
+
estimated_seconds: routine.estimatedSeconds,
|
|
2598
|
+
tag_ids: routine.tagIds,
|
|
2599
|
+
frequency: routine.frequency,
|
|
2600
|
+
auto_expand: routine.autoExpand,
|
|
2601
|
+
status: routine.status,
|
|
2602
|
+
created_at: routine.createdAt.toISOString(),
|
|
2603
|
+
updated_at: routine.updatedAt.toISOString()
|
|
2604
|
+
};
|
|
2605
|
+
if (routine.description !== void 0) summary.description = routine.description;
|
|
2606
|
+
if (routine.projectId !== void 0) summary.project_id = routine.projectId;
|
|
2607
|
+
if (routine.contextId !== void 0) summary.context_id = routine.contextId;
|
|
2608
|
+
if (routine.defaultScheduledStartTime !== void 0) {
|
|
2609
|
+
summary.default_scheduled_start_time = routine.defaultScheduledStartTime;
|
|
2610
|
+
}
|
|
2611
|
+
if (routine.startDate !== void 0) summary.start_date = routine.startDate;
|
|
2612
|
+
if (routine.endDate !== void 0) summary.end_date = routine.endDate;
|
|
2613
|
+
return summary;
|
|
2614
|
+
}
|
|
2615
|
+
|
|
2616
|
+
// src/tools/archive-routine.ts
|
|
2617
|
+
var archiveRoutineInputSchema = z.object({
|
|
2618
|
+
id: z.string().uuid()
|
|
2619
|
+
});
|
|
2620
|
+
async function archiveRoutineHandler(ctx, input) {
|
|
2621
|
+
const existing = await ctx.repos.routine.findById(input.id);
|
|
2622
|
+
if (!existing) {
|
|
2623
|
+
throw new McpToolError(`Routine not found: ${input.id}`);
|
|
2624
|
+
}
|
|
2625
|
+
const archived = await ctx.repos.routine.archive(input.id);
|
|
2626
|
+
return { routine: routineSummaryFrom(archived) };
|
|
2627
|
+
}
|
|
2628
|
+
|
|
2629
|
+
// src/format/tag-summary.ts
|
|
2630
|
+
function tagSummaryFrom(tag) {
|
|
2631
|
+
const summary = {
|
|
2632
|
+
id: tag.id,
|
|
2633
|
+
name: tag.name,
|
|
2634
|
+
status: tag.status,
|
|
2635
|
+
created_at: tag.createdAt.toISOString(),
|
|
2636
|
+
updated_at: tag.updatedAt.toISOString()
|
|
2637
|
+
};
|
|
2638
|
+
if (tag.description !== void 0) summary.description = tag.description;
|
|
2639
|
+
if (tag.color !== void 0) summary.color = tag.color;
|
|
2640
|
+
return summary;
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
// src/tools/archive-tag.ts
|
|
2644
|
+
var archiveTagInputSchema = z.object({
|
|
2645
|
+
id: z.string().uuid()
|
|
2646
|
+
});
|
|
2647
|
+
async function archiveTagHandler(ctx, input) {
|
|
2648
|
+
const existing = await ctx.repos.tag.findById(input.id);
|
|
2649
|
+
if (!existing) {
|
|
2650
|
+
throw new McpToolError(`Tag not found: ${input.id}`);
|
|
2651
|
+
}
|
|
2652
|
+
const archived = await ctx.repos.tag.archive(input.id);
|
|
2653
|
+
return { tag: tagSummaryFrom(archived) };
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
// src/format/time-block-summary.ts
|
|
2657
|
+
function timeBlockSummaryFrom(timeBlock) {
|
|
2658
|
+
const summary = {
|
|
2659
|
+
id: timeBlock.id,
|
|
2660
|
+
name: timeBlock.name,
|
|
2661
|
+
start_time: timeBlock.startTime,
|
|
2662
|
+
end_time: timeBlock.endTime,
|
|
2663
|
+
weekdays: timeBlock.weekdays,
|
|
2664
|
+
status: timeBlock.status,
|
|
2665
|
+
created_at: timeBlock.createdAt.toISOString(),
|
|
2666
|
+
updated_at: timeBlock.updatedAt.toISOString()
|
|
2667
|
+
};
|
|
2668
|
+
if (timeBlock.defaultProjectId !== void 0) {
|
|
2669
|
+
summary.default_project_id = timeBlock.defaultProjectId;
|
|
2670
|
+
}
|
|
2671
|
+
if (timeBlock.defaultContextId !== void 0) {
|
|
2672
|
+
summary.default_context_id = timeBlock.defaultContextId;
|
|
2673
|
+
}
|
|
2674
|
+
if (timeBlock.defaultTagIds !== void 0) summary.default_tag_ids = timeBlock.defaultTagIds;
|
|
2675
|
+
if (timeBlock.color !== void 0) summary.color = timeBlock.color;
|
|
2676
|
+
if (timeBlock.startDate !== void 0) summary.start_date = timeBlock.startDate;
|
|
2677
|
+
if (timeBlock.endDate !== void 0) summary.end_date = timeBlock.endDate;
|
|
2678
|
+
return summary;
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2681
|
+
// src/tools/archive-time-block.ts
|
|
2682
|
+
var archiveTimeBlockInputSchema = z.object({
|
|
2683
|
+
id: z.string().uuid()
|
|
2684
|
+
});
|
|
2685
|
+
async function archiveTimeBlockHandler(ctx, input) {
|
|
2686
|
+
const existing = await ctx.repos.timeBlock.findById(input.id);
|
|
2687
|
+
if (!existing) {
|
|
2688
|
+
throw new McpToolError(`TimeBlock not found: ${input.id}`);
|
|
2689
|
+
}
|
|
2690
|
+
const archived = await ctx.repos.timeBlock.archive(input.id);
|
|
2691
|
+
return { time_block: timeBlockSummaryFrom(archived) };
|
|
2692
|
+
}
|
|
2693
|
+
var createContextInputSchema = z.object({
|
|
2694
|
+
name: z.string().min(1, "name must not be empty"),
|
|
2695
|
+
description: z.string().optional(),
|
|
2696
|
+
icon: z.string().optional().describe("\u7D75\u6587\u5B57\u307E\u305F\u306F\u30A2\u30A4\u30B3\u30F3\u540D (\u4F8B: \u{1F3E0} / mdi-home)"),
|
|
2697
|
+
color: z.string().optional().describe("UI \u8272 (\u4F8B: #ff6b6b)")
|
|
2698
|
+
});
|
|
2699
|
+
async function createContextHandler(ctx, input) {
|
|
2700
|
+
const createInput = {
|
|
2701
|
+
name: input.name,
|
|
2702
|
+
status: "active"
|
|
2703
|
+
};
|
|
2704
|
+
if (input.description !== void 0) createInput.description = input.description;
|
|
2705
|
+
if (input.icon !== void 0) createInput.icon = input.icon;
|
|
2706
|
+
if (input.color !== void 0) createInput.color = input.color;
|
|
2707
|
+
const context = await ctx.repos.context.create(createInput);
|
|
2708
|
+
return { context: contextSummaryFrom(context) };
|
|
2709
|
+
}
|
|
2710
|
+
var createProjectInputSchema = z.object({
|
|
2711
|
+
name: z.string().min(1, "name must not be empty"),
|
|
2712
|
+
description: z.string().optional(),
|
|
2713
|
+
color: z.string().optional().describe("UI \u8272 (\u4F8B: #ff6b6b)"),
|
|
2714
|
+
parent_project_id: z.string().uuid().optional(),
|
|
2715
|
+
goal_id: z.string().uuid().optional(),
|
|
2716
|
+
started_at: z.string().datetime().optional().describe("ISO 8601 datetime"),
|
|
2717
|
+
target_end_date: z.string().datetime().optional().describe("ISO 8601 datetime")
|
|
2718
|
+
});
|
|
2719
|
+
async function createProjectHandler(ctx, input) {
|
|
2720
|
+
if (input.parent_project_id) {
|
|
2721
|
+
const parent = await ctx.repos.project.findById(input.parent_project_id);
|
|
2722
|
+
if (!parent) {
|
|
2723
|
+
throw new McpToolError(`Parent project not found: ${input.parent_project_id}`);
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
const createInput = {
|
|
2727
|
+
name: input.name,
|
|
2728
|
+
status: "active"
|
|
2729
|
+
};
|
|
2730
|
+
if (input.description !== void 0) createInput.description = input.description;
|
|
2731
|
+
if (input.color !== void 0) createInput.color = input.color;
|
|
2732
|
+
if (input.parent_project_id !== void 0) createInput.parentProjectId = input.parent_project_id;
|
|
2733
|
+
if (input.goal_id !== void 0) createInput.goalId = input.goal_id;
|
|
2734
|
+
if (input.started_at !== void 0) createInput.startedAt = new Date(input.started_at);
|
|
2735
|
+
if (input.target_end_date !== void 0) {
|
|
2736
|
+
createInput.targetEndDate = new Date(input.target_end_date);
|
|
2737
|
+
}
|
|
2738
|
+
const project = await ctx.repos.project.create(createInput);
|
|
2739
|
+
return { project: projectSummaryFrom(project) };
|
|
2740
|
+
}
|
|
2741
|
+
var frequencySchema = z.discriminatedUnion("type", [
|
|
2742
|
+
z.object({ type: z.literal("daily") }),
|
|
2743
|
+
z.object({
|
|
2744
|
+
type: z.literal("weekly"),
|
|
2745
|
+
weekdays: z.array(z.number().int().min(0).max(6)).min(1, "at least 1 weekday")
|
|
2746
|
+
}),
|
|
2747
|
+
z.object({
|
|
2748
|
+
type: z.literal("monthly"),
|
|
2749
|
+
days: z.array(z.number().int().min(1).max(31)).min(1, "at least 1 day")
|
|
2750
|
+
}),
|
|
2751
|
+
z.object({ type: z.literal("custom"), cron: z.string().min(1) })
|
|
2752
|
+
]);
|
|
2753
|
+
var createRoutineInputSchema = z.object({
|
|
2754
|
+
title: z.string().min(1, "title must not be empty"),
|
|
2755
|
+
description: z.string().optional(),
|
|
2756
|
+
estimated_seconds: z.number().int().positive(),
|
|
2757
|
+
frequency: frequencySchema,
|
|
2758
|
+
project_id: z.string().uuid().optional(),
|
|
2759
|
+
context_id: z.string().uuid().optional(),
|
|
2760
|
+
tag_ids: z.array(z.string().uuid()).optional(),
|
|
2761
|
+
default_scheduled_start_time: z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "must be HH:MM").optional(),
|
|
2762
|
+
auto_expand: z.boolean().optional().describe("true \u306A\u3089 Today \u3092\u958B\u3044\u305F\u6642\u306B\u81EA\u52D5\u5C55\u958B (default true)"),
|
|
2763
|
+
start_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().describe("\u3053\u306E\u65E5\u4ED8\u4EE5\u964D\u306B\u6709\u52B9\u3002YYYY-MM-DD"),
|
|
2764
|
+
end_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional()
|
|
2765
|
+
});
|
|
2766
|
+
async function createRoutineHandler(ctx, input) {
|
|
2767
|
+
if (input.project_id) {
|
|
2768
|
+
const p = await ctx.repos.project.findById(input.project_id);
|
|
2769
|
+
if (!p) throw new McpToolError(`Project not found: ${input.project_id}`);
|
|
2770
|
+
}
|
|
2771
|
+
if (input.context_id) {
|
|
2772
|
+
const c = await ctx.repos.context.findById(input.context_id);
|
|
2773
|
+
if (!c) throw new McpToolError(`Context not found: ${input.context_id}`);
|
|
2774
|
+
}
|
|
2775
|
+
if (input.tag_ids && input.tag_ids.length > 0) {
|
|
2776
|
+
const checked = await Promise.all(
|
|
2777
|
+
input.tag_ids.map(async (id) => ({
|
|
2778
|
+
id,
|
|
2779
|
+
exists: await ctx.repos.tag.findById(id) !== null
|
|
2780
|
+
}))
|
|
2781
|
+
);
|
|
2782
|
+
const missing = checked.filter((c) => !c.exists).map((c) => c.id);
|
|
2783
|
+
if (missing.length > 0) throw new McpToolError(`Tag(s) not found: ${missing.join(", ")}`);
|
|
2784
|
+
}
|
|
2785
|
+
const createInput = {
|
|
2786
|
+
title: input.title,
|
|
2787
|
+
estimatedSeconds: input.estimated_seconds,
|
|
2788
|
+
tagIds: input.tag_ids ?? [],
|
|
2789
|
+
frequency: input.frequency,
|
|
2790
|
+
autoExpand: input.auto_expand ?? true,
|
|
2791
|
+
status: "active"
|
|
2792
|
+
};
|
|
2793
|
+
if (input.description !== void 0) createInput.description = input.description;
|
|
2794
|
+
if (input.project_id !== void 0) createInput.projectId = input.project_id;
|
|
2795
|
+
if (input.context_id !== void 0) createInput.contextId = input.context_id;
|
|
2796
|
+
if (input.default_scheduled_start_time !== void 0) {
|
|
2797
|
+
createInput.defaultScheduledStartTime = input.default_scheduled_start_time;
|
|
2798
|
+
}
|
|
2799
|
+
if (input.start_date !== void 0) createInput.startDate = input.start_date;
|
|
2800
|
+
if (input.end_date !== void 0) createInput.endDate = input.end_date;
|
|
2801
|
+
const routine = await ctx.repos.routine.create(createInput);
|
|
2802
|
+
return { routine: routineSummaryFrom(routine) };
|
|
2803
|
+
}
|
|
2804
|
+
var createTagInputSchema = z.object({
|
|
2805
|
+
name: z.string().min(1, "name must not be empty"),
|
|
2806
|
+
description: z.string().optional(),
|
|
2807
|
+
color: z.string().optional().describe("UI \u8272 (\u4F8B: #ff6b6b)")
|
|
2808
|
+
});
|
|
2809
|
+
async function createTagHandler(ctx, input) {
|
|
2810
|
+
const createInput = {
|
|
2811
|
+
name: input.name,
|
|
2812
|
+
status: "active"
|
|
2813
|
+
};
|
|
2814
|
+
if (input.description !== void 0) createInput.description = input.description;
|
|
2815
|
+
if (input.color !== void 0) createInput.color = input.color;
|
|
2816
|
+
const tag = await ctx.repos.tag.create(createInput);
|
|
2817
|
+
return { tag: tagSummaryFrom(tag) };
|
|
2818
|
+
}
|
|
2819
|
+
var HHMM = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
2820
|
+
var createTimeBlockInputSchema = z.object({
|
|
2821
|
+
name: z.string().min(1, "name must not be empty"),
|
|
2822
|
+
start_time: z.string().regex(HHMM, "start_time must be HH:MM"),
|
|
2823
|
+
end_time: z.string().regex(HHMM, "end_time must be HH:MM"),
|
|
2824
|
+
weekdays: z.array(z.number().int().min(0).max(6)).min(1, "at least 1 weekday"),
|
|
2825
|
+
default_project_id: z.string().uuid().optional(),
|
|
2826
|
+
default_context_id: z.string().uuid().optional(),
|
|
2827
|
+
default_tag_ids: z.array(z.string().uuid()).optional(),
|
|
2828
|
+
color: z.string().optional(),
|
|
2829
|
+
start_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
|
|
2830
|
+
end_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional()
|
|
2831
|
+
});
|
|
2832
|
+
async function createTimeBlockHandler(ctx, input) {
|
|
2833
|
+
if (input.default_project_id) {
|
|
2834
|
+
const p = await ctx.repos.project.findById(input.default_project_id);
|
|
2835
|
+
if (!p) throw new McpToolError(`Project not found: ${input.default_project_id}`);
|
|
2836
|
+
}
|
|
2837
|
+
if (input.default_context_id) {
|
|
2838
|
+
const c = await ctx.repos.context.findById(input.default_context_id);
|
|
2839
|
+
if (!c) throw new McpToolError(`Context not found: ${input.default_context_id}`);
|
|
2840
|
+
}
|
|
2841
|
+
if (input.default_tag_ids && input.default_tag_ids.length > 0) {
|
|
2842
|
+
const checked = await Promise.all(
|
|
2843
|
+
input.default_tag_ids.map(async (id) => ({
|
|
2844
|
+
id,
|
|
2845
|
+
exists: await ctx.repos.tag.findById(id) !== null
|
|
2846
|
+
}))
|
|
2847
|
+
);
|
|
2848
|
+
const missing = checked.filter((c) => !c.exists).map((c) => c.id);
|
|
2849
|
+
if (missing.length > 0) throw new McpToolError(`Tag(s) not found: ${missing.join(", ")}`);
|
|
2850
|
+
}
|
|
2851
|
+
const createInput = {
|
|
2852
|
+
name: input.name,
|
|
2853
|
+
startTime: input.start_time,
|
|
2854
|
+
endTime: input.end_time,
|
|
2855
|
+
weekdays: input.weekdays,
|
|
2856
|
+
status: "active"
|
|
2857
|
+
};
|
|
2858
|
+
if (input.default_project_id !== void 0) {
|
|
2859
|
+
createInput.defaultProjectId = input.default_project_id;
|
|
2860
|
+
}
|
|
2861
|
+
if (input.default_context_id !== void 0) {
|
|
2862
|
+
createInput.defaultContextId = input.default_context_id;
|
|
2863
|
+
}
|
|
2864
|
+
if (input.default_tag_ids !== void 0) createInput.defaultTagIds = input.default_tag_ids;
|
|
2865
|
+
if (input.color !== void 0) createInput.color = input.color;
|
|
2866
|
+
if (input.start_date !== void 0) createInput.startDate = input.start_date;
|
|
2867
|
+
if (input.end_date !== void 0) createInput.endDate = input.end_date;
|
|
2868
|
+
const block = await ctx.repos.timeBlock.create(createInput);
|
|
2869
|
+
return { time_block: timeBlockSummaryFrom(block) };
|
|
2870
|
+
}
|
|
2871
|
+
var deleteContextInputSchema = z.object({
|
|
2872
|
+
id: z.string().uuid()
|
|
2873
|
+
});
|
|
2874
|
+
async function deleteContextHandler(ctx, input) {
|
|
2875
|
+
const existing = await ctx.repos.context.findById(input.id);
|
|
2876
|
+
if (!existing) {
|
|
2877
|
+
throw new McpToolError(`Context not found: ${input.id}`);
|
|
2878
|
+
}
|
|
2879
|
+
await ctx.repos.context.delete(input.id);
|
|
2880
|
+
return { id: input.id, deleted: true };
|
|
2881
|
+
}
|
|
2882
|
+
var deleteProjectInputSchema = z.object({
|
|
2883
|
+
id: z.string().uuid()
|
|
2884
|
+
});
|
|
2885
|
+
async function deleteProjectHandler(ctx, input) {
|
|
2886
|
+
const existing = await ctx.repos.project.findById(input.id);
|
|
2887
|
+
if (!existing) {
|
|
2888
|
+
throw new McpToolError(`Project not found: ${input.id}`);
|
|
2889
|
+
}
|
|
2890
|
+
await ctx.repos.project.delete(input.id);
|
|
2891
|
+
return { id: input.id, deleted: true };
|
|
2892
|
+
}
|
|
2893
|
+
var deleteRoutineInputSchema = z.object({
|
|
2894
|
+
id: z.string().uuid()
|
|
2895
|
+
});
|
|
2896
|
+
async function deleteRoutineHandler(ctx, input) {
|
|
2897
|
+
const existing = await ctx.repos.routine.findById(input.id);
|
|
2898
|
+
if (!existing) {
|
|
2899
|
+
throw new McpToolError(`Routine not found: ${input.id}`);
|
|
2900
|
+
}
|
|
2901
|
+
await ctx.repos.routine.delete(input.id);
|
|
2902
|
+
return { id: input.id, deleted: true };
|
|
2903
|
+
}
|
|
2904
|
+
var deleteTagInputSchema = z.object({
|
|
2905
|
+
id: z.string().uuid()
|
|
2906
|
+
});
|
|
2907
|
+
async function deleteTagHandler(ctx, input) {
|
|
2908
|
+
const existing = await ctx.repos.tag.findById(input.id);
|
|
2909
|
+
if (!existing) {
|
|
2910
|
+
throw new McpToolError(`Tag not found: ${input.id}`);
|
|
2911
|
+
}
|
|
2912
|
+
await ctx.repos.tag.delete(input.id);
|
|
2913
|
+
return { id: input.id, deleted: true };
|
|
2914
|
+
}
|
|
2915
|
+
var deleteTaskInputSchema = z.object({
|
|
2916
|
+
id: z.string().uuid({ message: "id must be a UUID" }),
|
|
2917
|
+
hard_delete: z.boolean().optional().describe(
|
|
2918
|
+
"true \u306A\u3089 routine_expansions \u306B skip \u8A18\u9332\u305B\u305A\u7269\u7406\u524A\u9664\u306E\u307F\u3002Routine \u7531\u6765\u30BF\u30B9\u30AF\u3092\u5B8C\u5168\u30EA\u30BB\u30C3\u30C8\u3057\u305F\u3044\u4E0A\u7D1A\u8005\u5411\u3051"
|
|
2919
|
+
)
|
|
2920
|
+
});
|
|
2921
|
+
async function deleteTaskHandler(ctx, input) {
|
|
2922
|
+
const existing = await ctx.repos.task.findById(input.id);
|
|
2923
|
+
if (!existing) {
|
|
2924
|
+
throw new McpToolError(`Task not found: ${input.id}`);
|
|
2925
|
+
}
|
|
2926
|
+
if (input.hard_delete === true) {
|
|
2927
|
+
await ctx.repos.task.delete(input.id);
|
|
2928
|
+
} else {
|
|
2929
|
+
await ctx.repos.task.deleteWithRoutineSkip(input.id, todayDateString());
|
|
2930
|
+
}
|
|
2931
|
+
return { id: input.id, deleted: true };
|
|
2932
|
+
}
|
|
2933
|
+
var deleteTimeBlockInputSchema = z.object({
|
|
2934
|
+
id: z.string().uuid()
|
|
2935
|
+
});
|
|
2936
|
+
async function deleteTimeBlockHandler(ctx, input) {
|
|
2937
|
+
const existing = await ctx.repos.timeBlock.findById(input.id);
|
|
2938
|
+
if (!existing) {
|
|
2939
|
+
throw new McpToolError(`TimeBlock not found: ${input.id}`);
|
|
2940
|
+
}
|
|
2941
|
+
await ctx.repos.timeBlock.delete(input.id);
|
|
2942
|
+
return { id: input.id, deleted: true };
|
|
2943
|
+
}
|
|
2061
2944
|
var doneTaskInputSchema = z.object({
|
|
2062
2945
|
id: z.string().uuid({ message: "id must be a UUID" })
|
|
2063
2946
|
});
|
|
@@ -2069,6 +2952,127 @@ async function doneTaskHandler(ctx, input) {
|
|
|
2069
2952
|
const updated = await completeTask(ctx.repos.task, input.id);
|
|
2070
2953
|
return { task: taskSummaryFrom(updated) };
|
|
2071
2954
|
}
|
|
2955
|
+
var interruptTaskInputSchema = z.object({
|
|
2956
|
+
target_task_id: z.string().uuid().describe("\u5272\u308A\u8FBC\u307F\u5BFE\u8C61 (running \u4E2D) \u306E\u30BF\u30B9\u30AF id"),
|
|
2957
|
+
title: z.string().min(1, "interruption title must not be empty"),
|
|
2958
|
+
estimated_seconds: z.number().int().positive(),
|
|
2959
|
+
description: z.string().optional(),
|
|
2960
|
+
project_id: z.string().uuid().optional(),
|
|
2961
|
+
context_id: z.string().uuid().optional(),
|
|
2962
|
+
tag_ids: z.array(z.string().uuid()).optional()
|
|
2963
|
+
});
|
|
2964
|
+
async function interruptTaskHandler(ctx, input) {
|
|
2965
|
+
if (input.project_id) {
|
|
2966
|
+
const p = await ctx.repos.project.findById(input.project_id);
|
|
2967
|
+
if (!p) throw new McpToolError(`Project not found: ${input.project_id}`);
|
|
2968
|
+
}
|
|
2969
|
+
if (input.context_id) {
|
|
2970
|
+
const c = await ctx.repos.context.findById(input.context_id);
|
|
2971
|
+
if (!c) throw new McpToolError(`Context not found: ${input.context_id}`);
|
|
2972
|
+
}
|
|
2973
|
+
if (input.tag_ids && input.tag_ids.length > 0) {
|
|
2974
|
+
const checked = await Promise.all(
|
|
2975
|
+
input.tag_ids.map(async (id) => ({
|
|
2976
|
+
id,
|
|
2977
|
+
exists: await ctx.repos.tag.findById(id) !== null
|
|
2978
|
+
}))
|
|
2979
|
+
);
|
|
2980
|
+
const missing = checked.filter((c) => !c.exists).map((c) => c.id);
|
|
2981
|
+
if (missing.length > 0) throw new McpToolError(`Tag(s) not found: ${missing.join(", ")}`);
|
|
2982
|
+
}
|
|
2983
|
+
const result = await wrapDomainErrors(
|
|
2984
|
+
() => interruptTaskWithAudit(ctx.repos.task, ctx.repos.taskNote, {
|
|
2985
|
+
targetTaskId: input.target_task_id,
|
|
2986
|
+
interruption: {
|
|
2987
|
+
title: input.title,
|
|
2988
|
+
estimatedSeconds: input.estimated_seconds,
|
|
2989
|
+
...input.description !== void 0 && { description: input.description },
|
|
2990
|
+
...input.project_id !== void 0 && { projectId: input.project_id },
|
|
2991
|
+
...input.context_id !== void 0 && { contextId: input.context_id },
|
|
2992
|
+
...input.tag_ids !== void 0 && { tagIds: input.tag_ids }
|
|
2993
|
+
}
|
|
2994
|
+
})
|
|
2995
|
+
);
|
|
2996
|
+
return {
|
|
2997
|
+
finished_original: taskSummaryFrom(result.finishedOriginal),
|
|
2998
|
+
interruption: taskSummaryFrom(result.interruption),
|
|
2999
|
+
continuation: taskSummaryFrom(result.continuation)
|
|
3000
|
+
};
|
|
3001
|
+
}
|
|
3002
|
+
var DEFAULT_LIMIT = 100;
|
|
3003
|
+
var listContextsInputSchema = z.object({
|
|
3004
|
+
status: z.enum(["active", "archived"]).optional().describe("\u7701\u7565\u6642\u306F active \u306E\u307F"),
|
|
3005
|
+
limit: z.number().int().positive().max(1e3).optional().describe(`\u8FD4\u5374\u4EF6\u6570\u306E\u4E0A\u9650 (default ${DEFAULT_LIMIT})`)
|
|
3006
|
+
});
|
|
3007
|
+
async function listContextsHandler(ctx, input) {
|
|
3008
|
+
const limit = input.limit ?? DEFAULT_LIMIT;
|
|
3009
|
+
const filter = input.status === void 0 ? { status: "active" } : { status: input.status };
|
|
3010
|
+
const all = await ctx.repos.context.findAll(filter);
|
|
3011
|
+
const truncated = all.length > limit;
|
|
3012
|
+
const contexts = (truncated ? all.slice(0, limit) : all).map(contextSummaryFrom);
|
|
3013
|
+
return { contexts, total: all.length, truncated };
|
|
3014
|
+
}
|
|
3015
|
+
var DEFAULT_LIMIT2 = 100;
|
|
3016
|
+
var listProjectsInputSchema = z.object({
|
|
3017
|
+
status: z.enum(["active", "archived"]).optional().describe('\u7701\u7565\u6642\u306F active \u306E\u307F\u3002"archived" \u3067 archived \u306E\u307F\u3001\u4E21\u65B9\u304C\u8981\u308B\u306A\u3089 2 \u56DE\u547C\u3073\u51FA\u3059'),
|
|
3018
|
+
limit: z.number().int().positive().max(1e3).optional().describe(`\u8FD4\u5374\u4EF6\u6570\u306E\u4E0A\u9650 (default ${DEFAULT_LIMIT2})`)
|
|
3019
|
+
});
|
|
3020
|
+
async function listProjectsHandler(ctx, input) {
|
|
3021
|
+
const limit = input.limit ?? DEFAULT_LIMIT2;
|
|
3022
|
+
const filter = input.status === void 0 ? { status: "active" } : { status: input.status };
|
|
3023
|
+
const all = await ctx.repos.project.findAll(filter);
|
|
3024
|
+
const truncated = all.length > limit;
|
|
3025
|
+
const projects = (truncated ? all.slice(0, limit) : all).map(projectSummaryFrom);
|
|
3026
|
+
return { projects, total: all.length, truncated };
|
|
3027
|
+
}
|
|
3028
|
+
var DEFAULT_DAYS = 90;
|
|
3029
|
+
var DEFAULT_LIMIT3 = 100;
|
|
3030
|
+
var listRecentTasksInputSchema = z.object({
|
|
3031
|
+
days: z.number().int().positive().max(365).optional().describe(`\u4ECA\u65E5\u304B\u3089\u9061\u308B\u65E5\u6570 (default ${DEFAULT_DAYS})`),
|
|
3032
|
+
query: z.string().optional().describe("\u6307\u5B9A\u3059\u308B\u3068 fuzzy match \u3067\u985E\u4F3C\u30BF\u30A4\u30C8\u30EB\u3092\u4E0A\u4F4D\u306B\u8FD4\u3059\u3002\u3072\u3089\u304C\u306A\u2194\u30AB\u30BF\u30AB\u30CA\u6B63\u898F\u5316\u8FBC\u307F"),
|
|
3033
|
+
limit: z.number().int().positive().max(1e3).optional().describe(`\u8FD4\u5374\u4EF6\u6570\u306E\u4E0A\u9650 (default ${DEFAULT_LIMIT3})`)
|
|
3034
|
+
});
|
|
3035
|
+
async function listRecentTasksHandler(ctx, input) {
|
|
3036
|
+
const days = input.days ?? DEFAULT_DAYS;
|
|
3037
|
+
const limit = input.limit ?? DEFAULT_LIMIT3;
|
|
3038
|
+
const today = todayDateString();
|
|
3039
|
+
const fromDate = (() => {
|
|
3040
|
+
const d = fromDateString(today);
|
|
3041
|
+
d.setDate(d.getDate() - days);
|
|
3042
|
+
return toDateString(d);
|
|
3043
|
+
})();
|
|
3044
|
+
const all = await ctx.repos.task.findFromDate(fromDate);
|
|
3045
|
+
const ordered = input.query ? findSimilarTasks(input.query, all, limit) : [...all].sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());
|
|
3046
|
+
const truncated = ordered.length > limit;
|
|
3047
|
+
const tasks = (truncated ? ordered.slice(0, limit) : ordered).map(taskSummaryFrom);
|
|
3048
|
+
return { tasks, total: ordered.length, truncated };
|
|
3049
|
+
}
|
|
3050
|
+
var DEFAULT_LIMIT4 = 100;
|
|
3051
|
+
var listRoutinesInputSchema = z.object({
|
|
3052
|
+
status: z.enum(["active", "paused", "archived"]).optional().describe('\u7701\u7565\u6642\u306F active \u306E\u307F\u3002"paused" \u306F\u4E00\u6642\u505C\u6B62\u4E2D (\u5C55\u958B\u505C\u6B62), "archived" \u306F\u5B8C\u5168\u505C\u6B62'),
|
|
3053
|
+
limit: z.number().int().positive().max(1e3).optional().describe(`\u8FD4\u5374\u4EF6\u6570\u306E\u4E0A\u9650 (default ${DEFAULT_LIMIT4})`)
|
|
3054
|
+
});
|
|
3055
|
+
async function listRoutinesHandler(ctx, input) {
|
|
3056
|
+
const limit = input.limit ?? DEFAULT_LIMIT4;
|
|
3057
|
+
const filter = input.status === void 0 ? { status: "active" } : { status: input.status };
|
|
3058
|
+
const all = await ctx.repos.routine.findAll(filter);
|
|
3059
|
+
const truncated = all.length > limit;
|
|
3060
|
+
const routines = (truncated ? all.slice(0, limit) : all).map(routineSummaryFrom);
|
|
3061
|
+
return { routines, total: all.length, truncated };
|
|
3062
|
+
}
|
|
3063
|
+
var DEFAULT_LIMIT5 = 100;
|
|
3064
|
+
var listTagsInputSchema = z.object({
|
|
3065
|
+
status: z.enum(["active", "archived"]).optional().describe("\u7701\u7565\u6642\u306F active \u306E\u307F"),
|
|
3066
|
+
limit: z.number().int().positive().max(1e3).optional().describe(`\u8FD4\u5374\u4EF6\u6570\u306E\u4E0A\u9650 (default ${DEFAULT_LIMIT5})`)
|
|
3067
|
+
});
|
|
3068
|
+
async function listTagsHandler(ctx, input) {
|
|
3069
|
+
const limit = input.limit ?? DEFAULT_LIMIT5;
|
|
3070
|
+
const filter = input.status === void 0 ? { status: "active" } : { status: input.status };
|
|
3071
|
+
const all = await ctx.repos.tag.findAll(filter);
|
|
3072
|
+
const truncated = all.length > limit;
|
|
3073
|
+
const tags = (truncated ? all.slice(0, limit) : all).map(tagSummaryFrom);
|
|
3074
|
+
return { tags, total: all.length, truncated };
|
|
3075
|
+
}
|
|
2072
3076
|
var listTasksInputSchema = z.object({
|
|
2073
3077
|
date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "date must be YYYY-MM-DD").optional().describe("\u5BFE\u8C61\u65E5 (YYYY-MM-DD)\u3002\u7701\u7565\u6642\u306F\u30B5\u30FC\u30D0\u30FC\u306E\u4ECA\u65E5 (Asia/Tokyo) \u3092\u4F7F\u3046")
|
|
2074
3078
|
});
|
|
@@ -2077,6 +3081,19 @@ async function listTasksHandler(ctx, input) {
|
|
|
2077
3081
|
const tasks = await ctx.repos.task.findByDate(date);
|
|
2078
3082
|
return { date, tasks: tasks.map(taskSummaryFrom) };
|
|
2079
3083
|
}
|
|
3084
|
+
var DEFAULT_LIMIT6 = 100;
|
|
3085
|
+
var listTimeBlocksInputSchema = z.object({
|
|
3086
|
+
status: z.enum(["active", "archived"]).optional().describe("\u7701\u7565\u6642\u306F active \u306E\u307F"),
|
|
3087
|
+
limit: z.number().int().positive().max(1e3).optional().describe(`\u8FD4\u5374\u4EF6\u6570\u306E\u4E0A\u9650 (default ${DEFAULT_LIMIT6})`)
|
|
3088
|
+
});
|
|
3089
|
+
async function listTimeBlocksHandler(ctx, input) {
|
|
3090
|
+
const limit = input.limit ?? DEFAULT_LIMIT6;
|
|
3091
|
+
const filter = input.status === void 0 ? { status: "active" } : { status: input.status };
|
|
3092
|
+
const all = await ctx.repos.timeBlock.findAll(filter);
|
|
3093
|
+
const truncated = all.length > limit;
|
|
3094
|
+
const blocks = (truncated ? all.slice(0, limit) : all).map(timeBlockSummaryFrom);
|
|
3095
|
+
return { time_blocks: blocks, total: all.length, truncated };
|
|
3096
|
+
}
|
|
2080
3097
|
var pauseTaskInputSchema = z.object({
|
|
2081
3098
|
id: z.string().uuid({ message: "id must be a UUID" })
|
|
2082
3099
|
});
|
|
@@ -2088,6 +3105,68 @@ async function pauseTaskHandler(ctx, input) {
|
|
|
2088
3105
|
const updated = await pauseTask(ctx.repos.task, input.id);
|
|
2089
3106
|
return { task: taskSummaryFrom(updated) };
|
|
2090
3107
|
}
|
|
3108
|
+
var reopenTaskInputSchema = z.object({
|
|
3109
|
+
id: z.string().uuid({ message: "id must be a UUID" })
|
|
3110
|
+
});
|
|
3111
|
+
async function reopenTaskHandler(ctx, input) {
|
|
3112
|
+
const existing = await ctx.repos.task.findById(input.id);
|
|
3113
|
+
if (!existing) {
|
|
3114
|
+
throw new McpToolError(`Task not found: ${input.id}`);
|
|
3115
|
+
}
|
|
3116
|
+
const updated = await reopenTask(ctx.repos.task, input.id);
|
|
3117
|
+
return { task: taskSummaryFrom(updated) };
|
|
3118
|
+
}
|
|
3119
|
+
var reorderTaskInputSchema = z.object({
|
|
3120
|
+
id: z.string().uuid(),
|
|
3121
|
+
order_index: z.number().int(),
|
|
3122
|
+
scheduled_start_time: z.union([z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "must be HH:MM"), z.null()]).optional().describe(
|
|
3123
|
+
"\u6307\u5B9A\u3059\u308B\u3068\u540C\u6642\u306B\u66F8\u304D\u63DB\u3048\u308B\u3002null=\u672A\u5272\u5F53\u30B0\u30EB\u30FC\u30D7\u306B\u79FB\u52D5\u3002HH:MM=\u8A72\u5F53\u30D6\u30ED\u30C3\u30AF\u306B\u79FB\u52D5\u3002\u7701\u7565=\u5909\u66F4\u306A\u3057"
|
|
3124
|
+
)
|
|
3125
|
+
});
|
|
3126
|
+
async function reorderTaskHandler(ctx, input) {
|
|
3127
|
+
const existing = await ctx.repos.task.findById(input.id);
|
|
3128
|
+
if (!existing) {
|
|
3129
|
+
throw new McpToolError(`Task not found: ${input.id}`);
|
|
3130
|
+
}
|
|
3131
|
+
const patch = { orderIndex: input.order_index };
|
|
3132
|
+
if (input.scheduled_start_time !== void 0) {
|
|
3133
|
+
patch.scheduledStartTime = input.scheduled_start_time === null ? void 0 : input.scheduled_start_time;
|
|
3134
|
+
}
|
|
3135
|
+
const updated = await ctx.repos.task.update(input.id, patch);
|
|
3136
|
+
return { task: taskSummaryFrom(updated) };
|
|
3137
|
+
}
|
|
3138
|
+
var setActualTimesInputSchema = z.object({
|
|
3139
|
+
id: z.string().uuid(),
|
|
3140
|
+
start_time: z.union([z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "must be HH:MM"), z.null()]).describe("HH:MM\u3002null \u306A\u3089\u5B9F\u7E3E\u958B\u59CB\u306A\u3057\u3002end_time \u306E\u307F\u6307\u5B9A\u306F\u30A8\u30E9\u30FC"),
|
|
3141
|
+
end_time: z.union([z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "must be HH:MM"), z.null()]).describe("HH:MM\u3002null \u306A\u3089\u672A\u5B8C\u4E86 (running \u6271\u3044)")
|
|
3142
|
+
});
|
|
3143
|
+
async function setActualTimesHandler(ctx, input) {
|
|
3144
|
+
const existing = await ctx.repos.task.findById(input.id);
|
|
3145
|
+
if (!existing) {
|
|
3146
|
+
throw new McpToolError(`Task not found: ${input.id}`);
|
|
3147
|
+
}
|
|
3148
|
+
const patch = await wrapDomainErrors(
|
|
3149
|
+
() => Promise.resolve(
|
|
3150
|
+
buildSetActualTimesPatch(existing, {
|
|
3151
|
+
startTime: input.start_time,
|
|
3152
|
+
endTime: input.end_time
|
|
3153
|
+
})
|
|
3154
|
+
)
|
|
3155
|
+
);
|
|
3156
|
+
const updated = await ctx.repos.task.update(input.id, patch);
|
|
3157
|
+
return { task: taskSummaryFrom(updated) };
|
|
3158
|
+
}
|
|
3159
|
+
var skipTaskInputSchema = z.object({
|
|
3160
|
+
id: z.string().uuid({ message: "id must be a UUID" })
|
|
3161
|
+
});
|
|
3162
|
+
async function skipTaskHandler(ctx, input) {
|
|
3163
|
+
const existing = await ctx.repos.task.findById(input.id);
|
|
3164
|
+
if (!existing) {
|
|
3165
|
+
throw new McpToolError(`Task not found: ${input.id}`);
|
|
3166
|
+
}
|
|
3167
|
+
const updated = await skipTask(ctx.repos.task, input.id);
|
|
3168
|
+
return { task: taskSummaryFrom(updated) };
|
|
3169
|
+
}
|
|
2091
3170
|
var startTaskInputSchema = z.object({
|
|
2092
3171
|
id: z.string().uuid({ message: "id must be a UUID" })
|
|
2093
3172
|
});
|
|
@@ -2099,6 +3178,332 @@ async function startTaskHandler(ctx, input) {
|
|
|
2099
3178
|
const updated = await startTask(ctx.repos.task, input.id);
|
|
2100
3179
|
return { task: taskSummaryFrom(updated) };
|
|
2101
3180
|
}
|
|
3181
|
+
var updateContextInputSchema = z.object({
|
|
3182
|
+
id: z.string().uuid(),
|
|
3183
|
+
name: z.string().min(1).optional(),
|
|
3184
|
+
description: z.union([z.string(), z.null()]).optional(),
|
|
3185
|
+
icon: z.union([z.string(), z.null()]).optional(),
|
|
3186
|
+
color: z.union([z.string(), z.null()]).optional(),
|
|
3187
|
+
status: z.enum(["active", "archived"]).optional().describe("archived \u5316\u306F archive_context tool \u63A8\u5968")
|
|
3188
|
+
});
|
|
3189
|
+
async function updateContextHandler(ctx, input) {
|
|
3190
|
+
const existing = await ctx.repos.context.findById(input.id);
|
|
3191
|
+
if (!existing) {
|
|
3192
|
+
throw new McpToolError(`Context not found: ${input.id}`);
|
|
3193
|
+
}
|
|
3194
|
+
const patch = {};
|
|
3195
|
+
if (input.name !== void 0) patch.name = input.name;
|
|
3196
|
+
if (input.description !== void 0) {
|
|
3197
|
+
patch.description = input.description === null ? void 0 : input.description;
|
|
3198
|
+
}
|
|
3199
|
+
if (input.icon !== void 0) {
|
|
3200
|
+
patch.icon = input.icon === null ? void 0 : input.icon;
|
|
3201
|
+
}
|
|
3202
|
+
if (input.color !== void 0) {
|
|
3203
|
+
patch.color = input.color === null ? void 0 : input.color;
|
|
3204
|
+
}
|
|
3205
|
+
if (input.status !== void 0) patch.status = input.status;
|
|
3206
|
+
const updated = await ctx.repos.context.update(input.id, patch);
|
|
3207
|
+
return { context: contextSummaryFrom(updated) };
|
|
3208
|
+
}
|
|
3209
|
+
var updateProjectInputSchema = z.object({
|
|
3210
|
+
id: z.string().uuid(),
|
|
3211
|
+
name: z.string().min(1).optional(),
|
|
3212
|
+
description: z.union([z.string(), z.null()]).optional(),
|
|
3213
|
+
color: z.union([z.string(), z.null()]).optional(),
|
|
3214
|
+
parent_project_id: z.union([z.string().uuid(), z.null()]).optional(),
|
|
3215
|
+
goal_id: z.union([z.string().uuid(), z.null()]).optional(),
|
|
3216
|
+
started_at: z.union([z.string().datetime(), z.null()]).optional(),
|
|
3217
|
+
target_end_date: z.union([z.string().datetime(), z.null()]).optional(),
|
|
3218
|
+
status: z.enum(["active", "archived"]).optional().describe("archived \u5316\u306F archive_project tool \u63A8\u5968 (\u4E21\u65B9\u3068\u3082 archived_at \u3092\u8A2D\u5B9A\u3059\u308B)")
|
|
3219
|
+
});
|
|
3220
|
+
async function updateProjectHandler(ctx, input) {
|
|
3221
|
+
const existing = await ctx.repos.project.findById(input.id);
|
|
3222
|
+
if (!existing) {
|
|
3223
|
+
throw new McpToolError(`Project not found: ${input.id}`);
|
|
3224
|
+
}
|
|
3225
|
+
if (input.parent_project_id !== void 0 && input.parent_project_id !== null) {
|
|
3226
|
+
const parent = await ctx.repos.project.findById(input.parent_project_id);
|
|
3227
|
+
if (!parent) {
|
|
3228
|
+
throw new McpToolError(`Parent project not found: ${input.parent_project_id}`);
|
|
3229
|
+
}
|
|
3230
|
+
if (parent.id === input.id) {
|
|
3231
|
+
throw new McpToolError("A project cannot be its own parent");
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
const patch = {};
|
|
3235
|
+
if (input.name !== void 0) patch.name = input.name;
|
|
3236
|
+
if (input.description !== void 0) {
|
|
3237
|
+
patch.description = input.description === null ? void 0 : input.description;
|
|
3238
|
+
}
|
|
3239
|
+
if (input.color !== void 0) {
|
|
3240
|
+
patch.color = input.color === null ? void 0 : input.color;
|
|
3241
|
+
}
|
|
3242
|
+
if (input.parent_project_id !== void 0) {
|
|
3243
|
+
patch.parentProjectId = input.parent_project_id === null ? void 0 : input.parent_project_id;
|
|
3244
|
+
}
|
|
3245
|
+
if (input.goal_id !== void 0) {
|
|
3246
|
+
patch.goalId = input.goal_id === null ? void 0 : input.goal_id;
|
|
3247
|
+
}
|
|
3248
|
+
if (input.started_at !== void 0) {
|
|
3249
|
+
patch.startedAt = input.started_at === null ? void 0 : new Date(input.started_at);
|
|
3250
|
+
}
|
|
3251
|
+
if (input.target_end_date !== void 0) {
|
|
3252
|
+
patch.targetEndDate = input.target_end_date === null ? void 0 : new Date(input.target_end_date);
|
|
3253
|
+
}
|
|
3254
|
+
if (input.status !== void 0) patch.status = input.status;
|
|
3255
|
+
const updated = await ctx.repos.project.update(input.id, patch);
|
|
3256
|
+
return { project: projectSummaryFrom(updated) };
|
|
3257
|
+
}
|
|
3258
|
+
var frequencySchema2 = z.discriminatedUnion("type", [
|
|
3259
|
+
z.object({ type: z.literal("daily") }),
|
|
3260
|
+
z.object({
|
|
3261
|
+
type: z.literal("weekly"),
|
|
3262
|
+
weekdays: z.array(z.number().int().min(0).max(6)).min(1)
|
|
3263
|
+
}),
|
|
3264
|
+
z.object({
|
|
3265
|
+
type: z.literal("monthly"),
|
|
3266
|
+
days: z.array(z.number().int().min(1).max(31)).min(1)
|
|
3267
|
+
}),
|
|
3268
|
+
z.object({ type: z.literal("custom"), cron: z.string().min(1) })
|
|
3269
|
+
]);
|
|
3270
|
+
var updateRoutineInputSchema = z.object({
|
|
3271
|
+
id: z.string().uuid(),
|
|
3272
|
+
title: z.string().min(1).optional(),
|
|
3273
|
+
description: z.union([z.string(), z.null()]).optional(),
|
|
3274
|
+
estimated_seconds: z.number().int().positive().optional(),
|
|
3275
|
+
frequency: frequencySchema2.optional(),
|
|
3276
|
+
project_id: z.union([z.string().uuid(), z.null()]).optional(),
|
|
3277
|
+
context_id: z.union([z.string().uuid(), z.null()]).optional(),
|
|
3278
|
+
tag_ids: z.array(z.string().uuid()).optional(),
|
|
3279
|
+
default_scheduled_start_time: z.union([z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "must be HH:MM"), z.null()]).optional(),
|
|
3280
|
+
auto_expand: z.boolean().optional(),
|
|
3281
|
+
start_date: z.union([z.string().regex(/^\d{4}-\d{2}-\d{2}$/), z.null()]).optional(),
|
|
3282
|
+
end_date: z.union([z.string().regex(/^\d{4}-\d{2}-\d{2}$/), z.null()]).optional(),
|
|
3283
|
+
status: z.enum(["active", "paused", "archived"]).optional()
|
|
3284
|
+
});
|
|
3285
|
+
async function updateRoutineHandler(ctx, input) {
|
|
3286
|
+
const existing = await ctx.repos.routine.findById(input.id);
|
|
3287
|
+
if (!existing) {
|
|
3288
|
+
throw new McpToolError(`Routine not found: ${input.id}`);
|
|
3289
|
+
}
|
|
3290
|
+
if (input.project_id !== void 0 && input.project_id !== null) {
|
|
3291
|
+
const p = await ctx.repos.project.findById(input.project_id);
|
|
3292
|
+
if (!p) throw new McpToolError(`Project not found: ${input.project_id}`);
|
|
3293
|
+
}
|
|
3294
|
+
if (input.context_id !== void 0 && input.context_id !== null) {
|
|
3295
|
+
const c = await ctx.repos.context.findById(input.context_id);
|
|
3296
|
+
if (!c) throw new McpToolError(`Context not found: ${input.context_id}`);
|
|
3297
|
+
}
|
|
3298
|
+
if (input.tag_ids !== void 0 && input.tag_ids.length > 0) {
|
|
3299
|
+
const checked = await Promise.all(
|
|
3300
|
+
input.tag_ids.map(async (id) => ({
|
|
3301
|
+
id,
|
|
3302
|
+
exists: await ctx.repos.tag.findById(id) !== null
|
|
3303
|
+
}))
|
|
3304
|
+
);
|
|
3305
|
+
const missing = checked.filter((c) => !c.exists).map((c) => c.id);
|
|
3306
|
+
if (missing.length > 0) throw new McpToolError(`Tag(s) not found: ${missing.join(", ")}`);
|
|
3307
|
+
}
|
|
3308
|
+
const patch = {};
|
|
3309
|
+
if (input.title !== void 0) patch.title = input.title;
|
|
3310
|
+
if (input.description !== void 0) {
|
|
3311
|
+
patch.description = input.description === null ? void 0 : input.description;
|
|
3312
|
+
}
|
|
3313
|
+
if (input.estimated_seconds !== void 0) patch.estimatedSeconds = input.estimated_seconds;
|
|
3314
|
+
if (input.frequency !== void 0) patch.frequency = input.frequency;
|
|
3315
|
+
if (input.project_id !== void 0) {
|
|
3316
|
+
patch.projectId = input.project_id === null ? void 0 : input.project_id;
|
|
3317
|
+
}
|
|
3318
|
+
if (input.context_id !== void 0) {
|
|
3319
|
+
patch.contextId = input.context_id === null ? void 0 : input.context_id;
|
|
3320
|
+
}
|
|
3321
|
+
if (input.tag_ids !== void 0) patch.tagIds = input.tag_ids;
|
|
3322
|
+
if (input.default_scheduled_start_time !== void 0) {
|
|
3323
|
+
patch.defaultScheduledStartTime = input.default_scheduled_start_time === null ? void 0 : input.default_scheduled_start_time;
|
|
3324
|
+
}
|
|
3325
|
+
if (input.auto_expand !== void 0) patch.autoExpand = input.auto_expand;
|
|
3326
|
+
if (input.start_date !== void 0) {
|
|
3327
|
+
patch.startDate = input.start_date === null ? void 0 : input.start_date;
|
|
3328
|
+
}
|
|
3329
|
+
if (input.end_date !== void 0) {
|
|
3330
|
+
patch.endDate = input.end_date === null ? void 0 : input.end_date;
|
|
3331
|
+
}
|
|
3332
|
+
if (input.status !== void 0) patch.status = input.status;
|
|
3333
|
+
const updated = await ctx.repos.routine.update(input.id, patch);
|
|
3334
|
+
const today = todayDateString();
|
|
3335
|
+
const futureTasks = await ctx.repos.task.findByRoutineIdFromDate(input.id, today);
|
|
3336
|
+
const targets = pickPropagationTargets(updated, futureTasks, today);
|
|
3337
|
+
if (targets.length > 0) {
|
|
3338
|
+
const { auditingTask } = ctx.repos;
|
|
3339
|
+
if (!auditingTask) {
|
|
3340
|
+
throw new McpToolError(
|
|
3341
|
+
"auditingTask is not configured. Routine propagation requires audit lookups to be enabled (createNodeAppContext sets this up automatically)."
|
|
3342
|
+
);
|
|
3343
|
+
}
|
|
3344
|
+
const taskPatch = buildRoutineTaskPatch(updated);
|
|
3345
|
+
await Promise.all(
|
|
3346
|
+
targets.map(
|
|
3347
|
+
(task) => auditingTask.updateWithCause(task.id, taskPatch, "routine-propagation")
|
|
3348
|
+
)
|
|
3349
|
+
);
|
|
3350
|
+
}
|
|
3351
|
+
return {
|
|
3352
|
+
routine: routineSummaryFrom(updated),
|
|
3353
|
+
propagated_task_count: targets.length
|
|
3354
|
+
};
|
|
3355
|
+
}
|
|
3356
|
+
var updateTagInputSchema = z.object({
|
|
3357
|
+
id: z.string().uuid(),
|
|
3358
|
+
name: z.string().min(1).optional(),
|
|
3359
|
+
description: z.union([z.string(), z.null()]).optional(),
|
|
3360
|
+
color: z.union([z.string(), z.null()]).optional(),
|
|
3361
|
+
status: z.enum(["active", "archived"]).optional().describe("archived \u5316\u306F archive_tag tool \u63A8\u5968")
|
|
3362
|
+
});
|
|
3363
|
+
async function updateTagHandler(ctx, input) {
|
|
3364
|
+
const existing = await ctx.repos.tag.findById(input.id);
|
|
3365
|
+
if (!existing) {
|
|
3366
|
+
throw new McpToolError(`Tag not found: ${input.id}`);
|
|
3367
|
+
}
|
|
3368
|
+
const patch = {};
|
|
3369
|
+
if (input.name !== void 0) patch.name = input.name;
|
|
3370
|
+
if (input.description !== void 0) {
|
|
3371
|
+
patch.description = input.description === null ? void 0 : input.description;
|
|
3372
|
+
}
|
|
3373
|
+
if (input.color !== void 0) {
|
|
3374
|
+
patch.color = input.color === null ? void 0 : input.color;
|
|
3375
|
+
}
|
|
3376
|
+
if (input.status !== void 0) patch.status = input.status;
|
|
3377
|
+
const updated = await ctx.repos.tag.update(input.id, patch);
|
|
3378
|
+
return { tag: tagSummaryFrom(updated) };
|
|
3379
|
+
}
|
|
3380
|
+
var updateTaskInputSchema = z.object({
|
|
3381
|
+
id: z.string().uuid({ message: "id must be a UUID" }),
|
|
3382
|
+
title: z.string().min(1).optional(),
|
|
3383
|
+
description: z.union([z.string(), z.null()]).optional(),
|
|
3384
|
+
estimated_seconds: z.number().int().positive().optional(),
|
|
3385
|
+
scheduled_start_time: z.union([z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "must be HH:MM"), z.null()]).optional(),
|
|
3386
|
+
project_id: z.union([z.string().uuid(), z.null()]).optional(),
|
|
3387
|
+
context_id: z.union([z.string().uuid(), z.null()]).optional(),
|
|
3388
|
+
tag_ids: z.array(z.string().uuid()).optional(),
|
|
3389
|
+
notify_at_scheduled_start: z.boolean().optional(),
|
|
3390
|
+
is_background: z.boolean().optional()
|
|
3391
|
+
});
|
|
3392
|
+
async function validateReferences(ctx, refs) {
|
|
3393
|
+
if (refs.projectId) {
|
|
3394
|
+
const project = await ctx.repos.project.findById(refs.projectId);
|
|
3395
|
+
if (!project) throw new McpToolError(`Project not found: ${refs.projectId}`);
|
|
3396
|
+
}
|
|
3397
|
+
if (refs.contextId) {
|
|
3398
|
+
const context = await ctx.repos.context.findById(refs.contextId);
|
|
3399
|
+
if (!context) throw new McpToolError(`Context not found: ${refs.contextId}`);
|
|
3400
|
+
}
|
|
3401
|
+
if (refs.tagIds && refs.tagIds.length > 0) {
|
|
3402
|
+
const checked = await Promise.all(
|
|
3403
|
+
refs.tagIds.map(async (id) => ({ id, exists: await ctx.repos.tag.findById(id) !== null }))
|
|
3404
|
+
);
|
|
3405
|
+
const missing = checked.filter((c) => !c.exists).map((c) => c.id);
|
|
3406
|
+
if (missing.length > 0) {
|
|
3407
|
+
throw new McpToolError(`Tag(s) not found: ${missing.join(", ")}`);
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
}
|
|
3411
|
+
async function updateTaskHandler(ctx, input) {
|
|
3412
|
+
const existing = await ctx.repos.task.findById(input.id);
|
|
3413
|
+
if (!existing) {
|
|
3414
|
+
throw new McpToolError(`Task not found: ${input.id}`);
|
|
3415
|
+
}
|
|
3416
|
+
await validateReferences(ctx, {
|
|
3417
|
+
projectId: input.project_id ?? void 0,
|
|
3418
|
+
contextId: input.context_id ?? void 0,
|
|
3419
|
+
tagIds: input.tag_ids
|
|
3420
|
+
});
|
|
3421
|
+
const patch = {};
|
|
3422
|
+
if (input.title !== void 0) patch.title = input.title;
|
|
3423
|
+
if (input.description !== void 0) {
|
|
3424
|
+
patch.description = input.description === null ? void 0 : input.description;
|
|
3425
|
+
}
|
|
3426
|
+
if (input.estimated_seconds !== void 0) patch.estimatedSeconds = input.estimated_seconds;
|
|
3427
|
+
if (input.scheduled_start_time !== void 0) {
|
|
3428
|
+
patch.scheduledStartTime = input.scheduled_start_time === null ? void 0 : input.scheduled_start_time;
|
|
3429
|
+
}
|
|
3430
|
+
if (input.project_id !== void 0) {
|
|
3431
|
+
patch.projectId = input.project_id === null ? void 0 : input.project_id;
|
|
3432
|
+
}
|
|
3433
|
+
if (input.context_id !== void 0) {
|
|
3434
|
+
patch.contextId = input.context_id === null ? void 0 : input.context_id;
|
|
3435
|
+
}
|
|
3436
|
+
if (input.tag_ids !== void 0) patch.tagIds = input.tag_ids;
|
|
3437
|
+
if (input.notify_at_scheduled_start !== void 0) {
|
|
3438
|
+
patch.notifyAtScheduledStart = input.notify_at_scheduled_start;
|
|
3439
|
+
}
|
|
3440
|
+
if (input.is_background !== void 0) patch.isBackground = input.is_background;
|
|
3441
|
+
const updated = await ctx.repos.task.update(input.id, patch);
|
|
3442
|
+
return { task: taskSummaryFrom(updated) };
|
|
3443
|
+
}
|
|
3444
|
+
var HHMM2 = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
3445
|
+
var updateTimeBlockInputSchema = z.object({
|
|
3446
|
+
id: z.string().uuid(),
|
|
3447
|
+
name: z.string().min(1).optional(),
|
|
3448
|
+
start_time: z.string().regex(HHMM2, "start_time must be HH:MM").optional(),
|
|
3449
|
+
end_time: z.string().regex(HHMM2, "end_time must be HH:MM").optional(),
|
|
3450
|
+
weekdays: z.array(z.number().int().min(0).max(6)).min(1).optional(),
|
|
3451
|
+
default_project_id: z.union([z.string().uuid(), z.null()]).optional(),
|
|
3452
|
+
default_context_id: z.union([z.string().uuid(), z.null()]).optional(),
|
|
3453
|
+
default_tag_ids: z.array(z.string().uuid()).optional(),
|
|
3454
|
+
color: z.union([z.string(), z.null()]).optional(),
|
|
3455
|
+
start_date: z.union([z.string().regex(/^\d{4}-\d{2}-\d{2}$/), z.null()]).optional(),
|
|
3456
|
+
end_date: z.union([z.string().regex(/^\d{4}-\d{2}-\d{2}$/), z.null()]).optional(),
|
|
3457
|
+
status: z.enum(["active", "archived"]).optional()
|
|
3458
|
+
});
|
|
3459
|
+
async function updateTimeBlockHandler(ctx, input) {
|
|
3460
|
+
const existing = await ctx.repos.timeBlock.findById(input.id);
|
|
3461
|
+
if (!existing) {
|
|
3462
|
+
throw new McpToolError(`TimeBlock not found: ${input.id}`);
|
|
3463
|
+
}
|
|
3464
|
+
if (input.default_project_id !== void 0 && input.default_project_id !== null) {
|
|
3465
|
+
const p = await ctx.repos.project.findById(input.default_project_id);
|
|
3466
|
+
if (!p) throw new McpToolError(`Project not found: ${input.default_project_id}`);
|
|
3467
|
+
}
|
|
3468
|
+
if (input.default_context_id !== void 0 && input.default_context_id !== null) {
|
|
3469
|
+
const c = await ctx.repos.context.findById(input.default_context_id);
|
|
3470
|
+
if (!c) throw new McpToolError(`Context not found: ${input.default_context_id}`);
|
|
3471
|
+
}
|
|
3472
|
+
if (input.default_tag_ids !== void 0 && input.default_tag_ids.length > 0) {
|
|
3473
|
+
const checked = await Promise.all(
|
|
3474
|
+
input.default_tag_ids.map(async (id) => ({
|
|
3475
|
+
id,
|
|
3476
|
+
exists: await ctx.repos.tag.findById(id) !== null
|
|
3477
|
+
}))
|
|
3478
|
+
);
|
|
3479
|
+
const missing = checked.filter((c) => !c.exists).map((c) => c.id);
|
|
3480
|
+
if (missing.length > 0) throw new McpToolError(`Tag(s) not found: ${missing.join(", ")}`);
|
|
3481
|
+
}
|
|
3482
|
+
const patch = {};
|
|
3483
|
+
if (input.name !== void 0) patch.name = input.name;
|
|
3484
|
+
if (input.start_time !== void 0) patch.startTime = input.start_time;
|
|
3485
|
+
if (input.end_time !== void 0) patch.endTime = input.end_time;
|
|
3486
|
+
if (input.weekdays !== void 0) patch.weekdays = input.weekdays;
|
|
3487
|
+
if (input.default_project_id !== void 0) {
|
|
3488
|
+
patch.defaultProjectId = input.default_project_id === null ? void 0 : input.default_project_id;
|
|
3489
|
+
}
|
|
3490
|
+
if (input.default_context_id !== void 0) {
|
|
3491
|
+
patch.defaultContextId = input.default_context_id === null ? void 0 : input.default_context_id;
|
|
3492
|
+
}
|
|
3493
|
+
if (input.default_tag_ids !== void 0) patch.defaultTagIds = input.default_tag_ids;
|
|
3494
|
+
if (input.color !== void 0) {
|
|
3495
|
+
patch.color = input.color === null ? void 0 : input.color;
|
|
3496
|
+
}
|
|
3497
|
+
if (input.start_date !== void 0) {
|
|
3498
|
+
patch.startDate = input.start_date === null ? void 0 : input.start_date;
|
|
3499
|
+
}
|
|
3500
|
+
if (input.end_date !== void 0) {
|
|
3501
|
+
patch.endDate = input.end_date === null ? void 0 : input.end_date;
|
|
3502
|
+
}
|
|
3503
|
+
if (input.status !== void 0) patch.status = input.status;
|
|
3504
|
+
const updated = await ctx.repos.timeBlock.update(input.id, patch);
|
|
3505
|
+
return { time_block: timeBlockSummaryFrom(updated) };
|
|
3506
|
+
}
|
|
2102
3507
|
|
|
2103
3508
|
// src/server.ts
|
|
2104
3509
|
function createDefaultContextFactory() {
|
|
@@ -2144,11 +3549,29 @@ function createMcpServer(opts) {
|
|
|
2144
3549
|
"add_task",
|
|
2145
3550
|
{
|
|
2146
3551
|
title: "Add task",
|
|
2147
|
-
description: "\u30BF\u30B9\u30AF\u3092\u8FFD\u52A0\u3059\u308B\u3002\u65E5\u4ED8\u7701\u7565\u6642\u306F\u4ECA\u65E5\u3002estimated_seconds \u7701\u7565\u6642\u306F 1800 (30 \u5206)\u3002",
|
|
3552
|
+
description: "\u30BF\u30B9\u30AF\u3092\u8FFD\u52A0\u3059\u308B\u3002\u65E5\u4ED8\u7701\u7565\u6642\u306F\u4ECA\u65E5\u3002estimated_seconds \u7701\u7565\u6642\u306F 1800 (30 \u5206)\u3002project_id / context_id / tag_ids \u306F\u4E8B\u524D\u306B list_projects / list_contexts / list_tags \u3067\u53D6\u5F97\u3057\u305F UUID \u3092\u6E21\u3059\u3002",
|
|
2148
3553
|
inputSchema: addTaskInputSchema.shape
|
|
2149
3554
|
},
|
|
2150
3555
|
async (input) => wrapHandler(ctxFactory, addTaskHandler, input)
|
|
2151
3556
|
);
|
|
3557
|
+
server.registerTool(
|
|
3558
|
+
"update_task",
|
|
3559
|
+
{
|
|
3560
|
+
title: "Update task",
|
|
3561
|
+
description: "\u30BF\u30B9\u30AF\u306E\u30E6\u30FC\u30B6\u30FC\u7DE8\u96C6\u53EF\u80FD\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u90E8\u5206\u66F4\u65B0\u3059\u308B\u3002undefined \u306F\u5909\u66F4\u306A\u3057\u3001null \u306F\u660E\u793A\u30AF\u30EA\u30A2\u3002status / order_index / actual_start_time \u7B49\u306E\u30B7\u30B9\u30C6\u30E0\u30D5\u30A3\u30FC\u30EB\u30C9\u306F\u5225 tool (start/pause/done/skip/reopen/reorder) \u7D4C\u7531\u3067\u5909\u66F4\u3059\u308B\u3002tag_ids \u306F\u5168\u7F6E\u63DB\u3002",
|
|
3562
|
+
inputSchema: updateTaskInputSchema.shape
|
|
3563
|
+
},
|
|
3564
|
+
async (input) => wrapHandler(ctxFactory, updateTaskHandler, input)
|
|
3565
|
+
);
|
|
3566
|
+
server.registerTool(
|
|
3567
|
+
"delete_task",
|
|
3568
|
+
{
|
|
3569
|
+
title: "Delete task",
|
|
3570
|
+
description: "\u30BF\u30B9\u30AF\u3092\u524A\u9664\u3059\u308B\u3002Routine \u7531\u6765\u30BF\u30B9\u30AF\u3092\u4ECA\u65E5\u4EE5\u964D\u306B\u6D88\u3059\u5834\u5408\u306F routine_expansions \u306B skip \u8A18\u9332\u3059\u308B (default)\u3002hard_delete: true \u306A\u3089\u7269\u7406\u524A\u9664\u306E\u307F\u3067\u3001\u6B21\u306E reload \u3067\u518D\u5C55\u958B\u3055\u308C\u308B (\u4E0A\u7D1A\u8005\u5411\u3051)\u3002",
|
|
3571
|
+
inputSchema: deleteTaskInputSchema.shape
|
|
3572
|
+
},
|
|
3573
|
+
async (input) => wrapHandler(ctxFactory, deleteTaskHandler, input)
|
|
3574
|
+
);
|
|
2152
3575
|
server.registerTool(
|
|
2153
3576
|
"start_task",
|
|
2154
3577
|
{
|
|
@@ -2176,12 +3599,300 @@ function createMcpServer(opts) {
|
|
|
2176
3599
|
},
|
|
2177
3600
|
async (input) => wrapHandler(ctxFactory, doneTaskHandler, input)
|
|
2178
3601
|
);
|
|
3602
|
+
server.registerTool(
|
|
3603
|
+
"skip_task",
|
|
3604
|
+
{
|
|
3605
|
+
title: "Skip task",
|
|
3606
|
+
description: "\u30BF\u30B9\u30AF\u3092 skipped \u306B\u9077\u79FB\u3055\u305B\u308B (\u3084\u3089\u306A\u3044\u3053\u3068\u304C\u6C7A\u307E\u3063\u305F\u30BF\u30B9\u30AF\u7528)\u3002reopen_task \u3067 planned \u306B\u623B\u305B\u308B\u3002",
|
|
3607
|
+
inputSchema: skipTaskInputSchema.shape
|
|
3608
|
+
},
|
|
3609
|
+
async (input) => wrapHandler(ctxFactory, skipTaskHandler, input)
|
|
3610
|
+
);
|
|
3611
|
+
server.registerTool(
|
|
3612
|
+
"reopen_task",
|
|
3613
|
+
{
|
|
3614
|
+
title: "Reopen task",
|
|
3615
|
+
description: "completed / skipped \u306E\u30BF\u30B9\u30AF\u3092 planned \u306B\u623B\u3059\u3002planned/running/paused \u306E\u3068\u304D\u306F no-op\u3002",
|
|
3616
|
+
inputSchema: reopenTaskInputSchema.shape
|
|
3617
|
+
},
|
|
3618
|
+
async (input) => wrapHandler(ctxFactory, reopenTaskHandler, input)
|
|
3619
|
+
);
|
|
3620
|
+
server.registerTool(
|
|
3621
|
+
"list_projects",
|
|
3622
|
+
{
|
|
3623
|
+
title: "List projects",
|
|
3624
|
+
description: "\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u4E00\u89A7\u3092\u8FD4\u3059\u3002`add_task` / `update_task` \u306E `project_id` \u306B\u6E21\u3059 UUID \u3092\u53D6\u5F97\u3059\u308B\u305F\u3081\u306B\u4F7F\u3046\u3002\u65E2\u5B9A\u306F active \u306E\u307F\u3001`status: archived` \u3067 archived \u3082\u53D6\u5F97\u53EF\u80FD\u3002`limit` \u65E2\u5B9A 100\u3002",
|
|
3625
|
+
inputSchema: listProjectsInputSchema.shape
|
|
3626
|
+
},
|
|
3627
|
+
async (input) => wrapHandler(ctxFactory, listProjectsHandler, input)
|
|
3628
|
+
);
|
|
3629
|
+
server.registerTool(
|
|
3630
|
+
"list_tags",
|
|
3631
|
+
{
|
|
3632
|
+
title: "List tags",
|
|
3633
|
+
description: "\u30BF\u30B0\u4E00\u89A7\u3092\u8FD4\u3059\u3002`add_task` / `update_task` \u306E `tag_ids` \u306B\u6E21\u3059 UUID \u3092\u53D6\u5F97\u3059\u308B\u305F\u3081\u306B\u4F7F\u3046\u3002`limit` \u65E2\u5B9A 100\u3002",
|
|
3634
|
+
inputSchema: listTagsInputSchema.shape
|
|
3635
|
+
},
|
|
3636
|
+
async (input) => wrapHandler(ctxFactory, listTagsHandler, input)
|
|
3637
|
+
);
|
|
3638
|
+
server.registerTool(
|
|
3639
|
+
"list_contexts",
|
|
3640
|
+
{
|
|
3641
|
+
title: "List contexts",
|
|
3642
|
+
description: "\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8 (\u4F5C\u696D\u74B0\u5883\u30BF\u30B0\u3002\u4F8B: home / office / mobile) \u4E00\u89A7\u3092\u8FD4\u3059\u3002`add_task` / `update_task` \u306E `context_id` \u306B\u6E21\u3059 UUID \u3092\u53D6\u5F97\u3059\u308B\u305F\u3081\u306B\u4F7F\u3046\u3002`limit` \u65E2\u5B9A 100\u3002",
|
|
3643
|
+
inputSchema: listContextsInputSchema.shape
|
|
3644
|
+
},
|
|
3645
|
+
async (input) => wrapHandler(ctxFactory, listContextsHandler, input)
|
|
3646
|
+
);
|
|
3647
|
+
server.registerTool(
|
|
3648
|
+
"list_routines",
|
|
3649
|
+
{
|
|
3650
|
+
title: "List routines",
|
|
3651
|
+
description: '\u7E70\u308A\u8FD4\u3057\u30BF\u30B9\u30AF\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8 (\u30EB\u30FC\u30C1\u30F3) \u4E00\u89A7\u3092\u8FD4\u3059\u3002`frequency` \u306F discriminated union (`{type: "daily"}` / `{type: "weekly", weekdays: [1,3,5]}` \u7B49) \u306E\u307E\u307E\u3002`limit` \u65E2\u5B9A 100\u3002',
|
|
3652
|
+
inputSchema: listRoutinesInputSchema.shape
|
|
3653
|
+
},
|
|
3654
|
+
async (input) => wrapHandler(ctxFactory, listRoutinesHandler, input)
|
|
3655
|
+
);
|
|
3656
|
+
server.registerTool(
|
|
3657
|
+
"list_time_blocks",
|
|
3658
|
+
{
|
|
3659
|
+
title: "List time blocks",
|
|
3660
|
+
description: "\u30BF\u30A4\u30E0\u30D6\u30ED\u30C3\u30AF (\u6642\u9593\u5E2F\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3002\u4F8B: \u671D\u306E\u96C6\u4E2D\u6642\u9593 09:00-12:00) \u4E00\u89A7\u3092\u8FD4\u3059\u3002`limit` \u65E2\u5B9A 100\u3002",
|
|
3661
|
+
inputSchema: listTimeBlocksInputSchema.shape
|
|
3662
|
+
},
|
|
3663
|
+
async (input) => wrapHandler(ctxFactory, listTimeBlocksHandler, input)
|
|
3664
|
+
);
|
|
3665
|
+
server.registerTool(
|
|
3666
|
+
"list_recent_tasks",
|
|
3667
|
+
{
|
|
3668
|
+
title: "List recent tasks",
|
|
3669
|
+
description: "\u904E\u53BB N \u65E5 (\u65E2\u5B9A 90) \u306E\u30BF\u30B9\u30AF\u3092\u8FD4\u3059\u3002`query` \u3092\u6307\u5B9A\u3059\u308B\u3068 fuzzy match \u3067\u985E\u4F3C\u30BF\u30A4\u30C8\u30EB\u4E0A\u4F4D\u3092\u8FD4\u3059 (\u3072\u3089\u304C\u306A\u2194\u30AB\u30BF\u30AB\u30CA\u6B63\u898F\u5316\u8FBC\u307F)\u3002\u300C\u6700\u8FD1\u3084\u3063\u305F\u4F3C\u305F\u30BF\u30B9\u30AF\u3092\u53C2\u8003\u306B\u65B0\u3057\u3044\u30BF\u30B9\u30AF\u3092\u4F5C\u3063\u3066\u300D\u306E\u3088\u3046\u306A AI \u64CD\u4F5C\u5411\u3051\u3002`limit` \u65E2\u5B9A 100\u3002",
|
|
3670
|
+
inputSchema: listRecentTasksInputSchema.shape
|
|
3671
|
+
},
|
|
3672
|
+
async (input) => wrapHandler(ctxFactory, listRecentTasksHandler, input)
|
|
3673
|
+
);
|
|
3674
|
+
server.registerTool(
|
|
3675
|
+
"create_project",
|
|
3676
|
+
{
|
|
3677
|
+
title: "Create project",
|
|
3678
|
+
description: "\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u65B0\u898F\u4F5C\u6210\u3059\u308B\u3002`name` \u5FC5\u9808\u3001`status` \u306F active \u56FA\u5B9A\u3002`parent_project_id` \u3092\u6307\u5B9A\u3059\u308B\u3068\u30B5\u30D6\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3002",
|
|
3679
|
+
inputSchema: createProjectInputSchema.shape
|
|
3680
|
+
},
|
|
3681
|
+
async (input) => wrapHandler(ctxFactory, createProjectHandler, input)
|
|
3682
|
+
);
|
|
3683
|
+
server.registerTool(
|
|
3684
|
+
"update_project",
|
|
3685
|
+
{
|
|
3686
|
+
title: "Update project",
|
|
3687
|
+
description: "\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u90E8\u5206\u66F4\u65B0\u3059\u308B\u3002undefined=\u5909\u66F4\u306A\u3057\u3001null=\u660E\u793A\u30AF\u30EA\u30A2\u3002`status` \u306E archived \u5316\u306F archive_project tool \u63A8\u5968\u3002\u81EA\u5206\u81EA\u8EAB\u3092 parent \u306B\u3057\u3088\u3046\u3068\u3059\u308B\u3068\u30A8\u30E9\u30FC\u3002",
|
|
3688
|
+
inputSchema: updateProjectInputSchema.shape
|
|
3689
|
+
},
|
|
3690
|
+
async (input) => wrapHandler(ctxFactory, updateProjectHandler, input)
|
|
3691
|
+
);
|
|
3692
|
+
server.registerTool(
|
|
3693
|
+
"archive_project",
|
|
3694
|
+
{
|
|
3695
|
+
title: "Archive project",
|
|
3696
|
+
description: "\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u30A2\u30FC\u30AB\u30A4\u30D6\u3059\u308B (status=archived + archived_at \u30BB\u30C3\u30C8)\u3002\u95A2\u9023\u30BF\u30B9\u30AF\u306E project_id \u306F\u7DAD\u6301\u3055\u308C\u308B\u306E\u3067\u3001\u904E\u53BB\u5C65\u6B74\u304C\u8AAD\u3081\u308B\u3002\u901A\u5E38\u306F delete \u3088\u308A archive \u3092\u63A8\u5968\u3002",
|
|
3697
|
+
inputSchema: archiveProjectInputSchema.shape
|
|
3698
|
+
},
|
|
3699
|
+
async (input) => wrapHandler(ctxFactory, archiveProjectHandler, input)
|
|
3700
|
+
);
|
|
3701
|
+
server.registerTool(
|
|
3702
|
+
"delete_project",
|
|
3703
|
+
{
|
|
3704
|
+
title: "Delete project",
|
|
3705
|
+
description: "\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u7269\u7406\u524A\u9664\u3059\u308B\u3002\u30BF\u30B9\u30AF\u306E project_id \u306F NULL \u5316 (ON DELETE SET NULL)\u3001\u5B50\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E parent_project_id \u3082 NULL \u5316\u3002\u904E\u53BB\u5C65\u6B74\u3092\u4FDD\u3061\u305F\u3044\u5834\u5408\u306F archive_project \u3092\u4F7F\u3046\u3002",
|
|
3706
|
+
inputSchema: deleteProjectInputSchema.shape
|
|
3707
|
+
},
|
|
3708
|
+
async (input) => wrapHandler(ctxFactory, deleteProjectHandler, input)
|
|
3709
|
+
);
|
|
3710
|
+
server.registerTool(
|
|
3711
|
+
"create_tag",
|
|
3712
|
+
{
|
|
3713
|
+
title: "Create tag",
|
|
3714
|
+
description: "\u30BF\u30B0\u3092\u65B0\u898F\u4F5C\u6210\u3059\u308B\u3002`name` \u5FC5\u9808\u3001status \u306F active \u56FA\u5B9A\u3002",
|
|
3715
|
+
inputSchema: createTagInputSchema.shape
|
|
3716
|
+
},
|
|
3717
|
+
async (input) => wrapHandler(ctxFactory, createTagHandler, input)
|
|
3718
|
+
);
|
|
3719
|
+
server.registerTool(
|
|
3720
|
+
"update_tag",
|
|
3721
|
+
{
|
|
3722
|
+
title: "Update tag",
|
|
3723
|
+
description: "\u30BF\u30B0\u3092\u90E8\u5206\u66F4\u65B0\u3059\u308B\u3002null=\u660E\u793A\u30AF\u30EA\u30A2\u3002",
|
|
3724
|
+
inputSchema: updateTagInputSchema.shape
|
|
3725
|
+
},
|
|
3726
|
+
async (input) => wrapHandler(ctxFactory, updateTagHandler, input)
|
|
3727
|
+
);
|
|
3728
|
+
server.registerTool(
|
|
3729
|
+
"archive_tag",
|
|
3730
|
+
{
|
|
3731
|
+
title: "Archive tag",
|
|
3732
|
+
description: "\u30BF\u30B0\u3092\u30A2\u30FC\u30AB\u30A4\u30D6\u3059\u308B\u3002\u30BF\u30B9\u30AF\u306E tag_ids \u914D\u5217\u306B id \u306F\u6B8B\u308B\u306E\u3067\u3001\u65E2\u5B58\u30BF\u30B9\u30AF\u306E\u30BF\u30B0\u8868\u793A\u306F\u7DAD\u6301\u3055\u308C\u308B\u3002",
|
|
3733
|
+
inputSchema: archiveTagInputSchema.shape
|
|
3734
|
+
},
|
|
3735
|
+
async (input) => wrapHandler(ctxFactory, archiveTagHandler, input)
|
|
3736
|
+
);
|
|
3737
|
+
server.registerTool(
|
|
3738
|
+
"delete_tag",
|
|
3739
|
+
{
|
|
3740
|
+
title: "Delete tag",
|
|
3741
|
+
description: "\u30BF\u30B0\u3092\u7269\u7406\u524A\u9664\u3059\u308B\u3002\u30BF\u30B9\u30AF\u306E tag_ids \u914D\u5217\u306F UUID[] \u5217\u306A\u306E\u3067\u5B64\u5150 id \u304C\u6B8B\u308B (UI \u8868\u793A\u6642\u306B\u300C\u4E0D\u660E\u306A\u30BF\u30B0\u300D\u6271\u3044)\u3002\u5C65\u6B74\u5C0A\u91CD\u306A\u3089 archive_tag \u63A8\u5968\u3002",
|
|
3742
|
+
inputSchema: deleteTagInputSchema.shape
|
|
3743
|
+
},
|
|
3744
|
+
async (input) => wrapHandler(ctxFactory, deleteTagHandler, input)
|
|
3745
|
+
);
|
|
3746
|
+
server.registerTool(
|
|
3747
|
+
"create_context",
|
|
3748
|
+
{
|
|
3749
|
+
title: "Create context",
|
|
3750
|
+
description: "\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8 (\u4F5C\u696D\u74B0\u5883\u30BF\u30B0\u3002home / office / mobile \u7B49) \u3092\u65B0\u898F\u4F5C\u6210\u3059\u308B\u3002`name` \u5FC5\u9808\u3001icon \u306F\u7D75\u6587\u5B57\u307E\u305F\u306F\u30A2\u30A4\u30B3\u30F3\u540D\u3002",
|
|
3751
|
+
inputSchema: createContextInputSchema.shape
|
|
3752
|
+
},
|
|
3753
|
+
async (input) => wrapHandler(ctxFactory, createContextHandler, input)
|
|
3754
|
+
);
|
|
3755
|
+
server.registerTool(
|
|
3756
|
+
"update_context",
|
|
3757
|
+
{
|
|
3758
|
+
title: "Update context",
|
|
3759
|
+
description: "\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u3092\u90E8\u5206\u66F4\u65B0\u3059\u308B\u3002null=\u660E\u793A\u30AF\u30EA\u30A2\u3002",
|
|
3760
|
+
inputSchema: updateContextInputSchema.shape
|
|
3761
|
+
},
|
|
3762
|
+
async (input) => wrapHandler(ctxFactory, updateContextHandler, input)
|
|
3763
|
+
);
|
|
3764
|
+
server.registerTool(
|
|
3765
|
+
"archive_context",
|
|
3766
|
+
{
|
|
3767
|
+
title: "Archive context",
|
|
3768
|
+
description: "\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u3092\u30A2\u30FC\u30AB\u30A4\u30D6\u3059\u308B\u3002\u30BF\u30B9\u30AF\u306E context_id \u306F\u7DAD\u6301\u3002",
|
|
3769
|
+
inputSchema: archiveContextInputSchema.shape
|
|
3770
|
+
},
|
|
3771
|
+
async (input) => wrapHandler(ctxFactory, archiveContextHandler, input)
|
|
3772
|
+
);
|
|
3773
|
+
server.registerTool(
|
|
3774
|
+
"delete_context",
|
|
3775
|
+
{
|
|
3776
|
+
title: "Delete context",
|
|
3777
|
+
description: "\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u3092\u7269\u7406\u524A\u9664\u3059\u308B\u3002\u30BF\u30B9\u30AF\u306E context_id \u306F NULL \u5316 (ON DELETE SET NULL)\u3002\u5C65\u6B74\u5C0A\u91CD\u306A\u3089 archive_context \u63A8\u5968\u3002",
|
|
3778
|
+
inputSchema: deleteContextInputSchema.shape
|
|
3779
|
+
},
|
|
3780
|
+
async (input) => wrapHandler(ctxFactory, deleteContextHandler, input)
|
|
3781
|
+
);
|
|
3782
|
+
server.registerTool(
|
|
3783
|
+
"create_routine",
|
|
3784
|
+
{
|
|
3785
|
+
title: "Create routine",
|
|
3786
|
+
description: '\u7E70\u308A\u8FD4\u3057\u30BF\u30B9\u30AF\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8 (\u30EB\u30FC\u30C1\u30F3) \u3092\u65B0\u898F\u4F5C\u6210\u3059\u308B\u3002`frequency` \u306F discriminated union (\u4F8B: {type: "weekly", weekdays: [1,3,5]})\u3002auto_expand=true (default) \u306A\u3089 Today \u3092\u958B\u3044\u305F\u6642\u306B\u81EA\u52D5\u5C55\u958B\u3055\u308C\u308B\u3002',
|
|
3787
|
+
inputSchema: createRoutineInputSchema.shape
|
|
3788
|
+
},
|
|
3789
|
+
async (input) => wrapHandler(ctxFactory, createRoutineHandler, input)
|
|
3790
|
+
);
|
|
3791
|
+
server.registerTool(
|
|
3792
|
+
"update_routine",
|
|
3793
|
+
{
|
|
3794
|
+
title: "Update routine (with propagation)",
|
|
3795
|
+
description: "\u30EB\u30FC\u30C1\u30F3\u3092\u90E8\u5206\u66F4\u65B0\u3059\u308B\u3002**\u672A\u6765 (date >= today) \u306E planned \u30BF\u30B9\u30AF\u306B\u81EA\u52D5\u4F1D\u64AD**\u3055\u308C\u308B (title / estimated / project / context / tags / scheduled_start_time)\u3002\u624B\u52D5\u7DE8\u96C6\u3057\u3066\u3044\u305F\u30BF\u30B9\u30AF\u306E\u8A72\u5F53\u30D5\u30A3\u30FC\u30EB\u30C9\u3082\u4E0A\u66F8\u304D\u3055\u308C\u308B\u70B9\u306B\u6CE8\u610F\u3002\u5B9F\u884C\u4E2D\u30FB\u5B8C\u4E86\u30FB\u30B9\u30AD\u30C3\u30D7\u6E08\u307F\u30FB\u904E\u53BB\u65E5\u306E\u30BF\u30B9\u30AF\u306F\u4FDD\u8B77\u3055\u308C\u308B\u3002propagated_task_count \u3092\u8FD4\u3059\u3002",
|
|
3796
|
+
inputSchema: updateRoutineInputSchema.shape
|
|
3797
|
+
},
|
|
3798
|
+
async (input) => wrapHandler(ctxFactory, updateRoutineHandler, input)
|
|
3799
|
+
);
|
|
3800
|
+
server.registerTool(
|
|
3801
|
+
"archive_routine",
|
|
3802
|
+
{
|
|
3803
|
+
title: "Archive routine",
|
|
3804
|
+
description: "\u30EB\u30FC\u30C1\u30F3\u3092\u30A2\u30FC\u30AB\u30A4\u30D6\u3059\u308B (status=archived)\u3002\u65E2\u5B58\u30BF\u30B9\u30AF\u306E routine_id \u306F\u7DAD\u6301\u3055\u308C\u308B (\u5C65\u6B74\u53EF)\u3002\u65B0\u898F\u5C55\u958B\u306F\u6B62\u307E\u308B\u3002",
|
|
3805
|
+
inputSchema: archiveRoutineInputSchema.shape
|
|
3806
|
+
},
|
|
3807
|
+
async (input) => wrapHandler(ctxFactory, archiveRoutineHandler, input)
|
|
3808
|
+
);
|
|
3809
|
+
server.registerTool(
|
|
3810
|
+
"delete_routine",
|
|
3811
|
+
{
|
|
3812
|
+
title: "Delete routine",
|
|
3813
|
+
description: "\u30EB\u30FC\u30C1\u30F3\u3092\u7269\u7406\u524A\u9664\u3059\u308B\u3002\u30BF\u30B9\u30AF\u306E routine_id \u306F ON DELETE SET NULL \u3067 NULL \u5316 (\u300Croutine \u7531\u6765\u300D\u306E\u30E9\u30D9\u30EB\u304C\u5931\u308F\u308C\u308B)\u3002\u5C65\u6B74\u5C0A\u91CD\u306A\u3089 archive_routine \u63A8\u5968\u3002",
|
|
3814
|
+
inputSchema: deleteRoutineInputSchema.shape
|
|
3815
|
+
},
|
|
3816
|
+
async (input) => wrapHandler(ctxFactory, deleteRoutineHandler, input)
|
|
3817
|
+
);
|
|
3818
|
+
server.registerTool(
|
|
3819
|
+
"create_time_block",
|
|
3820
|
+
{
|
|
3821
|
+
title: "Create time block",
|
|
3822
|
+
description: "\u30BF\u30A4\u30E0\u30D6\u30ED\u30C3\u30AF (\u6642\u9593\u5E2F\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8) \u3092\u65B0\u898F\u4F5C\u6210\u3059\u308B\u3002weekdays \u306F 0=\u65E5\u66DC\uFF5E6=\u571F\u66DC\u306E\u914D\u5217 (\u7A7A\u914D\u5217\u4E0D\u53EF)\u3002default_project_id / default_context_id / default_tag_ids \u3092\u6307\u5B9A\u3059\u308B\u3068\u30D6\u30ED\u30C3\u30AF\u7BC4\u56F2\u306B\u8FFD\u52A0\u3055\u308C\u305F\u30BF\u30B9\u30AF\u306E\u30C7\u30D5\u30A9\u30EB\u30C8\u306B\u4F7F\u308F\u308C\u308B\u3002",
|
|
3823
|
+
inputSchema: createTimeBlockInputSchema.shape
|
|
3824
|
+
},
|
|
3825
|
+
async (input) => wrapHandler(ctxFactory, createTimeBlockHandler, input)
|
|
3826
|
+
);
|
|
3827
|
+
server.registerTool(
|
|
3828
|
+
"update_time_block",
|
|
3829
|
+
{
|
|
3830
|
+
title: "Update time block",
|
|
3831
|
+
description: "\u30BF\u30A4\u30E0\u30D6\u30ED\u30C3\u30AF\u3092\u90E8\u5206\u66F4\u65B0\u3059\u308B\u3002default_tag_ids \u306F\u914D\u5217\u6307\u5B9A\u3067\u5168\u7F6E\u63DB\u3001null \u30AF\u30EA\u30A2\u306F default_project_id / default_context_id / color / start_date / end_date \u306E\u307F\u5BFE\u5FDC\u3002",
|
|
3832
|
+
inputSchema: updateTimeBlockInputSchema.shape
|
|
3833
|
+
},
|
|
3834
|
+
async (input) => wrapHandler(ctxFactory, updateTimeBlockHandler, input)
|
|
3835
|
+
);
|
|
3836
|
+
server.registerTool(
|
|
3837
|
+
"archive_time_block",
|
|
3838
|
+
{
|
|
3839
|
+
title: "Archive time block",
|
|
3840
|
+
description: "\u30BF\u30A4\u30E0\u30D6\u30ED\u30C3\u30AF\u3092\u30A2\u30FC\u30AB\u30A4\u30D6\u3059\u308B (status=archived)\u3002\u904E\u53BB\u65E5\u8868\u793A\u3067\u306F\u5F53\u6642\u306E\u72B6\u614B\u304C\u518D\u73FE\u3055\u308C\u308B\u3002",
|
|
3841
|
+
inputSchema: archiveTimeBlockInputSchema.shape
|
|
3842
|
+
},
|
|
3843
|
+
async (input) => wrapHandler(ctxFactory, archiveTimeBlockHandler, input)
|
|
3844
|
+
);
|
|
3845
|
+
server.registerTool(
|
|
3846
|
+
"delete_time_block",
|
|
3847
|
+
{
|
|
3848
|
+
title: "Delete time block",
|
|
3849
|
+
description: "\u30BF\u30A4\u30E0\u30D6\u30ED\u30C3\u30AF\u3092\u7269\u7406\u524A\u9664\u3059\u308B\u3002\u30BF\u30B9\u30AF\u306F\u6642\u523B\u30D9\u30FC\u30B9\u3067\u52D5\u7684\u306B\u30D6\u30ED\u30C3\u30AF\u3092\u5224\u5B9A\u3059\u308B\u306E\u3067\u53C2\u7167\u4E0D\u6574\u5408\u306F\u767A\u751F\u3057\u306A\u3044\u304C\u3001\u904E\u53BB\u65E5\u8868\u793A\u3067\u3082\u3053\u306E\u30D6\u30ED\u30C3\u30AF\u306F\u51FA\u3066\u3053\u306A\u304F\u306A\u308B\u3002",
|
|
3850
|
+
inputSchema: deleteTimeBlockInputSchema.shape
|
|
3851
|
+
},
|
|
3852
|
+
async (input) => wrapHandler(ctxFactory, deleteTimeBlockHandler, input)
|
|
3853
|
+
);
|
|
3854
|
+
server.registerTool(
|
|
3855
|
+
"set_actual_times",
|
|
3856
|
+
{
|
|
3857
|
+
title: "Set actual start/end times",
|
|
3858
|
+
description: "\u5B9F\u7E3E\u958B\u59CB/\u7D42\u4E86\u6642\u523B\u3092\u76F4\u63A5\u6307\u5B9A\u3059\u308B (Play \u62BC\u3057\u5FD8\u308C\u30EA\u30AB\u30D0\u30EA\u7528)\u3002start+end \u2192 completed\u3001start \u306E\u307F \u2192 running\u3001\u4E21\u65B9 null \u2192 planned \u30EA\u30BB\u30C3\u30C8\u3002end < start \u306A\u3089\u65E5\u8DE8\u304E\u30BB\u30C3\u30B7\u30E7\u30F3\u6271\u3044 (Domain \u3067 finishedAt \u3092\u7FCC\u65E5\u7E70\u4E0A\u3052)\u3002",
|
|
3859
|
+
inputSchema: setActualTimesInputSchema.shape
|
|
3860
|
+
},
|
|
3861
|
+
async (input) => wrapHandler(ctxFactory, setActualTimesHandler, input)
|
|
3862
|
+
);
|
|
3863
|
+
server.registerTool(
|
|
3864
|
+
"interrupt_task",
|
|
3865
|
+
{
|
|
3866
|
+
title: "Interrupt running task",
|
|
3867
|
+
description: "\u8D70\u884C\u4E2D\u30BF\u30B9\u30AF\u3092\u300C\u5272\u308A\u8FBC\u307F\u300D\u3067\u5206\u5272\u3059\u308B\u30021 \u547C\u3073\u51FA\u3057\u3067 3 \u30BF\u30B9\u30AF\u3092\u64CD\u4F5C: (1) \u5143\u30BF\u30B9\u30AF\u3092 completed (\u5B9F\u7E3E\u306F\u305D\u3053\u307E\u3067)\u3001(2) \u5272\u308A\u8FBC\u307F\u30BF\u30B9\u30AF\u3092 running \u3067\u65B0\u898F\u4F5C\u6210 (\u5373\u8A08\u6E2C\u958B\u59CB)\u3001(3) \u5143\u30BF\u30B9\u30AF\u306E\u6B8B\u4F5C\u696D\u3092 planned \u3067\u65B0\u898F\u4F5C\u6210 (splitFromTaskId \u3067\u30EA\u30CD\u30FC\u30B8\u4FDD\u6301)\u3002split note 3 \u4EF6\u304C\u81EA\u52D5\u8A18\u9332\u3055\u308C\u308B\u3002\u5BFE\u8C61\u30BF\u30B9\u30AF\u304C running \u4E2D\u3067\u306A\u3044\u3068\u30A8\u30E9\u30FC\u3002",
|
|
3868
|
+
inputSchema: interruptTaskInputSchema.shape
|
|
3869
|
+
},
|
|
3870
|
+
async (input) => wrapHandler(ctxFactory, interruptTaskHandler, input)
|
|
3871
|
+
);
|
|
3872
|
+
server.registerTool(
|
|
3873
|
+
"add_parallel_task",
|
|
3874
|
+
{
|
|
3875
|
+
title: "Add parallel task",
|
|
3876
|
+
description: "\u9032\u884C\u4E2D\u30BF\u30B9\u30AF\u3068\u4E26\u884C\u3059\u308B\u65B0\u898F\u30BF\u30B9\u30AF\u3092\u8FFD\u52A0\u3059\u308B\u3002start_immediately: true (default) \u3067 running \u72B6\u614B + \u5373\u8A08\u6E2C\u958B\u59CB\u3002false \u3067 planned \u4F5C\u6210\u306E\u307F\u3002is_background: true \u4F75\u7528\u3067\u898B\u7A4D\u3082\u308A\u96C6\u8A08\u304B\u3089\u9664\u5916\u3002",
|
|
3877
|
+
inputSchema: addParallelTaskInputSchema.shape
|
|
3878
|
+
},
|
|
3879
|
+
async (input) => wrapHandler(ctxFactory, addParallelTaskHandler, input)
|
|
3880
|
+
);
|
|
3881
|
+
server.registerTool(
|
|
3882
|
+
"reorder_task",
|
|
3883
|
+
{
|
|
3884
|
+
title: "Reorder task",
|
|
3885
|
+
description: "\u30BF\u30B9\u30AF\u306E\u4E26\u3073\u9806 (order_index) \u3092\u5909\u66F4\u3059\u308B\u3002\u6163\u7FD2\u3067 10 \u5358\u4F4D (\u96A3\u63A5\u4E2D\u9593\u633F\u5165\u306F 5 \u3084 15)\u3002scheduled_start_time \u3082\u540C\u6642\u6307\u5B9A\u53EF\u80FD (null=\u672A\u5272\u5F53\u30B0\u30EB\u30FC\u30D7\u3078\u3001HH:MM=\u8A72\u5F53\u30BF\u30A4\u30E0\u30D6\u30ED\u30C3\u30AF\u3078\u79FB\u52D5)\u3002",
|
|
3886
|
+
inputSchema: reorderTaskInputSchema.shape
|
|
3887
|
+
},
|
|
3888
|
+
async (input) => wrapHandler(ctxFactory, reorderTaskHandler, input)
|
|
3889
|
+
);
|
|
2179
3890
|
return server;
|
|
2180
3891
|
}
|
|
2181
3892
|
|
|
2182
3893
|
// src/index.ts
|
|
2183
3894
|
async function main() {
|
|
2184
|
-
const version = "0.
|
|
3895
|
+
const version = "0.2.0" ;
|
|
2185
3896
|
const server = createMcpServer({ version });
|
|
2186
3897
|
const transport = new StdioServerTransport();
|
|
2187
3898
|
await server.connect(transport);
|