@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 CHANGED
@@ -10,8 +10,8 @@ var __export = (target, all) => {
10
10
  });
11
11
  };
12
12
 
13
- // src/tools/create-plan.ts
14
- import { mkdir } from "fs/promises";
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 = path4.resolve(context.directory, args.filePath);
12519
- const normalized = path4.normalize(resolved);
12520
- if (!normalized.startsWith(context.directory + path4.sep) && normalized !== 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 = path4.relative(context.directory, resolved);
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 as mkdir2 } from "fs/promises";
12545
- import path5 from "path";
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 mkdir2(path5.join(dir, "src", "lib"), { recursive: true });
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
- [path5.join("src", "index.css"), indexCss(primary, font, radius)],
12774
- [path5.join("src", "lib", "utils.ts"), utilsTs()],
12775
- [path5.join("src", "main.tsx"), mainTsx()]
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(path5.join(dir, filePath), content);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helloleo/plugins",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "OpenCode plugins for HelloLeo",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
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";