@helloleo/plugins 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +14 -191
- package/package.json +1 -1
- package/src/index.ts +3 -3
package/dist/index.js
CHANGED
|
@@ -10,8 +10,8 @@ var __export = (target, all) => {
|
|
|
10
10
|
});
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
// src/tools/
|
|
14
|
-
import {
|
|
13
|
+
// src/tools/remove.ts
|
|
14
|
+
import { unlink } from "fs/promises";
|
|
15
15
|
import path from "path";
|
|
16
16
|
|
|
17
17
|
// node_modules/zod/v4/classic/external.js
|
|
@@ -12334,197 +12334,23 @@ function tool(input) {
|
|
|
12334
12334
|
return input;
|
|
12335
12335
|
}
|
|
12336
12336
|
tool.schema = exports_external;
|
|
12337
|
-
// src/tools/create-plan.ts
|
|
12338
|
-
function slug(title) {
|
|
12339
|
-
return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
|
|
12340
|
-
}
|
|
12341
|
-
function frontmatter(fields) {
|
|
12342
|
-
const lines = Object.entries(fields).map(([k, v]) => `${k}: ${v}`);
|
|
12343
|
-
return `---
|
|
12344
|
-
${lines.join(`
|
|
12345
|
-
`)}
|
|
12346
|
-
---`;
|
|
12347
|
-
}
|
|
12348
|
-
var createPlan = tool({
|
|
12349
|
-
description: "Create a new plan file in .leo/plans/. Plans use markdown with YAML frontmatter " + "tracking title, status, and timestamps. The plan ID is a slug derived from the title.",
|
|
12350
|
-
args: {
|
|
12351
|
-
title: tool.schema.string().describe("Title of the plan"),
|
|
12352
|
-
content: tool.schema.string().describe("Markdown body of the plan")
|
|
12353
|
-
},
|
|
12354
|
-
async execute(args, context) {
|
|
12355
|
-
const dir = path.join(context.directory, ".leo", "plans");
|
|
12356
|
-
await mkdir(dir, { recursive: true });
|
|
12357
|
-
let id = slug(args.title);
|
|
12358
|
-
let filepath = path.join(dir, `${id}.md`);
|
|
12359
|
-
let suffix = 1;
|
|
12360
|
-
while (await Bun.file(filepath).exists()) {
|
|
12361
|
-
suffix++;
|
|
12362
|
-
id = `${slug(args.title)}-${suffix}`;
|
|
12363
|
-
filepath = path.join(dir, `${id}.md`);
|
|
12364
|
-
}
|
|
12365
|
-
const now = new Date().toISOString();
|
|
12366
|
-
const header = frontmatter({
|
|
12367
|
-
title: args.title,
|
|
12368
|
-
status: "active",
|
|
12369
|
-
created: now,
|
|
12370
|
-
modified: now
|
|
12371
|
-
});
|
|
12372
|
-
const body = `${header}
|
|
12373
|
-
|
|
12374
|
-
${args.content}
|
|
12375
|
-
`;
|
|
12376
|
-
await Bun.write(filepath, body);
|
|
12377
|
-
const relative = path.relative(context.directory, filepath);
|
|
12378
|
-
return `Created plan "${args.title}" at ${relative}
|
|
12379
|
-
|
|
12380
|
-
${body}`;
|
|
12381
|
-
}
|
|
12382
|
-
});
|
|
12383
|
-
var CreatePlanPlugin = async () => {
|
|
12384
|
-
return {
|
|
12385
|
-
tool: { create_plan: createPlan }
|
|
12386
|
-
};
|
|
12387
|
-
};
|
|
12388
|
-
// src/tools/list-plans.ts
|
|
12389
|
-
import { existsSync } from "fs";
|
|
12390
|
-
import path2 from "path";
|
|
12391
|
-
var STATUS = ["active", "completed", "cancelled"];
|
|
12392
|
-
function parseFrontmatter(raw) {
|
|
12393
|
-
const match = raw.match(/^---\n([\s\S]*?)\n---/);
|
|
12394
|
-
if (!match)
|
|
12395
|
-
return {};
|
|
12396
|
-
const fields = {};
|
|
12397
|
-
for (const line of (match[1] ?? "").split(`
|
|
12398
|
-
`)) {
|
|
12399
|
-
const idx = line.indexOf(":");
|
|
12400
|
-
if (idx === -1)
|
|
12401
|
-
continue;
|
|
12402
|
-
fields[line.slice(0, idx).trim()] = line.slice(idx + 1).trim();
|
|
12403
|
-
}
|
|
12404
|
-
return fields;
|
|
12405
|
-
}
|
|
12406
|
-
var listPlans = tool({
|
|
12407
|
-
description: "List all plans in .leo/plans/. Returns each plan's slug, title, status, and last modified date. " + "Optionally filter by status.",
|
|
12408
|
-
args: {
|
|
12409
|
-
status: tool.schema.enum(STATUS).optional().describe(`Filter plans by status: ${STATUS.join(", ")}`)
|
|
12410
|
-
},
|
|
12411
|
-
async execute(args, context) {
|
|
12412
|
-
const dir = path2.join(context.directory, ".leo", "plans");
|
|
12413
|
-
if (!existsSync(dir)) {
|
|
12414
|
-
return args.status ? `No plans with status "${args.status}"` : "No plans found";
|
|
12415
|
-
}
|
|
12416
|
-
const glob = new Bun.Glob("*.md");
|
|
12417
|
-
const entries = [];
|
|
12418
|
-
for await (const match of glob.scan({ cwd: dir, absolute: true })) {
|
|
12419
|
-
const raw = await Bun.file(match).text();
|
|
12420
|
-
const fields = parseFrontmatter(raw);
|
|
12421
|
-
const id = path2.basename(match, ".md");
|
|
12422
|
-
if (args.status && fields.status !== args.status)
|
|
12423
|
-
continue;
|
|
12424
|
-
entries.push({
|
|
12425
|
-
id,
|
|
12426
|
-
title: fields.title ?? id,
|
|
12427
|
-
status: fields.status ?? "unknown",
|
|
12428
|
-
modified: fields.modified ?? fields.created ?? "unknown"
|
|
12429
|
-
});
|
|
12430
|
-
}
|
|
12431
|
-
if (entries.length === 0) {
|
|
12432
|
-
return args.status ? `No plans with status "${args.status}"` : "No plans found";
|
|
12433
|
-
}
|
|
12434
|
-
entries.sort((a, b) => b.modified > a.modified ? 1 : -1);
|
|
12435
|
-
const header = `Found ${entries.length} plan${entries.length === 1 ? "" : "s"}:
|
|
12436
|
-
`;
|
|
12437
|
-
const rows = entries.map((e) => `${e.id} | ${e.status} | ${e.title} | modified ${e.modified}`);
|
|
12438
|
-
return header + rows.join(`
|
|
12439
|
-
`);
|
|
12440
|
-
}
|
|
12441
|
-
});
|
|
12442
|
-
var ListPlansPlugin = async () => {
|
|
12443
|
-
return {
|
|
12444
|
-
tool: { list_plans: listPlans }
|
|
12445
|
-
};
|
|
12446
|
-
};
|
|
12447
|
-
// src/tools/modify-plan.ts
|
|
12448
|
-
import path3 from "path";
|
|
12449
|
-
var STATUS2 = ["active", "completed", "cancelled"];
|
|
12450
|
-
function parseFrontmatter2(raw) {
|
|
12451
|
-
const match = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
12452
|
-
if (!match)
|
|
12453
|
-
return { fields: {}, body: raw };
|
|
12454
|
-
const fields = {};
|
|
12455
|
-
for (const line of (match[1] ?? "").split(`
|
|
12456
|
-
`)) {
|
|
12457
|
-
const idx = line.indexOf(":");
|
|
12458
|
-
if (idx === -1)
|
|
12459
|
-
continue;
|
|
12460
|
-
fields[line.slice(0, idx).trim()] = line.slice(idx + 1).trim();
|
|
12461
|
-
}
|
|
12462
|
-
return { fields, body: (match[2] ?? "").trim() };
|
|
12463
|
-
}
|
|
12464
|
-
function formatFrontmatter(fields, body) {
|
|
12465
|
-
const lines = Object.entries(fields).map(([k, v]) => `${k}: ${v}`);
|
|
12466
|
-
return `---
|
|
12467
|
-
${lines.join(`
|
|
12468
|
-
`)}
|
|
12469
|
-
---
|
|
12470
|
-
|
|
12471
|
-
${body}
|
|
12472
|
-
`;
|
|
12473
|
-
}
|
|
12474
|
-
var modifyPlan = tool({
|
|
12475
|
-
description: "Modify an existing plan in .leo/plans/. You can update the content, the status, or both. " + "The modified timestamp is updated automatically.",
|
|
12476
|
-
args: {
|
|
12477
|
-
planId: tool.schema.string().describe("Plan slug ID (e.g. refactor-auth-flow)"),
|
|
12478
|
-
content: tool.schema.string().optional().describe("New markdown body for the plan"),
|
|
12479
|
-
status: tool.schema.enum(STATUS2).optional().describe("New status for the plan")
|
|
12480
|
-
},
|
|
12481
|
-
async execute(args, context) {
|
|
12482
|
-
if (!args.content && !args.status) {
|
|
12483
|
-
throw new Error("Provide at least one of content or status to modify");
|
|
12484
|
-
}
|
|
12485
|
-
const filepath = path3.join(context.directory, ".leo", "plans", `${args.planId}.md`);
|
|
12486
|
-
const file2 = Bun.file(filepath);
|
|
12487
|
-
if (!await file2.exists()) {
|
|
12488
|
-
throw new Error(`Plan not found: ${args.planId}`);
|
|
12489
|
-
}
|
|
12490
|
-
const raw = await file2.text();
|
|
12491
|
-
const parsed = parseFrontmatter2(raw);
|
|
12492
|
-
if (args.status)
|
|
12493
|
-
parsed.fields.status = args.status;
|
|
12494
|
-
parsed.fields.modified = new Date().toISOString();
|
|
12495
|
-
const body = args.content ?? parsed.body;
|
|
12496
|
-
const output = formatFrontmatter(parsed.fields, body);
|
|
12497
|
-
await Bun.write(filepath, output);
|
|
12498
|
-
const relative = path3.relative(context.directory, filepath);
|
|
12499
|
-
return `Updated plan "${args.planId}" at ${relative}
|
|
12500
|
-
|
|
12501
|
-
${output}`;
|
|
12502
|
-
}
|
|
12503
|
-
});
|
|
12504
|
-
var ModifyPlanPlugin = async () => {
|
|
12505
|
-
return {
|
|
12506
|
-
tool: { modify_plan: modifyPlan }
|
|
12507
|
-
};
|
|
12508
|
-
};
|
|
12509
12337
|
// src/tools/remove.ts
|
|
12510
|
-
import { unlink } from "fs/promises";
|
|
12511
|
-
import path4 from "path";
|
|
12512
12338
|
var remove = tool({
|
|
12513
12339
|
description: "Remove a file from the project. The file path must be relative to the project root. " + "This tool will ask for permission before deleting. " + "Cannot delete files outside the project boundary.",
|
|
12514
12340
|
args: {
|
|
12515
12341
|
filePath: tool.schema.string().describe("Relative path to the file to remove (e.g. src/App.tsx)")
|
|
12516
12342
|
},
|
|
12517
12343
|
async execute(args, context) {
|
|
12518
|
-
const resolved =
|
|
12519
|
-
const normalized =
|
|
12520
|
-
if (!normalized.startsWith(context.directory +
|
|
12344
|
+
const resolved = path.resolve(context.directory, args.filePath);
|
|
12345
|
+
const normalized = path.normalize(resolved);
|
|
12346
|
+
if (!normalized.startsWith(context.directory + path.sep) && normalized !== context.directory) {
|
|
12521
12347
|
throw new Error(`Path "${args.filePath}" resolves outside the project boundary. Deletion blocked.`);
|
|
12522
12348
|
}
|
|
12523
12349
|
const file2 = Bun.file(resolved);
|
|
12524
12350
|
if (!await file2.exists()) {
|
|
12525
12351
|
throw new Error(`File not found: ${args.filePath}`);
|
|
12526
12352
|
}
|
|
12527
|
-
const relative =
|
|
12353
|
+
const relative = path.relative(context.directory, resolved);
|
|
12528
12354
|
await context.ask({
|
|
12529
12355
|
permission: "remove",
|
|
12530
12356
|
patterns: [resolved],
|
|
@@ -12541,8 +12367,8 @@ var RemovePlugin = async () => {
|
|
|
12541
12367
|
};
|
|
12542
12368
|
};
|
|
12543
12369
|
// src/tools/scaffold.ts
|
|
12544
|
-
import { mkdir
|
|
12545
|
-
import
|
|
12370
|
+
import { mkdir } from "fs/promises";
|
|
12371
|
+
import path2 from "path";
|
|
12546
12372
|
function packageJson(name) {
|
|
12547
12373
|
return JSON.stringify({
|
|
12548
12374
|
name,
|
|
@@ -12763,20 +12589,20 @@ var scaffold = tool({
|
|
|
12763
12589
|
const primary = args.primaryColor ?? "221.2 83.2% 53.3%";
|
|
12764
12590
|
const font = args.fontFamily ?? "Inter";
|
|
12765
12591
|
const radius = args.borderRadius ?? "0.5rem";
|
|
12766
|
-
await
|
|
12592
|
+
await mkdir(path2.join(dir, "src", "lib"), { recursive: true });
|
|
12767
12593
|
const files = [
|
|
12768
12594
|
["package.json", packageJson(name)],
|
|
12769
12595
|
["index.html", indexHtml(font)],
|
|
12770
12596
|
["vite.config.js", viteConfig()],
|
|
12771
12597
|
["tailwind.config.js", tailwindConfig()],
|
|
12772
12598
|
["postcss.config.js", postcssConfig()],
|
|
12773
|
-
[
|
|
12774
|
-
[
|
|
12775
|
-
[
|
|
12599
|
+
[path2.join("src", "index.css"), indexCss(primary, font, radius)],
|
|
12600
|
+
[path2.join("src", "lib", "utils.ts"), utilsTs()],
|
|
12601
|
+
[path2.join("src", "main.tsx"), mainTsx()]
|
|
12776
12602
|
];
|
|
12777
12603
|
const created = [];
|
|
12778
12604
|
for (const [filePath, content] of files) {
|
|
12779
|
-
await Bun.write(
|
|
12605
|
+
await Bun.write(path2.join(dir, filePath), content);
|
|
12780
12606
|
created.push(filePath);
|
|
12781
12607
|
}
|
|
12782
12608
|
return [
|
|
@@ -12797,8 +12623,5 @@ var ScaffoldPlugin = async () => {
|
|
|
12797
12623
|
};
|
|
12798
12624
|
export {
|
|
12799
12625
|
ScaffoldPlugin,
|
|
12800
|
-
RemovePlugin
|
|
12801
|
-
ModifyPlanPlugin,
|
|
12802
|
-
ListPlansPlugin,
|
|
12803
|
-
CreatePlanPlugin
|
|
12626
|
+
RemovePlugin
|
|
12804
12627
|
};
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { CreatePlanPlugin } from "./tools/create-plan.ts";
|
|
2
|
-
export { ListPlansPlugin } from "./tools/list-plans.ts";
|
|
3
|
-
export { ModifyPlanPlugin } from "./tools/modify-plan.ts";
|
|
4
1
|
export { RemovePlugin } from "./tools/remove.ts";
|
|
5
2
|
export { ScaffoldPlugin } from "./tools/scaffold.ts";
|
|
3
|
+
// export { CreatePlanPlugin } from "./tools/create-plan.ts";
|
|
4
|
+
// export { ListPlansPlugin } from "./tools/list-plans.ts";
|
|
5
|
+
// export { ModifyPlanPlugin } from "./tools/modify-plan.ts";
|