@a13xu/lucid 1.9.5 → 1.10.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/build/database.d.ts +32 -0
- package/build/database.js +38 -0
- package/build/index.js +84 -1
- package/build/tools/plan.d.ts +75 -0
- package/build/tools/plan.js +148 -0
- package/package.json +1 -1
package/build/database.d.ts
CHANGED
|
@@ -36,6 +36,27 @@ export interface FileRewardRow {
|
|
|
36
36
|
use_count: number;
|
|
37
37
|
last_rewarded: number | null;
|
|
38
38
|
}
|
|
39
|
+
export interface PlanRow {
|
|
40
|
+
id: number;
|
|
41
|
+
title: string;
|
|
42
|
+
description: string;
|
|
43
|
+
user_story: string;
|
|
44
|
+
status: string;
|
|
45
|
+
created_at: number;
|
|
46
|
+
updated_at: number;
|
|
47
|
+
}
|
|
48
|
+
export interface PlanTaskRow {
|
|
49
|
+
id: number;
|
|
50
|
+
plan_id: number;
|
|
51
|
+
seq: number;
|
|
52
|
+
title: string;
|
|
53
|
+
description: string;
|
|
54
|
+
test_criteria: string;
|
|
55
|
+
status: string;
|
|
56
|
+
notes: string;
|
|
57
|
+
created_at: number;
|
|
58
|
+
updated_at: number;
|
|
59
|
+
}
|
|
39
60
|
export interface Statements {
|
|
40
61
|
getFileByPath: Stmt<[string], FileContentRow>;
|
|
41
62
|
upsertFile: WriteStmt<[string, Buffer, string, number, number, string]>;
|
|
@@ -83,6 +104,17 @@ export interface Statements {
|
|
|
83
104
|
upsertFileReward: WriteStmt<[string, number]>;
|
|
84
105
|
getFileRewards: Stmt<[], FileRewardRow>;
|
|
85
106
|
getTopFileRewards: Stmt<[number], FileRewardRow>;
|
|
107
|
+
insertPlan: WriteStmt<[string, string, string]>;
|
|
108
|
+
getPlanById: Stmt<[number], PlanRow>;
|
|
109
|
+
getAllPlans: Stmt<[], PlanRow>;
|
|
110
|
+
updatePlanStatus: WriteStmt<[string, number]>;
|
|
111
|
+
insertPlanTask: WriteStmt<[number, number, string, string, string]>;
|
|
112
|
+
getTasksByPlanId: Stmt<[number], PlanTaskRow>;
|
|
113
|
+
getTaskById: Stmt<[number], PlanTaskRow>;
|
|
114
|
+
updateTaskStatus: WriteStmt<[string, string, number]>;
|
|
115
|
+
countRemainingTasks: Stmt<[number], {
|
|
116
|
+
count: number;
|
|
117
|
+
}>;
|
|
86
118
|
}
|
|
87
119
|
export declare function prepareStatements(db: Database.Database): Statements;
|
|
88
120
|
export {};
|
package/build/database.js
CHANGED
|
@@ -143,6 +143,33 @@ function createSchema(db) {
|
|
|
143
143
|
use_count INTEGER NOT NULL DEFAULT 0,
|
|
144
144
|
last_rewarded INTEGER
|
|
145
145
|
);
|
|
146
|
+
|
|
147
|
+
-- Planning tables
|
|
148
|
+
CREATE TABLE IF NOT EXISTS plans (
|
|
149
|
+
id INTEGER PRIMARY KEY,
|
|
150
|
+
title TEXT NOT NULL,
|
|
151
|
+
description TEXT NOT NULL,
|
|
152
|
+
user_story TEXT NOT NULL,
|
|
153
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
154
|
+
created_at INTEGER DEFAULT (unixepoch()),
|
|
155
|
+
updated_at INTEGER DEFAULT (unixepoch())
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
CREATE TABLE IF NOT EXISTS plan_tasks (
|
|
159
|
+
id INTEGER PRIMARY KEY,
|
|
160
|
+
plan_id INTEGER NOT NULL REFERENCES plans(id) ON DELETE CASCADE,
|
|
161
|
+
seq INTEGER NOT NULL,
|
|
162
|
+
title TEXT NOT NULL,
|
|
163
|
+
description TEXT NOT NULL,
|
|
164
|
+
test_criteria TEXT NOT NULL,
|
|
165
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
166
|
+
notes TEXT NOT NULL DEFAULT '[]',
|
|
167
|
+
created_at INTEGER DEFAULT (unixepoch()),
|
|
168
|
+
updated_at INTEGER DEFAULT (unixepoch())
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
CREATE INDEX IF NOT EXISTS idx_plan_tasks_plan ON plan_tasks(plan_id, seq);
|
|
172
|
+
CREATE INDEX IF NOT EXISTS idx_plans_status ON plans(status);
|
|
146
173
|
`);
|
|
147
174
|
}
|
|
148
175
|
export function prepareStatements(db) {
|
|
@@ -223,5 +250,16 @@ export function prepareStatements(db) {
|
|
|
223
250
|
last_rewarded = unixepoch()`),
|
|
224
251
|
getFileRewards: db.prepare("SELECT * FROM file_rewards"),
|
|
225
252
|
getTopFileRewards: db.prepare("SELECT * FROM file_rewards WHERE total_reward > 0 ORDER BY total_reward DESC LIMIT ?"),
|
|
253
|
+
// plans
|
|
254
|
+
insertPlan: db.prepare("INSERT INTO plans (title, description, user_story) VALUES (?, ?, ?)"),
|
|
255
|
+
getPlanById: db.prepare("SELECT * FROM plans WHERE id = ?"),
|
|
256
|
+
getAllPlans: db.prepare("SELECT * FROM plans ORDER BY created_at DESC"),
|
|
257
|
+
updatePlanStatus: db.prepare("UPDATE plans SET status = ?, updated_at = unixepoch() WHERE id = ?"),
|
|
258
|
+
// plan_tasks
|
|
259
|
+
insertPlanTask: db.prepare("INSERT INTO plan_tasks (plan_id, seq, title, description, test_criteria) VALUES (?, ?, ?, ?, ?)"),
|
|
260
|
+
getTasksByPlanId: db.prepare("SELECT * FROM plan_tasks WHERE plan_id = ? ORDER BY seq"),
|
|
261
|
+
getTaskById: db.prepare("SELECT * FROM plan_tasks WHERE id = ?"),
|
|
262
|
+
updateTaskStatus: db.prepare("UPDATE plan_tasks SET status = ?, notes = ?, updated_at = unixepoch() WHERE id = ?"),
|
|
263
|
+
countRemainingTasks: db.prepare("SELECT COUNT(*) as count FROM plan_tasks WHERE plan_id = ? AND status != 'done'"),
|
|
226
264
|
};
|
|
227
265
|
}
|
package/build/index.js
CHANGED
|
@@ -20,6 +20,7 @@ import { handleSyncFile, SyncFileSchema, handleSyncProject, SyncProjectSchema, }
|
|
|
20
20
|
import { handleGetContext, GetContextSchema, handleGetRecent, GetRecentSchema, } from "./tools/context.js";
|
|
21
21
|
import { handleReward, RewardSchema, handlePenalize, PenalizeSchema, handleShowRewards, ShowRewardsSchema, } from "./tools/reward.js";
|
|
22
22
|
import { handleGetCodingRules, handleCheckCodeQuality, CheckCodeQualitySchema, } from "./tools/coding-guard.js";
|
|
23
|
+
import { handlePlanCreate, PlanCreateSchema, handlePlanList, PlanListSchema, handlePlanGet, PlanGetSchema, handlePlanUpdateTask, PlanUpdateTaskSchema, } from "./tools/plan.js";
|
|
23
24
|
// ---------------------------------------------------------------------------
|
|
24
25
|
// Init DB
|
|
25
26
|
// ---------------------------------------------------------------------------
|
|
@@ -52,7 +53,7 @@ else {
|
|
|
52
53
|
// ---------------------------------------------------------------------------
|
|
53
54
|
// MCP Server
|
|
54
55
|
// ---------------------------------------------------------------------------
|
|
55
|
-
const server = new Server({ name: "lucid", version: "1.
|
|
56
|
+
const server = new Server({ name: "lucid", version: "1.10.0" }, { capabilities: { tools: {} } });
|
|
56
57
|
// ---------------------------------------------------------------------------
|
|
57
58
|
// Tool definitions
|
|
58
59
|
// ---------------------------------------------------------------------------
|
|
@@ -322,6 +323,75 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
322
323
|
},
|
|
323
324
|
},
|
|
324
325
|
},
|
|
326
|
+
// ── Planning ─────────────────────────────────────────────────────────────
|
|
327
|
+
{
|
|
328
|
+
name: "plan_create",
|
|
329
|
+
description: "Create a plan with user story, ordered tasks, and test criteria. " +
|
|
330
|
+
"Call BEFORE writing any code to establish intent and acceptance criteria.",
|
|
331
|
+
inputSchema: {
|
|
332
|
+
type: "object",
|
|
333
|
+
properties: {
|
|
334
|
+
title: { type: "string", description: "Short plan title." },
|
|
335
|
+
description: { type: "string", description: "What this plan accomplishes." },
|
|
336
|
+
user_story: { type: "string", description: "As a [user], I want [goal], so that [benefit]." },
|
|
337
|
+
tasks: {
|
|
338
|
+
type: "array",
|
|
339
|
+
description: "Ordered list of implementation tasks (1–20).",
|
|
340
|
+
items: {
|
|
341
|
+
type: "object",
|
|
342
|
+
properties: {
|
|
343
|
+
title: { type: "string" },
|
|
344
|
+
description: { type: "string" },
|
|
345
|
+
test_criteria: { type: "string", description: "How to verify this task is done." },
|
|
346
|
+
},
|
|
347
|
+
required: ["title", "description", "test_criteria"],
|
|
348
|
+
},
|
|
349
|
+
minItems: 1,
|
|
350
|
+
maxItems: 20,
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
required: ["title", "description", "user_story", "tasks"],
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
name: "plan_list",
|
|
358
|
+
description: "List plans with progress summary. Defaults to active plans.",
|
|
359
|
+
inputSchema: {
|
|
360
|
+
type: "object",
|
|
361
|
+
properties: {
|
|
362
|
+
status: {
|
|
363
|
+
type: "string",
|
|
364
|
+
enum: ["active", "completed", "abandoned", "all"],
|
|
365
|
+
description: "Filter by plan status (default: active).",
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
name: "plan_get",
|
|
372
|
+
description: "Get full plan details: tasks, test criteria, status, and notes.",
|
|
373
|
+
inputSchema: {
|
|
374
|
+
type: "object",
|
|
375
|
+
properties: {
|
|
376
|
+
plan_id: { type: "number", description: "Plan ID from plan_create or plan_list." },
|
|
377
|
+
},
|
|
378
|
+
required: ["plan_id"],
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
name: "plan_update_task",
|
|
383
|
+
description: "Update a task status. Auto-completes the plan when all tasks are done. " +
|
|
384
|
+
"Statuses: pending → in_progress → done (or blocked).",
|
|
385
|
+
inputSchema: {
|
|
386
|
+
type: "object",
|
|
387
|
+
properties: {
|
|
388
|
+
task_id: { type: "number", description: "Task ID from plan_get." },
|
|
389
|
+
status: { type: "string", enum: ["pending", "in_progress", "done", "blocked"] },
|
|
390
|
+
note: { type: "string", description: "Optional note appended to task history." },
|
|
391
|
+
},
|
|
392
|
+
required: ["task_id", "status"],
|
|
393
|
+
},
|
|
394
|
+
},
|
|
325
395
|
],
|
|
326
396
|
}));
|
|
327
397
|
// ---------------------------------------------------------------------------
|
|
@@ -404,6 +474,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
404
474
|
case "check_code_quality":
|
|
405
475
|
text = handleCheckCodeQuality(CheckCodeQualitySchema.parse(args));
|
|
406
476
|
break;
|
|
477
|
+
// Planning
|
|
478
|
+
case "plan_create":
|
|
479
|
+
text = handlePlanCreate(db, stmts, PlanCreateSchema.parse(args));
|
|
480
|
+
break;
|
|
481
|
+
case "plan_list":
|
|
482
|
+
text = handlePlanList(stmts, PlanListSchema.parse(args));
|
|
483
|
+
break;
|
|
484
|
+
case "plan_get":
|
|
485
|
+
text = handlePlanGet(stmts, PlanGetSchema.parse(args));
|
|
486
|
+
break;
|
|
487
|
+
case "plan_update_task":
|
|
488
|
+
text = handlePlanUpdateTask(stmts, PlanUpdateTaskSchema.parse(args));
|
|
489
|
+
break;
|
|
407
490
|
default:
|
|
408
491
|
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
|
409
492
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import type { Statements } from "../database.js";
|
|
4
|
+
export declare const PlanCreateSchema: z.ZodObject<{
|
|
5
|
+
title: z.ZodString;
|
|
6
|
+
description: z.ZodString;
|
|
7
|
+
user_story: z.ZodString;
|
|
8
|
+
tasks: z.ZodArray<z.ZodObject<{
|
|
9
|
+
title: z.ZodString;
|
|
10
|
+
description: z.ZodString;
|
|
11
|
+
test_criteria: z.ZodString;
|
|
12
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
|
+
description: string;
|
|
14
|
+
title: string;
|
|
15
|
+
test_criteria: string;
|
|
16
|
+
}, {
|
|
17
|
+
description: string;
|
|
18
|
+
title: string;
|
|
19
|
+
test_criteria: string;
|
|
20
|
+
}>, "many">;
|
|
21
|
+
}, "strip", z.ZodTypeAny, {
|
|
22
|
+
description: string;
|
|
23
|
+
title: string;
|
|
24
|
+
user_story: string;
|
|
25
|
+
tasks: {
|
|
26
|
+
description: string;
|
|
27
|
+
title: string;
|
|
28
|
+
test_criteria: string;
|
|
29
|
+
}[];
|
|
30
|
+
}, {
|
|
31
|
+
description: string;
|
|
32
|
+
title: string;
|
|
33
|
+
user_story: string;
|
|
34
|
+
tasks: {
|
|
35
|
+
description: string;
|
|
36
|
+
title: string;
|
|
37
|
+
test_criteria: string;
|
|
38
|
+
}[];
|
|
39
|
+
}>;
|
|
40
|
+
export declare const PlanListSchema: z.ZodObject<{
|
|
41
|
+
status: z.ZodDefault<z.ZodOptional<z.ZodEnum<["active", "completed", "abandoned", "all"]>>>;
|
|
42
|
+
}, "strip", z.ZodTypeAny, {
|
|
43
|
+
status: "all" | "active" | "completed" | "abandoned";
|
|
44
|
+
}, {
|
|
45
|
+
status?: "all" | "active" | "completed" | "abandoned" | undefined;
|
|
46
|
+
}>;
|
|
47
|
+
export declare const PlanGetSchema: z.ZodObject<{
|
|
48
|
+
plan_id: z.ZodNumber;
|
|
49
|
+
}, "strip", z.ZodTypeAny, {
|
|
50
|
+
plan_id: number;
|
|
51
|
+
}, {
|
|
52
|
+
plan_id: number;
|
|
53
|
+
}>;
|
|
54
|
+
export declare const PlanUpdateTaskSchema: z.ZodObject<{
|
|
55
|
+
task_id: z.ZodNumber;
|
|
56
|
+
status: z.ZodEnum<["pending", "in_progress", "done", "blocked"]>;
|
|
57
|
+
note: z.ZodOptional<z.ZodString>;
|
|
58
|
+
}, "strip", z.ZodTypeAny, {
|
|
59
|
+
status: "blocked" | "done" | "pending" | "in_progress";
|
|
60
|
+
task_id: number;
|
|
61
|
+
note?: string | undefined;
|
|
62
|
+
}, {
|
|
63
|
+
status: "blocked" | "done" | "pending" | "in_progress";
|
|
64
|
+
task_id: number;
|
|
65
|
+
note?: string | undefined;
|
|
66
|
+
}>;
|
|
67
|
+
type PlanCreateArgs = z.infer<typeof PlanCreateSchema>;
|
|
68
|
+
type PlanListArgs = z.infer<typeof PlanListSchema>;
|
|
69
|
+
type PlanGetArgs = z.infer<typeof PlanGetSchema>;
|
|
70
|
+
type PlanUpdateTaskArgs = z.infer<typeof PlanUpdateTaskSchema>;
|
|
71
|
+
export declare function handlePlanCreate(db: Database.Database, stmts: Statements, args: PlanCreateArgs): string;
|
|
72
|
+
export declare function handlePlanList(stmts: Statements, args: PlanListArgs): string;
|
|
73
|
+
export declare function handlePlanGet(stmts: Statements, args: PlanGetArgs): string;
|
|
74
|
+
export declare function handlePlanUpdateTask(stmts: Statements, args: PlanUpdateTaskArgs): string;
|
|
75
|
+
export {};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Zod schemas
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
export const PlanCreateSchema = z.object({
|
|
6
|
+
title: z.string().min(1),
|
|
7
|
+
description: z.string().min(1),
|
|
8
|
+
user_story: z.string().min(1).describe("As a [user], I want [goal], so that [benefit]"),
|
|
9
|
+
tasks: z.array(z.object({
|
|
10
|
+
title: z.string().min(1),
|
|
11
|
+
description: z.string().min(1),
|
|
12
|
+
test_criteria: z.string().min(1),
|
|
13
|
+
})).min(1).max(20),
|
|
14
|
+
});
|
|
15
|
+
export const PlanListSchema = z.object({
|
|
16
|
+
status: z.enum(["active", "completed", "abandoned", "all"]).optional().default("active"),
|
|
17
|
+
});
|
|
18
|
+
export const PlanGetSchema = z.object({
|
|
19
|
+
plan_id: z.number().int().positive(),
|
|
20
|
+
});
|
|
21
|
+
export const PlanUpdateTaskSchema = z.object({
|
|
22
|
+
task_id: z.number().int().positive(),
|
|
23
|
+
status: z.enum(["pending", "in_progress", "done", "blocked"]),
|
|
24
|
+
note: z.string().optional(),
|
|
25
|
+
});
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Helpers
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
const STATUS_ICONS = {
|
|
30
|
+
pending: "⬜",
|
|
31
|
+
in_progress: "🔄",
|
|
32
|
+
done: "✅",
|
|
33
|
+
blocked: "🚫",
|
|
34
|
+
};
|
|
35
|
+
const PLAN_STATUS_ICONS = {
|
|
36
|
+
active: "active",
|
|
37
|
+
completed: "completed",
|
|
38
|
+
abandoned: "abandoned",
|
|
39
|
+
};
|
|
40
|
+
function progressBar(done, total) {
|
|
41
|
+
if (total === 0)
|
|
42
|
+
return "░".repeat(10);
|
|
43
|
+
const filled = Math.round((done / total) * 10);
|
|
44
|
+
return "█".repeat(filled) + "░".repeat(10 - filled);
|
|
45
|
+
}
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Handlers
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
export function handlePlanCreate(db, stmts, args) {
|
|
50
|
+
const { title, description, user_story, tasks } = args;
|
|
51
|
+
const planId = db.transaction(() => {
|
|
52
|
+
const result = stmts.insertPlan.run(title, description, user_story);
|
|
53
|
+
const id = result.lastInsertRowid;
|
|
54
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
55
|
+
const t = tasks[i];
|
|
56
|
+
stmts.insertPlanTask.run(id, i + 1, t.title, t.description, t.test_criteria);
|
|
57
|
+
}
|
|
58
|
+
return id;
|
|
59
|
+
})();
|
|
60
|
+
const lines = [
|
|
61
|
+
`[PLAN #${planId} active] ${title}`,
|
|
62
|
+
`User Story: ${user_story}`,
|
|
63
|
+
``,
|
|
64
|
+
];
|
|
65
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
66
|
+
lines.push(`[TASK ${i + 1} #${planId * 100 + i + 1} pending] ${tasks[i].title}`);
|
|
67
|
+
}
|
|
68
|
+
lines.push(``, `Progress: 0/${tasks.length} done`);
|
|
69
|
+
return lines.join("\n");
|
|
70
|
+
}
|
|
71
|
+
export function handlePlanList(stmts, args) {
|
|
72
|
+
const { status } = args;
|
|
73
|
+
const all = stmts.getAllPlans.all();
|
|
74
|
+
const filtered = status === "all" ? all : all.filter(p => p.status === status);
|
|
75
|
+
if (filtered.length === 0) {
|
|
76
|
+
return `No ${status === "all" ? "" : status + " "}plans found.`;
|
|
77
|
+
}
|
|
78
|
+
const lines = [];
|
|
79
|
+
for (const plan of filtered) {
|
|
80
|
+
const tasks = stmts.getTasksByPlanId.all(plan.id);
|
|
81
|
+
const doneCount = tasks.filter(t => t.status === "done").length;
|
|
82
|
+
const label = PLAN_STATUS_ICONS[plan.status] ?? plan.status;
|
|
83
|
+
lines.push(`[#${plan.id} ${label}] ${plan.title} — ${doneCount}/${tasks.length} tasks done`);
|
|
84
|
+
}
|
|
85
|
+
return lines.join("\n");
|
|
86
|
+
}
|
|
87
|
+
export function handlePlanGet(stmts, args) {
|
|
88
|
+
const plan = stmts.getPlanById.get(args.plan_id);
|
|
89
|
+
if (!plan)
|
|
90
|
+
return `Error: Plan #${args.plan_id} not found.`;
|
|
91
|
+
const tasks = stmts.getTasksByPlanId.all(plan.id);
|
|
92
|
+
const doneCount = tasks.filter(t => t.status === "done").length;
|
|
93
|
+
const total = tasks.length;
|
|
94
|
+
const bar = progressBar(doneCount, total);
|
|
95
|
+
const label = PLAN_STATUS_ICONS[plan.status] ?? plan.status;
|
|
96
|
+
const lines = [
|
|
97
|
+
`[PLAN #${plan.id} | ${label}] ${plan.title}`,
|
|
98
|
+
`User Story: ${plan.user_story}`,
|
|
99
|
+
`Progress: ${doneCount}/${total} done ${bar}`,
|
|
100
|
+
``,
|
|
101
|
+
];
|
|
102
|
+
for (const task of tasks) {
|
|
103
|
+
const icon = STATUS_ICONS[task.status] ?? "❓";
|
|
104
|
+
lines.push(`[${task.seq}] ${icon} ${task.status} — ${task.title}`);
|
|
105
|
+
lines.push(` Desc: ${task.description}`);
|
|
106
|
+
lines.push(` Test: ${task.test_criteria}`);
|
|
107
|
+
let parsedNotes = [];
|
|
108
|
+
try {
|
|
109
|
+
parsedNotes = JSON.parse(task.notes);
|
|
110
|
+
}
|
|
111
|
+
catch { /* ignore */ }
|
|
112
|
+
for (const n of parsedNotes) {
|
|
113
|
+
const date = new Date(n.ts * 1000).toISOString().slice(0, 10);
|
|
114
|
+
lines.push(` Note: ${date} — ${n.text}`);
|
|
115
|
+
}
|
|
116
|
+
lines.push(``);
|
|
117
|
+
}
|
|
118
|
+
return lines.join("\n").trimEnd();
|
|
119
|
+
}
|
|
120
|
+
export function handlePlanUpdateTask(stmts, args) {
|
|
121
|
+
const { task_id, status, note } = args;
|
|
122
|
+
const task = stmts.getTaskById.get(task_id);
|
|
123
|
+
if (!task)
|
|
124
|
+
return `Error: Task #${task_id} not found.`;
|
|
125
|
+
let notes = [];
|
|
126
|
+
try {
|
|
127
|
+
notes = JSON.parse(task.notes);
|
|
128
|
+
}
|
|
129
|
+
catch { /* ignore */ }
|
|
130
|
+
if (note) {
|
|
131
|
+
notes.push({ text: note, ts: Math.floor(Date.now() / 1000) });
|
|
132
|
+
}
|
|
133
|
+
const notesJson = JSON.stringify(notes);
|
|
134
|
+
stmts.updateTaskStatus.run(status, notesJson, task_id);
|
|
135
|
+
const lines = [`✅ Task #${task_id} → ${status}`];
|
|
136
|
+
if (status === "done") {
|
|
137
|
+
const remaining = stmts.countRemainingTasks.get(task.plan_id);
|
|
138
|
+
if (remaining && remaining.count === 0) {
|
|
139
|
+
stmts.updatePlanStatus.run("completed", task.plan_id);
|
|
140
|
+
const plan = stmts.getPlanById.get(task.plan_id);
|
|
141
|
+
const taskCount = stmts.getTasksByPlanId.all(task.plan_id).length;
|
|
142
|
+
lines.push(`🎉 Plan #${task.plan_id} completat! Toate ${taskCount} task-uri done.`);
|
|
143
|
+
if (plan)
|
|
144
|
+
lines.push(` "${plan.title}"`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return lines.join("\n");
|
|
148
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@a13xu/lucid",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "Token-efficient memory, code indexing, and validation for Claude Code agents — SQLite + FTS5, TF-IDF + Qdrant retrieval, AST skeleton pruning, diff-aware context, Logic Guardian drift detection",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|