@shin1ohno/sage 0.1.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/LICENSE +21 -0
- package/README.md +168 -0
- package/dist/config/loader.d.ts +37 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +95 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/storage/file-storage.d.ts +35 -0
- package/dist/config/storage/file-storage.d.ts.map +1 -0
- package/dist/config/storage/file-storage.js +76 -0
- package/dist/config/storage/file-storage.js.map +1 -0
- package/dist/config/storage/index.d.ts +8 -0
- package/dist/config/storage/index.d.ts.map +1 -0
- package/dist/config/storage/index.js +8 -0
- package/dist/config/storage/index.js.map +1 -0
- package/dist/config/storage/session-storage.d.ts +35 -0
- package/dist/config/storage/session-storage.d.ts.map +1 -0
- package/dist/config/storage/session-storage.js +44 -0
- package/dist/config/storage/session-storage.js.map +1 -0
- package/dist/config/storage/storage-factory.d.ts +32 -0
- package/dist/config/storage/storage-factory.d.ts.map +1 -0
- package/dist/config/storage/storage-factory.js +78 -0
- package/dist/config/storage/storage-factory.js.map +1 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +6 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/sage-core.d.ts +80 -0
- package/dist/core/sage-core.d.ts.map +1 -0
- package/dist/core/sage-core.js +190 -0
- package/dist/core/sage-core.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +901 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/apple-reminders.d.ts +96 -0
- package/dist/integrations/apple-reminders.d.ts.map +1 -0
- package/dist/integrations/apple-reminders.js +250 -0
- package/dist/integrations/apple-reminders.js.map +1 -0
- package/dist/integrations/calendar-service.d.ts +126 -0
- package/dist/integrations/calendar-service.d.ts.map +1 -0
- package/dist/integrations/calendar-service.js +295 -0
- package/dist/integrations/calendar-service.js.map +1 -0
- package/dist/integrations/notion-mcp.d.ts +121 -0
- package/dist/integrations/notion-mcp.d.ts.map +1 -0
- package/dist/integrations/notion-mcp.js +281 -0
- package/dist/integrations/notion-mcp.js.map +1 -0
- package/dist/integrations/reminder-manager.d.ts +90 -0
- package/dist/integrations/reminder-manager.d.ts.map +1 -0
- package/dist/integrations/reminder-manager.js +182 -0
- package/dist/integrations/reminder-manager.js.map +1 -0
- package/dist/platform/adapter-factory.d.ts +22 -0
- package/dist/platform/adapter-factory.d.ts.map +1 -0
- package/dist/platform/adapter-factory.js +41 -0
- package/dist/platform/adapter-factory.js.map +1 -0
- package/dist/platform/adapters/mcp-adapter.d.ts +32 -0
- package/dist/platform/adapters/mcp-adapter.d.ts.map +1 -0
- package/dist/platform/adapters/mcp-adapter.js +52 -0
- package/dist/platform/adapters/mcp-adapter.js.map +1 -0
- package/dist/platform/adapters/skills-adapter-ios.d.ts +38 -0
- package/dist/platform/adapters/skills-adapter-ios.d.ts.map +1 -0
- package/dist/platform/adapters/skills-adapter-ios.js +59 -0
- package/dist/platform/adapters/skills-adapter-ios.js.map +1 -0
- package/dist/platform/adapters/skills-adapter-web.d.ts +36 -0
- package/dist/platform/adapters/skills-adapter-web.d.ts.map +1 -0
- package/dist/platform/adapters/skills-adapter-web.js +56 -0
- package/dist/platform/adapters/skills-adapter-web.js.map +1 -0
- package/dist/platform/detector.d.ts +60 -0
- package/dist/platform/detector.d.ts.map +1 -0
- package/dist/platform/detector.js +217 -0
- package/dist/platform/detector.js.map +1 -0
- package/dist/platform/index.d.ts +11 -0
- package/dist/platform/index.d.ts.map +1 -0
- package/dist/platform/index.js +11 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/platform/types.d.ts +205 -0
- package/dist/platform/types.d.ts.map +1 -0
- package/dist/platform/types.js +33 -0
- package/dist/platform/types.js.map +1 -0
- package/dist/setup/questions.d.ts +15 -0
- package/dist/setup/questions.d.ts.map +1 -0
- package/dist/setup/questions.js +131 -0
- package/dist/setup/questions.js.map +1 -0
- package/dist/setup/wizard.d.ts +51 -0
- package/dist/setup/wizard.d.ts.map +1 -0
- package/dist/setup/wizard.js +210 -0
- package/dist/setup/wizard.js.map +1 -0
- package/dist/tools/analyze-tasks.d.ts +61 -0
- package/dist/tools/analyze-tasks.d.ts.map +1 -0
- package/dist/tools/analyze-tasks.js +258 -0
- package/dist/tools/analyze-tasks.js.map +1 -0
- package/dist/types/config.d.ts +126 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +118 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/errors.d.ts +39 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +83 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/task.d.ts +69 -0
- package/dist/types/task.d.ts.map +1 -0
- package/dist/types/task.js +5 -0
- package/dist/types/task.js.map +1 -0
- package/dist/utils/estimation.d.ts +49 -0
- package/dist/utils/estimation.d.ts.map +1 -0
- package/dist/utils/estimation.js +244 -0
- package/dist/utils/estimation.js.map +1 -0
- package/dist/utils/priority.d.ts +68 -0
- package/dist/utils/priority.d.ts.map +1 -0
- package/dist/utils/priority.js +243 -0
- package/dist/utils/priority.js.map +1 -0
- package/dist/utils/retry.d.ts +62 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +161 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/stakeholders.d.ts +61 -0
- package/dist/utils/stakeholders.d.ts.map +1 -0
- package/dist/utils/stakeholders.js +301 -0
- package/dist/utils/stakeholders.js.map +1 -0
- package/dist/utils/task-splitter.d.ts +45 -0
- package/dist/utils/task-splitter.d.ts.map +1 -0
- package/dist/utils/task-splitter.js +321 -0
- package/dist/utils/task-splitter.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stakeholder Extraction System
|
|
3
|
+
* Identifies and extracts stakeholders from task content
|
|
4
|
+
* Requirements: 4.1-4.5
|
|
5
|
+
*/
|
|
6
|
+
// Manager keywords
|
|
7
|
+
const MANAGER_KEYWORDS = [
|
|
8
|
+
'manager',
|
|
9
|
+
'マネージャー',
|
|
10
|
+
'上司',
|
|
11
|
+
'boss',
|
|
12
|
+
'supervisor',
|
|
13
|
+
'管理者',
|
|
14
|
+
'director',
|
|
15
|
+
'ディレクター',
|
|
16
|
+
'lead',
|
|
17
|
+
'リーダー',
|
|
18
|
+
'team lead',
|
|
19
|
+
'チームリード',
|
|
20
|
+
];
|
|
21
|
+
// Mention patterns
|
|
22
|
+
const MENTION_PATTERNS = [
|
|
23
|
+
/@(\w+)/g, // @username
|
|
24
|
+
/@([^\s]+さん)/g, // @名前さん (Japanese)
|
|
25
|
+
/(?:from|by|with|to|cc|CC)\s+(\w+)/gi, // from/by/with person
|
|
26
|
+
/(?:から|と|へ|宛)\s*([^\s、]+(?:さん|様)?)/g, // Japanese particles
|
|
27
|
+
];
|
|
28
|
+
export class StakeholderExtractor {
|
|
29
|
+
/**
|
|
30
|
+
* Extract stakeholders from a task
|
|
31
|
+
* Requirement: 4.1, 4.5
|
|
32
|
+
*/
|
|
33
|
+
static extractStakeholders(task, teamConfig) {
|
|
34
|
+
const text = `${task.title} ${task.description ?? ''}`;
|
|
35
|
+
const stakeholders = [];
|
|
36
|
+
const matchedTeamMembers = [];
|
|
37
|
+
// Extract @mentions
|
|
38
|
+
const mentions = this.findMentions(text);
|
|
39
|
+
stakeholders.push(...mentions);
|
|
40
|
+
// Match against team members
|
|
41
|
+
if (teamConfig) {
|
|
42
|
+
const matched = this.matchTeamMembers(text, teamConfig);
|
|
43
|
+
for (const member of matched) {
|
|
44
|
+
if (!stakeholders.includes(member.name)) {
|
|
45
|
+
stakeholders.push(member.name);
|
|
46
|
+
matchedTeamMembers.push(member);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Check for manager involvement
|
|
51
|
+
const managerInvolved = this.checkManagerInvolvement(text, teamConfig);
|
|
52
|
+
// Add manager to stakeholders if involved
|
|
53
|
+
if (managerInvolved && teamConfig?.manager) {
|
|
54
|
+
if (!stakeholders.includes(teamConfig.manager.name)) {
|
|
55
|
+
stakeholders.push(teamConfig.manager.name);
|
|
56
|
+
matchedTeamMembers.push(teamConfig.manager);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
stakeholders,
|
|
61
|
+
managerInvolved,
|
|
62
|
+
reason: this.buildReason(stakeholders, managerInvolved, mentions),
|
|
63
|
+
mentions,
|
|
64
|
+
matchedTeamMembers,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Find @mentions in text
|
|
69
|
+
* Requirement: 4.3
|
|
70
|
+
*/
|
|
71
|
+
static findMentions(text) {
|
|
72
|
+
const mentions = new Set();
|
|
73
|
+
for (const pattern of MENTION_PATTERNS) {
|
|
74
|
+
// Reset lastIndex for global patterns
|
|
75
|
+
pattern.lastIndex = 0;
|
|
76
|
+
let match;
|
|
77
|
+
while ((match = pattern.exec(text)) !== null) {
|
|
78
|
+
const mention = match[1].trim();
|
|
79
|
+
// Filter out common false positives
|
|
80
|
+
if (mention.length > 1 && !this.isCommonWord(mention)) {
|
|
81
|
+
mentions.add(mention);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return Array.from(mentions);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Match text against configured team members
|
|
89
|
+
* Requirement: 4.2
|
|
90
|
+
*/
|
|
91
|
+
static matchTeamMembers(text, teamConfig) {
|
|
92
|
+
const lowerText = text.toLowerCase();
|
|
93
|
+
const matched = [];
|
|
94
|
+
// Check manager
|
|
95
|
+
if (teamConfig.manager) {
|
|
96
|
+
if (this.memberMatchesText(teamConfig.manager, lowerText)) {
|
|
97
|
+
matched.push(teamConfig.manager);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Check frequent collaborators
|
|
101
|
+
for (const collaborator of teamConfig.frequentCollaborators) {
|
|
102
|
+
if (this.memberMatchesText(collaborator, lowerText)) {
|
|
103
|
+
matched.push(collaborator);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return matched;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Check if a team member matches the text
|
|
110
|
+
*/
|
|
111
|
+
static memberMatchesText(member, lowerText) {
|
|
112
|
+
// Check name
|
|
113
|
+
if (lowerText.includes(member.name.toLowerCase())) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
// Check keywords
|
|
117
|
+
for (const keyword of member.keywords) {
|
|
118
|
+
if (lowerText.includes(keyword.toLowerCase())) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Check if manager is involved in the task
|
|
126
|
+
* Requirement: 4.4
|
|
127
|
+
*/
|
|
128
|
+
static checkManagerInvolvement(text, teamConfig) {
|
|
129
|
+
const lowerText = text.toLowerCase();
|
|
130
|
+
// Check generic manager keywords
|
|
131
|
+
if (MANAGER_KEYWORDS.some((keyword) => lowerText.includes(keyword.toLowerCase()))) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
// Check configured manager
|
|
135
|
+
if (teamConfig?.manager) {
|
|
136
|
+
if (lowerText.includes(teamConfig.manager.name.toLowerCase())) {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
for (const keyword of teamConfig.manager.keywords) {
|
|
140
|
+
if (lowerText.includes(keyword.toLowerCase())) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Check if a word is a common word (false positive)
|
|
149
|
+
*/
|
|
150
|
+
static isCommonWord(word) {
|
|
151
|
+
const commonWords = [
|
|
152
|
+
'the',
|
|
153
|
+
'a',
|
|
154
|
+
'an',
|
|
155
|
+
'to',
|
|
156
|
+
'from',
|
|
157
|
+
'with',
|
|
158
|
+
'by',
|
|
159
|
+
'for',
|
|
160
|
+
'in',
|
|
161
|
+
'on',
|
|
162
|
+
'at',
|
|
163
|
+
'it',
|
|
164
|
+
'is',
|
|
165
|
+
'are',
|
|
166
|
+
'was',
|
|
167
|
+
'were',
|
|
168
|
+
'be',
|
|
169
|
+
'been',
|
|
170
|
+
'being',
|
|
171
|
+
'have',
|
|
172
|
+
'has',
|
|
173
|
+
'had',
|
|
174
|
+
'do',
|
|
175
|
+
'does',
|
|
176
|
+
'did',
|
|
177
|
+
'will',
|
|
178
|
+
'would',
|
|
179
|
+
'could',
|
|
180
|
+
'should',
|
|
181
|
+
'may',
|
|
182
|
+
'might',
|
|
183
|
+
'must',
|
|
184
|
+
'shall',
|
|
185
|
+
'can',
|
|
186
|
+
'need',
|
|
187
|
+
'dare',
|
|
188
|
+
'ought',
|
|
189
|
+
'used',
|
|
190
|
+
'this',
|
|
191
|
+
'that',
|
|
192
|
+
'these',
|
|
193
|
+
'those',
|
|
194
|
+
'の',
|
|
195
|
+
'に',
|
|
196
|
+
'を',
|
|
197
|
+
'で',
|
|
198
|
+
'が',
|
|
199
|
+
'は',
|
|
200
|
+
];
|
|
201
|
+
return commonWords.includes(word.toLowerCase());
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Build a human-readable reason
|
|
205
|
+
*/
|
|
206
|
+
static buildReason(stakeholders, managerInvolved, mentions) {
|
|
207
|
+
if (stakeholders.length === 0) {
|
|
208
|
+
return '関係者は検出されませんでした';
|
|
209
|
+
}
|
|
210
|
+
const parts = [];
|
|
211
|
+
if (mentions.length > 0) {
|
|
212
|
+
parts.push(`@メンションから${mentions.length}名を検出`);
|
|
213
|
+
}
|
|
214
|
+
if (managerInvolved) {
|
|
215
|
+
parts.push('マネージャーが関与');
|
|
216
|
+
}
|
|
217
|
+
const nonMentionCount = stakeholders.length - mentions.length;
|
|
218
|
+
if (nonMentionCount > 0 && !managerInvolved) {
|
|
219
|
+
parts.push(`チームメンバーから${nonMentionCount}名を検出`);
|
|
220
|
+
}
|
|
221
|
+
return parts.join('、') || `${stakeholders.length}名の関係者を検出`;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Get priority boost for manager involvement
|
|
225
|
+
*/
|
|
226
|
+
static getManagerPriorityBoost() {
|
|
227
|
+
return 1; // Boost priority by 1 level (e.g., P2 -> P1)
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Extract all names from text (broader matching)
|
|
231
|
+
*/
|
|
232
|
+
static extractPotentialNames(text) {
|
|
233
|
+
const names = new Set();
|
|
234
|
+
// Japanese name patterns (漢字 + さん/様/氏)
|
|
235
|
+
const japaneseNamePattern = /([一-龯]{2,4})(さん|様|氏)/g;
|
|
236
|
+
let match;
|
|
237
|
+
while ((match = japaneseNamePattern.exec(text)) !== null) {
|
|
238
|
+
names.add(match[1]);
|
|
239
|
+
}
|
|
240
|
+
// English capitalized names
|
|
241
|
+
const englishNamePattern = /\b([A-Z][a-z]+(?:\s+[A-Z][a-z]+)?)\b/g;
|
|
242
|
+
while ((match = englishNamePattern.exec(text)) !== null) {
|
|
243
|
+
const name = match[1];
|
|
244
|
+
// Filter out common non-names
|
|
245
|
+
if (!this.isCommonCapitalizedWord(name)) {
|
|
246
|
+
names.add(name);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return Array.from(names);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Check if a capitalized word is commonly not a name
|
|
253
|
+
*/
|
|
254
|
+
static isCommonCapitalizedWord(word) {
|
|
255
|
+
const commonWords = [
|
|
256
|
+
'Monday',
|
|
257
|
+
'Tuesday',
|
|
258
|
+
'Wednesday',
|
|
259
|
+
'Thursday',
|
|
260
|
+
'Friday',
|
|
261
|
+
'Saturday',
|
|
262
|
+
'Sunday',
|
|
263
|
+
'January',
|
|
264
|
+
'February',
|
|
265
|
+
'March',
|
|
266
|
+
'April',
|
|
267
|
+
'May',
|
|
268
|
+
'June',
|
|
269
|
+
'July',
|
|
270
|
+
'August',
|
|
271
|
+
'September',
|
|
272
|
+
'October',
|
|
273
|
+
'November',
|
|
274
|
+
'December',
|
|
275
|
+
'The',
|
|
276
|
+
'This',
|
|
277
|
+
'That',
|
|
278
|
+
'Please',
|
|
279
|
+
'Thanks',
|
|
280
|
+
'Hello',
|
|
281
|
+
'Hi',
|
|
282
|
+
'Dear',
|
|
283
|
+
'Task',
|
|
284
|
+
'Project',
|
|
285
|
+
'Meeting',
|
|
286
|
+
'Review',
|
|
287
|
+
'Update',
|
|
288
|
+
'Urgent',
|
|
289
|
+
'Important',
|
|
290
|
+
'TODO',
|
|
291
|
+
'FIXME',
|
|
292
|
+
'NOTE',
|
|
293
|
+
'API',
|
|
294
|
+
'UI',
|
|
295
|
+
'PR',
|
|
296
|
+
'MR',
|
|
297
|
+
];
|
|
298
|
+
return commonWords.includes(word);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
//# sourceMappingURL=stakeholders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stakeholders.js","sourceRoot":"","sources":["../../src/utils/stakeholders.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task Splitter
|
|
3
|
+
* Splits complex tasks or multiple tasks into manageable pieces
|
|
4
|
+
* Requirements: 11.1-11.6
|
|
5
|
+
*/
|
|
6
|
+
import type { Task, SplitResult, ComplexityAnalysis } from '../types/index.js';
|
|
7
|
+
export declare class TaskSplitter {
|
|
8
|
+
/**
|
|
9
|
+
* Split input text into individual tasks
|
|
10
|
+
* Requirement: 11.1, 11.4
|
|
11
|
+
*/
|
|
12
|
+
static splitTasks(input: string): SplitResult;
|
|
13
|
+
/**
|
|
14
|
+
* Analyze task complexity
|
|
15
|
+
* Requirement: 11.2, 11.3
|
|
16
|
+
*/
|
|
17
|
+
static analyzeComplexity(task: Task): ComplexityAnalysis;
|
|
18
|
+
/**
|
|
19
|
+
* Split input into individual lines/items
|
|
20
|
+
*/
|
|
21
|
+
private static splitIntoLines;
|
|
22
|
+
/**
|
|
23
|
+
* Check if input contains multiple tasks
|
|
24
|
+
*/
|
|
25
|
+
private static containsMultipleTasks;
|
|
26
|
+
/**
|
|
27
|
+
* Suggest splits for project-level tasks
|
|
28
|
+
*/
|
|
29
|
+
private static suggestProjectSplits;
|
|
30
|
+
/**
|
|
31
|
+
* Suggest splits for complex tasks
|
|
32
|
+
*/
|
|
33
|
+
private static suggestComplexSplits;
|
|
34
|
+
/**
|
|
35
|
+
* Infer dependencies between tasks
|
|
36
|
+
* Requirement: 11.5
|
|
37
|
+
*/
|
|
38
|
+
private static inferDependencies;
|
|
39
|
+
/**
|
|
40
|
+
* Calculate recommended execution order
|
|
41
|
+
* Requirement: 11.6
|
|
42
|
+
*/
|
|
43
|
+
private static calculateRecommendedOrder;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=task-splitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-splitter.d.ts","sourceRoot":"","sources":["../../src/utils/task-splitter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,IAAI,EAEJ,WAAW,EACX,kBAAkB,EAEnB,MAAM,mBAAmB,CAAC;AA6E3B,qBAAa,YAAY;IACvB;;;OAGG;IACH,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW;IAgD7C;;;OAGG;IACH,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,kBAAkB;IAwCxD;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IA2B7B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAOpC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,oBAAoB;IA8BnC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAoBnC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAkDhC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,yBAAyB;CAuBzC"}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task Splitter
|
|
3
|
+
* Splits complex tasks or multiple tasks into manageable pieces
|
|
4
|
+
* Requirements: 11.1-11.6
|
|
5
|
+
*/
|
|
6
|
+
// Patterns that indicate multiple tasks
|
|
7
|
+
const MULTI_TASK_PATTERNS = [
|
|
8
|
+
/(?:^|\n)\s*[-•*]\s+/g, // Bullet points
|
|
9
|
+
/(?:^|\n)\s*\d+[.)]\s+/g, // Numbered lists
|
|
10
|
+
/(?:そして|また|さらに|加えて|それから)/g, // Japanese conjunctions
|
|
11
|
+
/(?:and then|also|additionally|furthermore|moreover)/gi, // English conjunctions
|
|
12
|
+
/[。.]\s*(?=[^。.]+[。.])/g, // Sentence boundaries with more content
|
|
13
|
+
];
|
|
14
|
+
// Keywords indicating complex tasks
|
|
15
|
+
const COMPLEXITY_KEYWORDS = {
|
|
16
|
+
project: [
|
|
17
|
+
'システム',
|
|
18
|
+
'アーキテクチャ',
|
|
19
|
+
'設計',
|
|
20
|
+
'構築',
|
|
21
|
+
'プロジェクト',
|
|
22
|
+
'system',
|
|
23
|
+
'architecture',
|
|
24
|
+
'design',
|
|
25
|
+
'build',
|
|
26
|
+
'project',
|
|
27
|
+
'develop',
|
|
28
|
+
'開発',
|
|
29
|
+
],
|
|
30
|
+
complex: [
|
|
31
|
+
'リファクタ',
|
|
32
|
+
'統合',
|
|
33
|
+
'移行',
|
|
34
|
+
'マイグレーション',
|
|
35
|
+
'最適化',
|
|
36
|
+
'refactor',
|
|
37
|
+
'integrate',
|
|
38
|
+
'migrate',
|
|
39
|
+
'migration',
|
|
40
|
+
'optimize',
|
|
41
|
+
'implement',
|
|
42
|
+
'実装',
|
|
43
|
+
],
|
|
44
|
+
medium: [
|
|
45
|
+
'修正',
|
|
46
|
+
'更新',
|
|
47
|
+
'変更',
|
|
48
|
+
'追加',
|
|
49
|
+
'作成',
|
|
50
|
+
'fix',
|
|
51
|
+
'update',
|
|
52
|
+
'change',
|
|
53
|
+
'add',
|
|
54
|
+
'create',
|
|
55
|
+
'modify',
|
|
56
|
+
],
|
|
57
|
+
simple: [
|
|
58
|
+
'確認',
|
|
59
|
+
'レビュー',
|
|
60
|
+
'チェック',
|
|
61
|
+
'読む',
|
|
62
|
+
'返信',
|
|
63
|
+
'confirm',
|
|
64
|
+
'review',
|
|
65
|
+
'check',
|
|
66
|
+
'read',
|
|
67
|
+
'reply',
|
|
68
|
+
'send',
|
|
69
|
+
'送信',
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
// Dependency indicator keywords
|
|
73
|
+
const DEPENDENCY_KEYWORDS = {
|
|
74
|
+
before: ['前に', '先に', 'まず', 'before', 'first', 'prior to'],
|
|
75
|
+
after: ['後に', '次に', 'その後', 'after', 'then', 'following'],
|
|
76
|
+
requires: ['必要', '依存', 'requires', 'depends on', 'needs'],
|
|
77
|
+
};
|
|
78
|
+
export class TaskSplitter {
|
|
79
|
+
/**
|
|
80
|
+
* Split input text into individual tasks
|
|
81
|
+
* Requirement: 11.1, 11.4
|
|
82
|
+
*/
|
|
83
|
+
static splitTasks(input) {
|
|
84
|
+
const tasks = [];
|
|
85
|
+
const lines = this.splitIntoLines(input);
|
|
86
|
+
if (lines.length === 1 && !this.containsMultipleTasks(input)) {
|
|
87
|
+
// Single task - check if it needs complexity-based splitting
|
|
88
|
+
const task = { title: input.trim() };
|
|
89
|
+
const complexity = this.analyzeComplexity(task);
|
|
90
|
+
if (complexity.isComplex && complexity.suggestedSplits) {
|
|
91
|
+
return {
|
|
92
|
+
originalInput: input,
|
|
93
|
+
splitTasks: complexity.suggestedSplits,
|
|
94
|
+
splitReason: complexity.reasoning,
|
|
95
|
+
recommendedOrder: complexity.suggestedSplits.map((_, i) => i),
|
|
96
|
+
dependencies: this.inferDependencies(complexity.suggestedSplits),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
originalInput: input,
|
|
101
|
+
splitTasks: [task],
|
|
102
|
+
splitReason: 'シンプルなタスクのため分割不要',
|
|
103
|
+
recommendedOrder: [0],
|
|
104
|
+
dependencies: [],
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
// Multiple lines/tasks detected
|
|
108
|
+
for (const line of lines) {
|
|
109
|
+
const trimmed = line.trim();
|
|
110
|
+
if (trimmed) {
|
|
111
|
+
tasks.push({ title: trimmed });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const dependencies = this.inferDependencies(tasks);
|
|
115
|
+
const recommendedOrder = this.calculateRecommendedOrder(tasks, dependencies);
|
|
116
|
+
return {
|
|
117
|
+
originalInput: input,
|
|
118
|
+
splitTasks: tasks,
|
|
119
|
+
splitReason: `${tasks.length}個のタスクを検出しました`,
|
|
120
|
+
recommendedOrder,
|
|
121
|
+
dependencies,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Analyze task complexity
|
|
126
|
+
* Requirement: 11.2, 11.3
|
|
127
|
+
*/
|
|
128
|
+
static analyzeComplexity(task) {
|
|
129
|
+
const text = `${task.title} ${task.description ?? ''}`.toLowerCase();
|
|
130
|
+
// Check for project-level complexity
|
|
131
|
+
if (COMPLEXITY_KEYWORDS.project.some((k) => text.includes(k.toLowerCase()))) {
|
|
132
|
+
return {
|
|
133
|
+
isComplex: true,
|
|
134
|
+
complexity: 'project',
|
|
135
|
+
suggestedSplits: this.suggestProjectSplits(task),
|
|
136
|
+
reasoning: 'プロジェクトレベルのタスクです。複数のフェーズに分割することを推奨します。',
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
// Check for complex tasks
|
|
140
|
+
if (COMPLEXITY_KEYWORDS.complex.some((k) => text.includes(k.toLowerCase()))) {
|
|
141
|
+
return {
|
|
142
|
+
isComplex: true,
|
|
143
|
+
complexity: 'complex',
|
|
144
|
+
suggestedSplits: this.suggestComplexSplits(task),
|
|
145
|
+
reasoning: '複雑なタスクです。より小さなステップに分割することを推奨します。',
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
// Check for medium tasks
|
|
149
|
+
if (COMPLEXITY_KEYWORDS.medium.some((k) => text.includes(k.toLowerCase()))) {
|
|
150
|
+
return {
|
|
151
|
+
isComplex: false,
|
|
152
|
+
complexity: 'medium',
|
|
153
|
+
reasoning: '中程度の複雑さのタスクです。そのまま実行可能です。',
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
// Simple task
|
|
157
|
+
return {
|
|
158
|
+
isComplex: false,
|
|
159
|
+
complexity: 'simple',
|
|
160
|
+
reasoning: 'シンプルなタスクです。分割は不要です。',
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Split input into individual lines/items
|
|
165
|
+
*/
|
|
166
|
+
static splitIntoLines(input) {
|
|
167
|
+
// First, try to split by bullet points or numbered lists
|
|
168
|
+
const bulletSplit = input.split(/(?:^|\n)\s*[-•*]\s+/).filter(Boolean);
|
|
169
|
+
if (bulletSplit.length > 1) {
|
|
170
|
+
return bulletSplit.map((s) => s.trim());
|
|
171
|
+
}
|
|
172
|
+
const numberedSplit = input.split(/(?:^|\n)\s*\d+[.)]\s+/).filter(Boolean);
|
|
173
|
+
if (numberedSplit.length > 1) {
|
|
174
|
+
return numberedSplit.map((s) => s.trim());
|
|
175
|
+
}
|
|
176
|
+
// Try splitting by Japanese conjunctions
|
|
177
|
+
const conjunctionSplit = input.split(/(?:そして|また|さらに|加えて|それから)/);
|
|
178
|
+
if (conjunctionSplit.length > 1) {
|
|
179
|
+
return conjunctionSplit.map((s) => s.trim()).filter(Boolean);
|
|
180
|
+
}
|
|
181
|
+
// Split by newlines
|
|
182
|
+
const newlineSplit = input.split('\n').filter((s) => s.trim());
|
|
183
|
+
if (newlineSplit.length > 1) {
|
|
184
|
+
return newlineSplit;
|
|
185
|
+
}
|
|
186
|
+
return [input];
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Check if input contains multiple tasks
|
|
190
|
+
*/
|
|
191
|
+
static containsMultipleTasks(input) {
|
|
192
|
+
return MULTI_TASK_PATTERNS.some((pattern) => {
|
|
193
|
+
const matches = input.match(pattern);
|
|
194
|
+
return matches && matches.length > 1;
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Suggest splits for project-level tasks
|
|
199
|
+
*/
|
|
200
|
+
static suggestProjectSplits(task) {
|
|
201
|
+
return [
|
|
202
|
+
{
|
|
203
|
+
title: `${task.title} - 要件定義と計画`,
|
|
204
|
+
order: 0,
|
|
205
|
+
status: 'not_started',
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
title: `${task.title} - 設計とアーキテクチャ`,
|
|
209
|
+
order: 1,
|
|
210
|
+
status: 'not_started',
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
title: `${task.title} - 実装`,
|
|
214
|
+
order: 2,
|
|
215
|
+
status: 'not_started',
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
title: `${task.title} - テストと検証`,
|
|
219
|
+
order: 3,
|
|
220
|
+
status: 'not_started',
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
title: `${task.title} - デプロイとドキュメント`,
|
|
224
|
+
order: 4,
|
|
225
|
+
status: 'not_started',
|
|
226
|
+
},
|
|
227
|
+
];
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Suggest splits for complex tasks
|
|
231
|
+
*/
|
|
232
|
+
static suggestComplexSplits(task) {
|
|
233
|
+
return [
|
|
234
|
+
{
|
|
235
|
+
title: `${task.title} - 調査と準備`,
|
|
236
|
+
order: 0,
|
|
237
|
+
status: 'not_started',
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
title: `${task.title} - 実装`,
|
|
241
|
+
order: 1,
|
|
242
|
+
status: 'not_started',
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
title: `${task.title} - 確認とテスト`,
|
|
246
|
+
order: 2,
|
|
247
|
+
status: 'not_started',
|
|
248
|
+
},
|
|
249
|
+
];
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Infer dependencies between tasks
|
|
253
|
+
* Requirement: 11.5
|
|
254
|
+
*/
|
|
255
|
+
static inferDependencies(tasks) {
|
|
256
|
+
const dependencies = [];
|
|
257
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
258
|
+
const task = tasks[i];
|
|
259
|
+
const text = `${task.title} ${task.description ?? ''}`.toLowerCase();
|
|
260
|
+
const dependsOn = [];
|
|
261
|
+
// Check for explicit dependency keywords
|
|
262
|
+
for (const [type, keywords] of Object.entries(DEPENDENCY_KEYWORDS)) {
|
|
263
|
+
if (keywords.some((k) => text.includes(k.toLowerCase()))) {
|
|
264
|
+
if (type === 'after' && i > 0) {
|
|
265
|
+
dependsOn.push(i - 1);
|
|
266
|
+
}
|
|
267
|
+
if (type === 'requires' && i > 0) {
|
|
268
|
+
// Look for references to previous tasks
|
|
269
|
+
for (let j = 0; j < i; j++) {
|
|
270
|
+
const prevTitle = tasks[j].title.toLowerCase();
|
|
271
|
+
if (text.includes(prevTitle.substring(0, 10))) {
|
|
272
|
+
dependsOn.push(j);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (dependsOn.length > 0) {
|
|
279
|
+
dependencies.push({
|
|
280
|
+
taskIndex: i,
|
|
281
|
+
dependsOn,
|
|
282
|
+
type: 'sequential',
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
// If no explicit dependencies found, assume sequential order
|
|
287
|
+
if (dependencies.length === 0 && tasks.length > 1) {
|
|
288
|
+
for (let i = 1; i < tasks.length; i++) {
|
|
289
|
+
dependencies.push({
|
|
290
|
+
taskIndex: i,
|
|
291
|
+
dependsOn: [i - 1],
|
|
292
|
+
type: 'sequential',
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return dependencies;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Calculate recommended execution order
|
|
300
|
+
* Requirement: 11.6
|
|
301
|
+
*/
|
|
302
|
+
static calculateRecommendedOrder(tasks, dependencies) {
|
|
303
|
+
const order = [];
|
|
304
|
+
const completed = new Set();
|
|
305
|
+
// Note: Circular dependencies cannot occur with current inferDependencies
|
|
306
|
+
// implementation as it only references previous tasks
|
|
307
|
+
while (order.length < tasks.length) {
|
|
308
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
309
|
+
if (completed.has(i))
|
|
310
|
+
continue;
|
|
311
|
+
const dep = dependencies.find((d) => d.taskIndex === i);
|
|
312
|
+
if (!dep || dep.dependsOn.every((d) => completed.has(d))) {
|
|
313
|
+
order.push(i);
|
|
314
|
+
completed.add(i);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return order;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
//# sourceMappingURL=task-splitter.js.map
|