phaibel 4.0.7 ā 4.0.21
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/README.md +229 -245
- package/dist/commands/chat.d.ts +5 -2
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +168 -172
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/cron.d.ts.map +1 -1
- package/dist/commands/cron.js +1 -0
- package/dist/commands/cron.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +54 -52
- package/dist/commands/init.js.map +1 -1
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/entities/entity-summary.js +3 -3
- package/dist/entities/entity-type-config.d.ts +3 -0
- package/dist/entities/entity-type-config.d.ts.map +1 -1
- package/dist/entities/entity-type-config.js +67 -1
- package/dist/entities/entity-type-config.js.map +1 -1
- package/dist/entities/entity-types-defaults.d.ts.map +1 -1
- package/dist/entities/entity-types-defaults.js +2 -0
- package/dist/entities/entity-types-defaults.js.map +1 -1
- package/dist/entities/spawner.d.ts.map +1 -1
- package/dist/entities/spawner.js +4 -2
- package/dist/entities/spawner.js.map +1 -1
- package/dist/feral/catalog/entity-catalog-source.js +31 -31
- package/dist/feral/node-code/abstract-node-code.js +1 -1
- package/dist/feral/node-code/abstract-node-code.js.map +1 -1
- package/dist/feral/node-code/data/set-context-value-node-code.d.ts.map +1 -1
- package/dist/feral/node-code/data/set-context-value-node-code.js +10 -1
- package/dist/feral/node-code/data/set-context-value-node-code.js.map +1 -1
- package/dist/feral/node-code/entity/create-entity-type-node-code.js +20 -20
- package/dist/feral/node-code/entity/load-vault-context-node-code.d.ts.map +1 -1
- package/dist/feral/node-code/entity/load-vault-context-node-code.js +7 -15
- package/dist/feral/node-code/entity/load-vault-context-node-code.js.map +1 -1
- package/dist/feral/node-code/entity/update-entity-type-node-code.js +20 -20
- package/dist/feral/node-code/input/prompt-input-node-code.d.ts.map +1 -1
- package/dist/feral/node-code/input/prompt-input-node-code.js +6 -0
- package/dist/feral/node-code/input/prompt-input-node-code.js.map +1 -1
- package/dist/feral/node-code/input/prompt-select-node-code.d.ts.map +1 -1
- package/dist/feral/node-code/input/prompt-select-node-code.js +6 -0
- package/dist/feral/node-code/input/prompt-select-node-code.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -39
- package/dist/index.js.map +1 -1
- package/dist/llm/router.js +27 -27
- package/dist/personalities.js +4 -4
- package/dist/phaibel.txt +81 -81
- package/dist/service/api-router.d.ts.map +1 -1
- package/dist/service/api-router.js +42 -2
- package/dist/service/api-router.js.map +1 -1
- package/dist/service/cron/feedback-analysis.js +14 -14
- package/dist/service/cron/innovate.d.ts +2 -0
- package/dist/service/cron/innovate.d.ts.map +1 -0
- package/dist/service/cron/innovate.js +354 -0
- package/dist/service/cron/innovate.js.map +1 -0
- package/dist/service/cron/process-lifecycle.js +36 -36
- package/dist/service/cron/scheduler.d.ts.map +1 -1
- package/dist/service/cron/scheduler.js +8 -0
- package/dist/service/cron/scheduler.js.map +1 -1
- package/dist/service/index.d.ts.map +1 -1
- package/dist/service/index.js +27 -20
- package/dist/service/index.js.map +1 -1
- package/dist/service/web-client.html +1984 -1569
- package/dist/service/web-server.d.ts +1 -0
- package/dist/service/web-server.d.ts.map +1 -1
- package/dist/service/web-server.js +188 -6
- package/dist/service/web-server.js.map +1 -1
- package/dist/tools/daily.js +2 -2
- package/package.json +69 -66
- package/dist/agentary.txt +0 -82
- package/dist/commands/event.d.ts +0 -4
- package/dist/commands/event.d.ts.map +0 -1
- package/dist/commands/event.js +0 -515
- package/dist/commands/event.js.map +0 -1
- package/dist/commands/goal.d.ts +0 -4
- package/dist/commands/goal.d.ts.map +0 -1
- package/dist/commands/goal.js +0 -14
- package/dist/commands/goal.js.map +0 -1
- package/dist/commands/interview.d.ts +0 -14
- package/dist/commands/interview.d.ts.map +0 -1
- package/dist/commands/interview.js +0 -343
- package/dist/commands/interview.js.map +0 -1
- package/dist/commands/note.d.ts +0 -4
- package/dist/commands/note.d.ts.map +0 -1
- package/dist/commands/note.js +0 -548
- package/dist/commands/note.js.map +0 -1
- package/dist/commands/pamp.d.ts +0 -4
- package/dist/commands/pamp.d.ts.map +0 -1
- package/dist/commands/pamp.js +0 -323
- package/dist/commands/pamp.js.map +0 -1
- package/dist/commands/person.d.ts +0 -4
- package/dist/commands/person.d.ts.map +0 -1
- package/dist/commands/person.js +0 -185
- package/dist/commands/person.js.map +0 -1
- package/dist/commands/project.d.ts +0 -4
- package/dist/commands/project.d.ts.map +0 -1
- package/dist/commands/project.js +0 -70
- package/dist/commands/project.js.map +0 -1
- package/dist/commands/remember.d.ts +0 -4
- package/dist/commands/remember.d.ts.map +0 -1
- package/dist/commands/remember.js +0 -70
- package/dist/commands/remember.js.map +0 -1
- package/dist/commands/research.d.ts +0 -4
- package/dist/commands/research.d.ts.map +0 -1
- package/dist/commands/research.js +0 -14
- package/dist/commands/research.js.map +0 -1
- package/dist/commands/shell.d.ts +0 -3
- package/dist/commands/shell.d.ts.map +0 -1
- package/dist/commands/shell.js +0 -346
- package/dist/commands/shell.js.map +0 -1
- package/dist/commands/today.d.ts +0 -4
- package/dist/commands/today.d.ts.map +0 -1
- package/dist/commands/today.js +0 -112
- package/dist/commands/today.js.map +0 -1
- package/dist/commands/todo.d.ts +0 -4
- package/dist/commands/todo.d.ts.map +0 -1
- package/dist/commands/todo.js +0 -678
- package/dist/commands/todo.js.map +0 -1
- package/dist/commands/todont.d.ts +0 -19
- package/dist/commands/todont.d.ts.map +0 -1
- package/dist/commands/todont.js +0 -209
- package/dist/commands/todont.js.map +0 -1
- package/dist/commands/week.d.ts +0 -4
- package/dist/commands/week.d.ts.map +0 -1
- package/dist/commands/week.js +0 -267
- package/dist/commands/week.js.map +0 -1
- package/dist/dobbai.txt +0 -55
- package/dist/dobbi.txt +0 -55
- package/dist/dobbie-bundle.cjs +0 -73313
- package/dist/dobbie.txt +0 -55
- package/dist/feral/node-code/output/dobbai-speak-node-code.d.ts +0 -11
- package/dist/feral/node-code/output/dobbai-speak-node-code.d.ts.map +0 -1
- package/dist/feral/node-code/output/dobbai-speak-node-code.js +0 -56
- package/dist/feral/node-code/output/dobbai-speak-node-code.js.map +0 -1
- package/dist/feral/node-code/output/dobbi-speak-node-code.d.ts +0 -15
- package/dist/feral/node-code/output/dobbi-speak-node-code.d.ts.map +0 -1
- package/dist/feral/node-code/output/dobbi-speak-node-code.js +0 -60
- package/dist/feral/node-code/output/dobbi-speak-node-code.js.map +0 -1
- package/dist/feral/node-code/output/dobbie-speak-node-code.d.ts +0 -11
- package/dist/feral/node-code/output/dobbie-speak-node-code.d.ts.map +0 -1
- package/dist/feral/node-code/output/dobbie-speak-node-code.js +0 -56
- package/dist/feral/node-code/output/dobbie-speak-node-code.js.map +0 -1
- package/dist/service/cron/process-evaluator.d.ts +0 -6
- package/dist/service/cron/process-evaluator.d.ts.map +0 -1
- package/dist/service/cron/process-evaluator.js +0 -126
- package/dist/service/cron/process-evaluator.js.map +0 -1
- package/dist/tools/project.d.ts +0 -2
- package/dist/tools/project.d.ts.map +0 -1
- package/dist/tools/project.js +0 -112
- package/dist/tools/project.js.map +0 -1
package/dist/commands/todo.js
DELETED
|
@@ -1,678 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import chalk from 'chalk';
|
|
3
|
-
import inquirer from 'inquirer';
|
|
4
|
-
import { promises as fs } from 'fs';
|
|
5
|
-
import path from 'path';
|
|
6
|
-
import matter from 'gray-matter';
|
|
7
|
-
import { getVaultRoot } from '../state/manager.js';
|
|
8
|
-
import { getEnrichedContext } from '../context/reader.js';
|
|
9
|
-
import { getModelForCapability, createSystemPrompt } from '../llm/router.js';
|
|
10
|
-
import { getResponse } from '../responses.js';
|
|
11
|
-
import { renderEntityHeader, entityPrompt, todoHeaderConfig } from '../ui/entity-prompt.js';
|
|
12
|
-
import { pushCrumb, popCrumb } from '../ui/breadcrumb.js';
|
|
13
|
-
import { debug } from '../utils/debug.js';
|
|
14
|
-
import { listEntities } from './list.js';
|
|
15
|
-
import { getEntityIndex } from '../entities/entity-index.js';
|
|
16
|
-
import { findEntityByTitle, trashEntity, generateEntityId, entityFilename } from '../entities/entity.js';
|
|
17
|
-
async function findExistingTodo(titleOrFilename) {
|
|
18
|
-
const found = await findEntityByTitle('task', titleOrFilename);
|
|
19
|
-
if (!found)
|
|
20
|
-
return null;
|
|
21
|
-
return {
|
|
22
|
-
filepath: found.filepath,
|
|
23
|
-
title: found.meta.title,
|
|
24
|
-
content: found.content,
|
|
25
|
-
priority: found.meta.priority || 'medium',
|
|
26
|
-
dueDate: found.meta.dueDate,
|
|
27
|
-
completed: found.meta.status === 'done',
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
async function breakdownTodo(state) {
|
|
31
|
-
console.log(chalk.gray('\n' + getResponse('todo_breakdown')));
|
|
32
|
-
const context = await getEnrichedContext('todos', state.content);
|
|
33
|
-
const llm = await getModelForCapability('reason');
|
|
34
|
-
const systemPrompt = createSystemPrompt(context);
|
|
35
|
-
const response = await llm.chat([
|
|
36
|
-
{
|
|
37
|
-
role: 'user',
|
|
38
|
-
content: `Break down the following todo into smaller, actionable subtasks. Format as a markdown checklist with [ ] for each item. Keep each subtask specific and achievable.
|
|
39
|
-
|
|
40
|
-
Title: ${state.title}
|
|
41
|
-
|
|
42
|
-
Current Content:
|
|
43
|
-
${state.content || '(No details yet)'}`,
|
|
44
|
-
},
|
|
45
|
-
], { systemPrompt });
|
|
46
|
-
// Strip code fences if present
|
|
47
|
-
let formatted = response.trim();
|
|
48
|
-
if (formatted.startsWith('```markdown')) {
|
|
49
|
-
formatted = formatted.slice(11);
|
|
50
|
-
}
|
|
51
|
-
else if (formatted.startsWith('```')) {
|
|
52
|
-
formatted = formatted.slice(3);
|
|
53
|
-
}
|
|
54
|
-
if (formatted.endsWith('```')) {
|
|
55
|
-
formatted = formatted.slice(0, -3);
|
|
56
|
-
}
|
|
57
|
-
return formatted.trim();
|
|
58
|
-
}
|
|
59
|
-
async function clarifyTodo(state) {
|
|
60
|
-
console.log(chalk.gray('\n' + getResponse('processing')));
|
|
61
|
-
const context = await getEnrichedContext('todos', state.content);
|
|
62
|
-
const llm = await getModelForCapability('reason');
|
|
63
|
-
const systemPrompt = createSystemPrompt(context);
|
|
64
|
-
const response = await llm.chat([
|
|
65
|
-
{
|
|
66
|
-
role: 'user',
|
|
67
|
-
content: `Review and clarify the following todo. Make the description clearer, add context if helpful, and ensure the goal is specific and measurable. Return ONLY the improved content, no explanations.
|
|
68
|
-
|
|
69
|
-
Title: ${state.title}
|
|
70
|
-
Priority: ${state.priority}
|
|
71
|
-
${state.dueDate ? `Due: ${state.dueDate}` : ''}
|
|
72
|
-
|
|
73
|
-
Content:
|
|
74
|
-
${state.content || '(No details yet)'}`,
|
|
75
|
-
},
|
|
76
|
-
], { systemPrompt });
|
|
77
|
-
// Strip code fences if present
|
|
78
|
-
let formatted = response.trim();
|
|
79
|
-
if (formatted.startsWith('```markdown')) {
|
|
80
|
-
formatted = formatted.slice(11);
|
|
81
|
-
}
|
|
82
|
-
else if (formatted.startsWith('```')) {
|
|
83
|
-
formatted = formatted.slice(3);
|
|
84
|
-
}
|
|
85
|
-
if (formatted.endsWith('```')) {
|
|
86
|
-
formatted = formatted.slice(0, -3);
|
|
87
|
-
}
|
|
88
|
-
return formatted.trim();
|
|
89
|
-
}
|
|
90
|
-
async function estimateTodo(state) {
|
|
91
|
-
console.log(chalk.gray('\n' + getResponse('thinking')));
|
|
92
|
-
const context = await getEnrichedContext('todos', state.content);
|
|
93
|
-
const llm = await getModelForCapability('reason');
|
|
94
|
-
const systemPrompt = createSystemPrompt(context);
|
|
95
|
-
const response = await llm.chat([
|
|
96
|
-
{
|
|
97
|
-
role: 'user',
|
|
98
|
-
content: `Analyze the following todo and provide:
|
|
99
|
-
1. Time estimate (how long it will take)
|
|
100
|
-
2. Complexity rating (simple/moderate/complex)
|
|
101
|
-
3. Dependencies (what needs to be done first)
|
|
102
|
-
4. Suggested priority based on the content
|
|
103
|
-
|
|
104
|
-
Keep the analysis brief and actionable.
|
|
105
|
-
|
|
106
|
-
Title: ${state.title}
|
|
107
|
-
Current Priority: ${state.priority}
|
|
108
|
-
${state.dueDate ? `Due: ${state.dueDate}` : ''}
|
|
109
|
-
|
|
110
|
-
Content:
|
|
111
|
-
${state.content || '(No details yet)'}`,
|
|
112
|
-
},
|
|
113
|
-
], { systemPrompt });
|
|
114
|
-
return response.trim();
|
|
115
|
-
}
|
|
116
|
-
async function modifyTodo(state, feedback) {
|
|
117
|
-
console.log(chalk.gray('\n' + getResponse('processing')));
|
|
118
|
-
const context = await getEnrichedContext('todos', state.content);
|
|
119
|
-
const llm = await getModelForCapability('reason');
|
|
120
|
-
const systemPrompt = createSystemPrompt(context);
|
|
121
|
-
const response = await llm.chat([
|
|
122
|
-
{
|
|
123
|
-
role: 'user',
|
|
124
|
-
content: `Modify the following todo based on the user's feedback. Return ONLY the modified content, no explanations.
|
|
125
|
-
|
|
126
|
-
Title: ${state.title}
|
|
127
|
-
|
|
128
|
-
Current Content:
|
|
129
|
-
${state.content || '(No details yet)'}
|
|
130
|
-
|
|
131
|
-
User Feedback: ${feedback}`,
|
|
132
|
-
},
|
|
133
|
-
], { systemPrompt });
|
|
134
|
-
// Strip code fences if present
|
|
135
|
-
let formatted = response.trim();
|
|
136
|
-
if (formatted.startsWith('```markdown')) {
|
|
137
|
-
formatted = formatted.slice(11);
|
|
138
|
-
}
|
|
139
|
-
else if (formatted.startsWith('```')) {
|
|
140
|
-
formatted = formatted.slice(3);
|
|
141
|
-
}
|
|
142
|
-
if (formatted.endsWith('```')) {
|
|
143
|
-
formatted = formatted.slice(0, -3);
|
|
144
|
-
}
|
|
145
|
-
return formatted.trim();
|
|
146
|
-
}
|
|
147
|
-
async function formatTodo(state) {
|
|
148
|
-
console.log(chalk.gray('\n' + getResponse('processing')));
|
|
149
|
-
try {
|
|
150
|
-
const context = await getEnrichedContext('todos', state.content);
|
|
151
|
-
const llm = await getModelForCapability('format');
|
|
152
|
-
const systemPrompt = createSystemPrompt(context);
|
|
153
|
-
const response = await llm.chat([
|
|
154
|
-
{
|
|
155
|
-
role: 'user',
|
|
156
|
-
content: `Format the following todo content as clean, well-structured markdown. Use appropriate headers, lists, and emphasis. Keep all information intact.
|
|
157
|
-
|
|
158
|
-
IMPORTANT: Return ONLY the raw markdown content. Do NOT wrap in code fences.
|
|
159
|
-
|
|
160
|
-
Title: ${state.title}
|
|
161
|
-
|
|
162
|
-
Content:
|
|
163
|
-
${state.content}`,
|
|
164
|
-
},
|
|
165
|
-
], { systemPrompt });
|
|
166
|
-
// Strip code fences if present
|
|
167
|
-
let formatted = response.trim();
|
|
168
|
-
if (formatted.startsWith('```markdown')) {
|
|
169
|
-
formatted = formatted.slice(11);
|
|
170
|
-
}
|
|
171
|
-
else if (formatted.startsWith('```md')) {
|
|
172
|
-
formatted = formatted.slice(5);
|
|
173
|
-
}
|
|
174
|
-
else if (formatted.startsWith('```')) {
|
|
175
|
-
formatted = formatted.slice(3);
|
|
176
|
-
}
|
|
177
|
-
if (formatted.endsWith('```')) {
|
|
178
|
-
formatted = formatted.slice(0, -3);
|
|
179
|
-
}
|
|
180
|
-
return formatted.trim();
|
|
181
|
-
}
|
|
182
|
-
catch (err) {
|
|
183
|
-
debug('todo', err);
|
|
184
|
-
console.log(chalk.yellow('Formatting skipped (configure AI for formatting)'));
|
|
185
|
-
return state.content;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
async function saveTodo(state) {
|
|
189
|
-
const vaultRoot = await getVaultRoot();
|
|
190
|
-
const todosDir = path.join(vaultRoot, 'todos');
|
|
191
|
-
// Ensure todos directory exists
|
|
192
|
-
await fs.mkdir(todosDir, { recursive: true });
|
|
193
|
-
// Use existing filepath or create new one
|
|
194
|
-
let filepath = state.filepath;
|
|
195
|
-
let entityId;
|
|
196
|
-
if (filepath) {
|
|
197
|
-
// Editing ā read id from existing frontmatter
|
|
198
|
-
const raw = await fs.readFile(filepath, 'utf-8');
|
|
199
|
-
const parsed = matter(raw);
|
|
200
|
-
entityId = parsed.data.id ?? path.basename(filepath, '.md');
|
|
201
|
-
}
|
|
202
|
-
else {
|
|
203
|
-
entityId = generateEntityId('task');
|
|
204
|
-
filepath = path.join(todosDir, entityFilename(state.title, entityId));
|
|
205
|
-
}
|
|
206
|
-
// Format content before saving
|
|
207
|
-
const finalContent = await formatTodo(state);
|
|
208
|
-
// Create markdown with frontmatter
|
|
209
|
-
const today = new Date().toISOString().split('T')[0];
|
|
210
|
-
const markdown = `---
|
|
211
|
-
id: ${entityId}
|
|
212
|
-
title: "${state.title}"
|
|
213
|
-
created: ${today}
|
|
214
|
-
priority: ${state.priority}
|
|
215
|
-
${state.dueDate ? `dueDate: ${state.dueDate}` : ''}
|
|
216
|
-
completed: ${state.completed}
|
|
217
|
-
tags: [todo]
|
|
218
|
-
---
|
|
219
|
-
|
|
220
|
-
${finalContent}
|
|
221
|
-
`;
|
|
222
|
-
await fs.writeFile(filepath, markdown);
|
|
223
|
-
// Update entity index
|
|
224
|
-
const index = getEntityIndex();
|
|
225
|
-
if (index.isBuilt) {
|
|
226
|
-
await index.addOrUpdate('task', entityId, state.title, filepath);
|
|
227
|
-
}
|
|
228
|
-
return filepath;
|
|
229
|
-
}
|
|
230
|
-
function displayTodo(state) {
|
|
231
|
-
const priorityColors = {
|
|
232
|
-
low: chalk.gray,
|
|
233
|
-
medium: chalk.yellow,
|
|
234
|
-
high: chalk.red,
|
|
235
|
-
};
|
|
236
|
-
const priorityColor = priorityColors[state.priority];
|
|
237
|
-
const statusIcon = state.completed ? 'ā
' : 'ā¬';
|
|
238
|
-
console.log(chalk.cyan('\n' + 'ā'.repeat(50)));
|
|
239
|
-
console.log(`${statusIcon} ${chalk.bold.cyan(state.title)} ${priorityColor(`[${state.priority}]`)}`);
|
|
240
|
-
if (state.dueDate) {
|
|
241
|
-
console.log(chalk.gray(` Due: ${state.dueDate}`));
|
|
242
|
-
}
|
|
243
|
-
console.log(chalk.cyan('ā'.repeat(50)));
|
|
244
|
-
console.log(state.content || chalk.gray('(No details yet)'));
|
|
245
|
-
console.log(chalk.cyan('ā'.repeat(50) + '\n'));
|
|
246
|
-
}
|
|
247
|
-
function showHelp() {
|
|
248
|
-
console.log(chalk.gray(`
|
|
249
|
-
Commands:
|
|
250
|
-
${chalk.bold('breakdown')} - AI breaks the todo into subtasks
|
|
251
|
-
${chalk.bold('clarify')} - AI clarifies and improves the description
|
|
252
|
-
${chalk.bold('estimate')} - AI estimates time, complexity, dependencies
|
|
253
|
-
${chalk.bold('modify')} - AI modifies the todo based on your feedback
|
|
254
|
-
${chalk.bold('save')} - Save the current version
|
|
255
|
-
${chalk.bold('show')} - Display the current todo
|
|
256
|
-
${chalk.bold('edit')} - Edit the todo content
|
|
257
|
-
${chalk.bold('title')} - Change the title
|
|
258
|
-
${chalk.bold('priority')} - Set priority (low|medium|high)
|
|
259
|
-
${chalk.bold('due')} - Set due date
|
|
260
|
-
${chalk.bold('done')} - Mark as completed
|
|
261
|
-
${chalk.bold('exit')} - Save and go back
|
|
262
|
-
${chalk.bold('back')} - Save and go back
|
|
263
|
-
${chalk.bold('abort')} - Discard changes and go back
|
|
264
|
-
${chalk.bold('quit')} - Quit entirely
|
|
265
|
-
${chalk.bold('help')} - Show this help
|
|
266
|
-
`));
|
|
267
|
-
}
|
|
268
|
-
export const todoCommand = new Command('todo')
|
|
269
|
-
.description('Interactive todo management with AI assistance')
|
|
270
|
-
.argument('[words...]', 'Title and optional inline description (e.g. "fix-login The login 500s with plus signs")')
|
|
271
|
-
.action(async (words) => {
|
|
272
|
-
try {
|
|
273
|
-
// Handle: todo list
|
|
274
|
-
if (words[0] === 'list') {
|
|
275
|
-
await listEntities('todos');
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
// Handle: todo done <title>
|
|
279
|
-
if (words[0] === 'done') {
|
|
280
|
-
const doneTitle = words.slice(1).join(' ');
|
|
281
|
-
if (!doneTitle) {
|
|
282
|
-
console.log(chalk.yellow('\n Please specify which task to complete: todo done <title>\n'));
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
const existing = await findExistingTodo(doneTitle);
|
|
286
|
-
if (!existing) {
|
|
287
|
-
console.log(chalk.red(`\n ā Task "${doneTitle}" not found\n`));
|
|
288
|
-
return;
|
|
289
|
-
}
|
|
290
|
-
const doneState = {
|
|
291
|
-
title: existing.title,
|
|
292
|
-
content: existing.content,
|
|
293
|
-
priority: existing.priority,
|
|
294
|
-
dueDate: existing.dueDate,
|
|
295
|
-
filepath: existing.filepath,
|
|
296
|
-
isExisting: true,
|
|
297
|
-
completed: true,
|
|
298
|
-
};
|
|
299
|
-
const filepath = await saveTodo(doneState);
|
|
300
|
-
const msg = getResponse('task_complete');
|
|
301
|
-
console.log(chalk.green(`\n ā ${msg}`));
|
|
302
|
-
console.log(chalk.gray(` ${filepath}\n`));
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
// Handle: todo remove <title>
|
|
306
|
-
if (words[0] === 'remove' || words[0] === 'delete') {
|
|
307
|
-
const removeTitle = words.slice(1).join(' ');
|
|
308
|
-
if (!removeTitle) {
|
|
309
|
-
console.log(chalk.yellow('\n Please specify which task to remove: todo remove <title>\n'));
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
const existing = await findExistingTodo(removeTitle);
|
|
313
|
-
if (!existing) {
|
|
314
|
-
console.log(chalk.red(`\n ā Task "${removeTitle}" not found\n`));
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
// Read id from frontmatter before trashing
|
|
318
|
-
const raw = await fs.readFile(existing.filepath, 'utf-8');
|
|
319
|
-
const taskId = matter(raw).data.id ?? path.basename(existing.filepath, '.md');
|
|
320
|
-
const trashPath = await trashEntity(existing.filepath);
|
|
321
|
-
// Update entity index
|
|
322
|
-
const idx = getEntityIndex();
|
|
323
|
-
if (idx.isBuilt) {
|
|
324
|
-
idx.remove('task', taskId);
|
|
325
|
-
}
|
|
326
|
-
console.log(chalk.green(`\n š Moved to trash: ${existing.title}`));
|
|
327
|
-
console.log(chalk.gray(` ${trashPath}\n`));
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
// Parse: first word = title, rest = inline description
|
|
331
|
-
let title = words.length > 0 ? words[0] : undefined;
|
|
332
|
-
const inlineBody = words.length > 1 ? words.slice(1).join(' ') : undefined;
|
|
333
|
-
// Get title if not provided
|
|
334
|
-
if (!title) {
|
|
335
|
-
const { todoTitle } = await inquirer.prompt([
|
|
336
|
-
{
|
|
337
|
-
type: 'input',
|
|
338
|
-
name: 'todoTitle',
|
|
339
|
-
message: 'What task should be tracked?',
|
|
340
|
-
validate: (input) => input.length > 0 || 'Title is required',
|
|
341
|
-
},
|
|
342
|
-
]);
|
|
343
|
-
title = todoTitle;
|
|
344
|
-
}
|
|
345
|
-
// Check if todo already exists
|
|
346
|
-
const existing = await findExistingTodo(title);
|
|
347
|
-
let state;
|
|
348
|
-
if (existing) {
|
|
349
|
-
// Open existing todo ā if inline body, append to it
|
|
350
|
-
if (inlineBody) {
|
|
351
|
-
const updatedContent = existing.content
|
|
352
|
-
? existing.content + '\n\n' + inlineBody
|
|
353
|
-
: inlineBody;
|
|
354
|
-
state = {
|
|
355
|
-
title: existing.title,
|
|
356
|
-
content: updatedContent,
|
|
357
|
-
priority: existing.priority,
|
|
358
|
-
dueDate: existing.dueDate,
|
|
359
|
-
filepath: existing.filepath,
|
|
360
|
-
isExisting: true,
|
|
361
|
-
completed: existing.completed,
|
|
362
|
-
};
|
|
363
|
-
const filepath = await saveTodo(state);
|
|
364
|
-
console.log(chalk.green(`\nā Appended to "${existing.title}" ā ${filepath}`));
|
|
365
|
-
return;
|
|
366
|
-
}
|
|
367
|
-
console.log(chalk.green(`\nā Opening existing todo "${existing.title}"`));
|
|
368
|
-
state = {
|
|
369
|
-
title: existing.title,
|
|
370
|
-
content: existing.content,
|
|
371
|
-
priority: existing.priority,
|
|
372
|
-
dueDate: existing.dueDate,
|
|
373
|
-
filepath: existing.filepath,
|
|
374
|
-
isExisting: true,
|
|
375
|
-
completed: existing.completed,
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
else if (inlineBody) {
|
|
379
|
-
// Quick todo ā save immediately with medium priority
|
|
380
|
-
state = {
|
|
381
|
-
title: title,
|
|
382
|
-
content: inlineBody,
|
|
383
|
-
priority: 'medium',
|
|
384
|
-
dueDate: undefined,
|
|
385
|
-
isExisting: false,
|
|
386
|
-
completed: false,
|
|
387
|
-
};
|
|
388
|
-
const filepath = await saveTodo(state);
|
|
389
|
-
console.log(chalk.green(`\nā Quick todo saved ā ${filepath}`));
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
|
-
else {
|
|
393
|
-
// Create new todo - get initial details
|
|
394
|
-
const { priority } = await inquirer.prompt([
|
|
395
|
-
{
|
|
396
|
-
type: 'list',
|
|
397
|
-
name: 'priority',
|
|
398
|
-
message: 'Priority level?',
|
|
399
|
-
choices: [
|
|
400
|
-
{ name: 'Low', value: 'low' },
|
|
401
|
-
{ name: 'Medium', value: 'medium' },
|
|
402
|
-
{ name: 'High', value: 'high' },
|
|
403
|
-
],
|
|
404
|
-
default: 'medium',
|
|
405
|
-
},
|
|
406
|
-
]);
|
|
407
|
-
const { dueDate } = await inquirer.prompt([
|
|
408
|
-
{
|
|
409
|
-
type: 'input',
|
|
410
|
-
name: 'dueDate',
|
|
411
|
-
message: 'Due date (YYYY-MM-DD, or leave empty):',
|
|
412
|
-
validate: (input) => {
|
|
413
|
-
if (!input)
|
|
414
|
-
return true;
|
|
415
|
-
return /^\d{4}-\d{2}-\d{2}$/.test(input) || 'Use format YYYY-MM-DD';
|
|
416
|
-
},
|
|
417
|
-
},
|
|
418
|
-
]);
|
|
419
|
-
const { content } = await inquirer.prompt([
|
|
420
|
-
{
|
|
421
|
-
type: 'editor',
|
|
422
|
-
name: 'content',
|
|
423
|
-
message: 'Todo details (optional):',
|
|
424
|
-
},
|
|
425
|
-
]);
|
|
426
|
-
state = {
|
|
427
|
-
title: title,
|
|
428
|
-
content: content.trim(),
|
|
429
|
-
priority,
|
|
430
|
-
dueDate: dueDate || undefined,
|
|
431
|
-
isExisting: false,
|
|
432
|
-
completed: false,
|
|
433
|
-
};
|
|
434
|
-
console.log(chalk.green(`\nā Todo created`));
|
|
435
|
-
}
|
|
436
|
-
pushCrumb('todo');
|
|
437
|
-
renderEntityHeader(todoHeaderConfig(state));
|
|
438
|
-
showHelp();
|
|
439
|
-
displayTodo(state);
|
|
440
|
-
// Interactive loop
|
|
441
|
-
let running = true;
|
|
442
|
-
while (running) {
|
|
443
|
-
const { command } = await inquirer.prompt([
|
|
444
|
-
{
|
|
445
|
-
type: 'input',
|
|
446
|
-
name: 'command',
|
|
447
|
-
message: entityPrompt('todo'),
|
|
448
|
-
prefix: '',
|
|
449
|
-
},
|
|
450
|
-
]);
|
|
451
|
-
const cmd = command.trim().toLowerCase();
|
|
452
|
-
const parts = cmd.split(' ');
|
|
453
|
-
const action = parts[0];
|
|
454
|
-
const args = parts.slice(1).join(' ');
|
|
455
|
-
switch (action) {
|
|
456
|
-
case 'save': {
|
|
457
|
-
const filepath = await saveTodo(state);
|
|
458
|
-
console.log(chalk.green(`\nā Todo saved to ${filepath}, sir!`));
|
|
459
|
-
break;
|
|
460
|
-
}
|
|
461
|
-
case 'exit': {
|
|
462
|
-
const filepath = await saveTodo(state);
|
|
463
|
-
console.log(chalk.green(`\nā Todo saved to ${filepath}, sir!`));
|
|
464
|
-
running = false;
|
|
465
|
-
break;
|
|
466
|
-
}
|
|
467
|
-
case 'back':
|
|
468
|
-
case 'b': {
|
|
469
|
-
const filepath = await saveTodo(state);
|
|
470
|
-
console.log(chalk.green(`\nā Todo saved to ${filepath}, sir!`));
|
|
471
|
-
running = false;
|
|
472
|
-
break;
|
|
473
|
-
}
|
|
474
|
-
case 'abort': {
|
|
475
|
-
const { confirm } = await inquirer.prompt([
|
|
476
|
-
{
|
|
477
|
-
type: 'confirm',
|
|
478
|
-
name: 'confirm',
|
|
479
|
-
message: 'There is unsaved work. Discard changes?',
|
|
480
|
-
default: false,
|
|
481
|
-
},
|
|
482
|
-
]);
|
|
483
|
-
if (confirm) {
|
|
484
|
-
console.log(chalk.yellow(getResponse('task_discarded')));
|
|
485
|
-
running = false;
|
|
486
|
-
}
|
|
487
|
-
break;
|
|
488
|
-
}
|
|
489
|
-
case 'quit':
|
|
490
|
-
case 'q': {
|
|
491
|
-
const { confirm: quitConfirm } = await inquirer.prompt([
|
|
492
|
-
{
|
|
493
|
-
type: 'confirm',
|
|
494
|
-
name: 'confirm',
|
|
495
|
-
message: 'There is unsaved work. Quit entirely?',
|
|
496
|
-
default: false,
|
|
497
|
-
},
|
|
498
|
-
]);
|
|
499
|
-
if (quitConfirm) {
|
|
500
|
-
console.log(chalk.yellow(getResponse('farewell')));
|
|
501
|
-
process.exit(42);
|
|
502
|
-
}
|
|
503
|
-
break;
|
|
504
|
-
}
|
|
505
|
-
case 'breakdown': {
|
|
506
|
-
try {
|
|
507
|
-
const breakdown = await breakdownTodo(state);
|
|
508
|
-
state.content = state.content ? state.content + '\n\n## Subtasks\n\n' + breakdown : breakdown;
|
|
509
|
-
console.log(chalk.green('ā Todo broken down into subtasks!'));
|
|
510
|
-
displayTodo(state);
|
|
511
|
-
}
|
|
512
|
-
catch (error) {
|
|
513
|
-
console.error(chalk.red('Error breaking down todo:'), error);
|
|
514
|
-
}
|
|
515
|
-
break;
|
|
516
|
-
}
|
|
517
|
-
case 'clarify': {
|
|
518
|
-
try {
|
|
519
|
-
state.content = await clarifyTodo(state);
|
|
520
|
-
console.log(chalk.green('ā Todo clarified!'));
|
|
521
|
-
displayTodo(state);
|
|
522
|
-
}
|
|
523
|
-
catch (error) {
|
|
524
|
-
console.error(chalk.red('Error clarifying todo:'), error);
|
|
525
|
-
}
|
|
526
|
-
break;
|
|
527
|
-
}
|
|
528
|
-
case 'estimate': {
|
|
529
|
-
try {
|
|
530
|
-
const estimate = await estimateTodo(state);
|
|
531
|
-
console.log(chalk.cyan('\nš Estimate:\n'));
|
|
532
|
-
console.log(estimate);
|
|
533
|
-
console.log('');
|
|
534
|
-
}
|
|
535
|
-
catch (error) {
|
|
536
|
-
console.error(chalk.red('Error estimating todo:'), error);
|
|
537
|
-
}
|
|
538
|
-
break;
|
|
539
|
-
}
|
|
540
|
-
case 'modify': {
|
|
541
|
-
if (!args) {
|
|
542
|
-
const { feedback } = await inquirer.prompt([
|
|
543
|
-
{
|
|
544
|
-
type: 'input',
|
|
545
|
-
name: 'feedback',
|
|
546
|
-
message: 'How should the todo be modified?',
|
|
547
|
-
},
|
|
548
|
-
]);
|
|
549
|
-
if (feedback) {
|
|
550
|
-
try {
|
|
551
|
-
state.content = await modifyTodo(state, feedback);
|
|
552
|
-
console.log(chalk.green('ā Todo modified!'));
|
|
553
|
-
displayTodo(state);
|
|
554
|
-
}
|
|
555
|
-
catch (error) {
|
|
556
|
-
console.error(chalk.red('Error modifying todo:'), error);
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
else {
|
|
561
|
-
try {
|
|
562
|
-
state.content = await modifyTodo(state, args);
|
|
563
|
-
console.log(chalk.green('ā Todo modified!'));
|
|
564
|
-
displayTodo(state);
|
|
565
|
-
}
|
|
566
|
-
catch (error) {
|
|
567
|
-
console.error(chalk.red('Error modifying todo:'), error);
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
break;
|
|
571
|
-
}
|
|
572
|
-
case 'show': {
|
|
573
|
-
displayTodo(state);
|
|
574
|
-
break;
|
|
575
|
-
}
|
|
576
|
-
case 'edit': {
|
|
577
|
-
const { newContent } = await inquirer.prompt([
|
|
578
|
-
{
|
|
579
|
-
type: 'editor',
|
|
580
|
-
name: 'newContent',
|
|
581
|
-
message: 'Edit todo:',
|
|
582
|
-
default: state.content,
|
|
583
|
-
},
|
|
584
|
-
]);
|
|
585
|
-
state.content = newContent.trim();
|
|
586
|
-
console.log(chalk.green('ā Todo updated!'));
|
|
587
|
-
displayTodo(state);
|
|
588
|
-
break;
|
|
589
|
-
}
|
|
590
|
-
case 'title': {
|
|
591
|
-
const { newTitle } = await inquirer.prompt([
|
|
592
|
-
{
|
|
593
|
-
type: 'input',
|
|
594
|
-
name: 'newTitle',
|
|
595
|
-
message: 'New title:',
|
|
596
|
-
default: state.title,
|
|
597
|
-
},
|
|
598
|
-
]);
|
|
599
|
-
state.title = newTitle;
|
|
600
|
-
console.log(chalk.green(`ā Title changed to "${newTitle}"`));
|
|
601
|
-
break;
|
|
602
|
-
}
|
|
603
|
-
case 'priority': {
|
|
604
|
-
const newPriority = args;
|
|
605
|
-
if (['low', 'medium', 'high'].includes(newPriority)) {
|
|
606
|
-
state.priority = newPriority;
|
|
607
|
-
console.log(chalk.green(`ā Priority set to ${newPriority}`));
|
|
608
|
-
}
|
|
609
|
-
else {
|
|
610
|
-
const { selectedPriority } = await inquirer.prompt([
|
|
611
|
-
{
|
|
612
|
-
type: 'list',
|
|
613
|
-
name: 'selectedPriority',
|
|
614
|
-
message: 'Select priority:',
|
|
615
|
-
choices: ['low', 'medium', 'high'],
|
|
616
|
-
default: state.priority,
|
|
617
|
-
},
|
|
618
|
-
]);
|
|
619
|
-
state.priority = selectedPriority;
|
|
620
|
-
console.log(chalk.green(`ā Priority set to ${selectedPriority}`));
|
|
621
|
-
}
|
|
622
|
-
displayTodo(state);
|
|
623
|
-
break;
|
|
624
|
-
}
|
|
625
|
-
case 'due': {
|
|
626
|
-
if (args && /^\d{4}-\d{2}-\d{2}$/.test(args)) {
|
|
627
|
-
state.dueDate = args;
|
|
628
|
-
console.log(chalk.green(`ā Due date set to ${args}`));
|
|
629
|
-
}
|
|
630
|
-
else {
|
|
631
|
-
const { newDueDate } = await inquirer.prompt([
|
|
632
|
-
{
|
|
633
|
-
type: 'input',
|
|
634
|
-
name: 'newDueDate',
|
|
635
|
-
message: 'Due date (YYYY-MM-DD):',
|
|
636
|
-
default: state.dueDate || '',
|
|
637
|
-
validate: (input) => {
|
|
638
|
-
if (!input)
|
|
639
|
-
return true;
|
|
640
|
-
return /^\d{4}-\d{2}-\d{2}$/.test(input) || 'Use format YYYY-MM-DD';
|
|
641
|
-
},
|
|
642
|
-
},
|
|
643
|
-
]);
|
|
644
|
-
state.dueDate = newDueDate || undefined;
|
|
645
|
-
console.log(chalk.green(newDueDate ? `ā Due date set to ${newDueDate}` : 'ā Due date cleared'));
|
|
646
|
-
}
|
|
647
|
-
displayTodo(state);
|
|
648
|
-
break;
|
|
649
|
-
}
|
|
650
|
-
case 'done': {
|
|
651
|
-
state.completed = !state.completed;
|
|
652
|
-
console.log(chalk.green(state.completed ? 'ā Marked as completed!' : 'ā Marked as incomplete'));
|
|
653
|
-
displayTodo(state);
|
|
654
|
-
break;
|
|
655
|
-
}
|
|
656
|
-
case 'help':
|
|
657
|
-
case '?': {
|
|
658
|
-
showHelp();
|
|
659
|
-
break;
|
|
660
|
-
}
|
|
661
|
-
case '': {
|
|
662
|
-
// Empty command, ignore
|
|
663
|
-
break;
|
|
664
|
-
}
|
|
665
|
-
default: {
|
|
666
|
-
console.log(chalk.yellow(`Unknown command: ${action}. Type 'help' for options.`));
|
|
667
|
-
break;
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
popCrumb();
|
|
672
|
-
}
|
|
673
|
-
catch (error) {
|
|
674
|
-
console.error(chalk.red(getResponse('error')), error);
|
|
675
|
-
}
|
|
676
|
-
});
|
|
677
|
-
export default todoCommand;
|
|
678
|
-
//# sourceMappingURL=todo.js.map
|