opencode-manifold 0.4.8 → 0.4.9

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 CHANGED
@@ -72,8 +72,9 @@ Open Manifold requires:
72
72
  1. **Install** using one of the methods above
73
73
  2. **Run `/manifold-init`** in the opencode TUI to set up agents, skills, and the Manifold directory
74
74
  3. **(Optional) Run `/manifold-models`** to configure which models each sub-agent uses
75
- 4. **Create a plan** any format (markdown, TODO list, email, meeting notes)
76
- 5. **Point the Lead Dev agent** at your plan file and tell it to execute
75
+ 4. **(Optional) Run `/manifold-update`** to clear plugin cache before updating (requires path configuration)
76
+ 5. **Create a plan** any format (markdown, TODO list, email, meeting notes)
77
+ 6. **Point the Lead Dev agent** at your plan file and tell it to execute
77
78
 
78
79
  The Lead Dev will:
79
80
  - Extract tasks from your plan
@@ -252,6 +253,7 @@ Located at `Manifold/settings.json`:
252
253
  | `clerkRetryEnabled` | true | Clerk gets second pass after Debug fails |
253
254
  | `timeout` | 300 | Max seconds per agent call |
254
255
  | `testCommand` | null | Default test command |
256
+ | `updateCachePaths` | `[]` | Paths to clear when running `/manifold-update` (see [Plugin Updates](#plugin-updates)) |
255
257
 
256
258
  ---
257
259
 
@@ -295,6 +297,62 @@ A: The system is designed around the Clerk's ability to research context via sem
295
297
 
296
298
  ---
297
299
 
300
+ ## Plugin Updates
301
+
302
+ Opencode caches plugins to improve startup performance. When a new version of `opencode-manifold` is published, you may need to clear the cache to receive the update.
303
+
304
+ ### Using `/manifold-update`
305
+
306
+ 1. **Configure cache paths** in `Manifold/settings.json`:
307
+ ```json
308
+ {
309
+ "updateCachePaths": [
310
+ "~/.cache/opencode/packages/opencode-manifold@latest",
311
+ "~/node_modules/opencode-manifold"
312
+ ]
313
+ }
314
+ ```
315
+
316
+ 2. **Run `/manifold-update`** in the TUI
317
+ 3. **Confirm** the paths to clear
318
+ 4. **Restart opencode** to pull the fresh version
319
+
320
+ ### Safety Features
321
+
322
+ The command includes built-in protections:
323
+ - **Wildcards blocked:** Paths with `*` are rejected
324
+ - **System paths protected:** `/`, `/System`, `/Applications`, home directory, etc. cannot be deleted
325
+ - **Project detection:** Directories containing `.git` + `opencode.json` or `package.json` are treated as projects and blocked
326
+ - **Explicit confirmation:** You must type "yes" to proceed
327
+
328
+ ### Platform-Specific Paths
329
+
330
+ **macOS:**
331
+ ```json
332
+ [
333
+ "~/.cache/opencode/packages/opencode-manifold@latest",
334
+ "~/node_modules/opencode-manifold"
335
+ ]
336
+ ```
337
+
338
+ **Linux:**
339
+ ```json
340
+ [
341
+ "~/.cache/opencode/packages/opencode-manifold@latest"
342
+ ]
343
+ ```
344
+
345
+ **Windows:**
346
+ ```json
347
+ [
348
+ "%LOCALAPPDATA%/opencode/packages/opencode-manifold@latest"
349
+ ]
350
+ ```
351
+
352
+ If your cache is stored elsewhere, add the full path to `updateCachePaths`. The command is intentionally conservative — it's safer to manually clear cache than to accidentally delete project files.
353
+
354
+ ---
355
+
298
356
  ## Uninstall
299
357
 
300
358
  To remove Open Manifold from a project:
@@ -314,26 +372,20 @@ rm -rf ~/.config/opencode/manifold/ ~/.config/opencode/commands/manifold-init.md
314
372
  To fully uninstall the plugin, also remove `"opencode-manifold"` from the `plugin` array in your global or project `opencode.json`.
315
373
 
316
374
  ### Complete Clean Uninstall
317
- # Mac:
318
- OpenCode caches plugins in multiple locations. To fully clear all cached versions before reinstalling:
375
+
376
+ For a full clean reinstall, use `/manifold-update` (see [Plugin Updates](#plugin-updates)) to clear caches, then:
319
377
 
320
378
  ```bash
321
- # Remove plugin from all cache locations
322
- rm -rf ~/node_modules/opencode-manifold
323
- rm -rf ~/.cache/opencode/packages/opencode-manifold@latest
324
- rm -rf ~/.config/opencode/manifold/
325
- rm -rf ~/.config/opencode/commands/manifold-init.md
379
+ # Remove project files
380
+ rm -rf .opencode/agents/ .opencode/skills/ Manifold/
326
381
 
327
- # Then restart opencode and run /manifold-init
382
+ # Remove global templates
383
+ rm -rf ~/.config/opencode/manifold/ ~/.config/opencode/commands/manifold-init.md
328
384
  ```
329
385
 
330
- This ensures you're running the latest version after updates.
331
-
332
- # Win:
333
- I have no clue. Use linux.
386
+ Then remove `"opencode-manifold"` from your `opencode.json` plugin array.
334
387
 
335
- # Linux:
336
- Still have no clue but I know you can handle it.
388
+ ---
337
389
 
338
390
  ---
339
391
 
package/dist/index.js CHANGED
@@ -4074,7 +4074,8 @@ async function readSettings(directory) {
4074
4074
  recentTaskCount: 3,
4075
4075
  clerkRetryEnabled: true,
4076
4076
  timeout: 300,
4077
- testCommand: null
4077
+ testCommand: null,
4078
+ updateCachePaths: []
4078
4079
  };
4079
4080
  }
4080
4081
  async function updatePlansRegistry(directory, planFile) {
@@ -4429,6 +4430,246 @@ Type the model number or full model ID (e.g., anthropic/claude-sonnet-4-20250514
4429
4430
  });
4430
4431
  }
4431
4432
 
4433
+ // src/tools/clear-cache.ts
4434
+ import { rm } from "fs/promises";
4435
+ import { existsSync as existsSync7 } from "fs";
4436
+ import { join as join7, isAbsolute } from "path";
4437
+ import { homedir as homedir3 } from "os";
4438
+ var PROTECTED_PATHS = [
4439
+ "/",
4440
+ "/System",
4441
+ "/Applications",
4442
+ "/Users",
4443
+ "/etc",
4444
+ "/bin",
4445
+ "/sbin",
4446
+ "/usr"
4447
+ ];
4448
+ function resolvePath(pathStr) {
4449
+ const expanded = pathStr.startsWith("~") ? join7(homedir3(), pathStr.slice(1)) : pathStr;
4450
+ return isAbsolute(expanded) ? expanded : join7(process.cwd(), expanded);
4451
+ }
4452
+ function isPathSafe(pathStr) {
4453
+ const normalized = pathStr.toLowerCase();
4454
+ if (normalized.includes("*")) {
4455
+ return { safe: false, reason: "Wildcards are not allowed for safety" };
4456
+ }
4457
+ for (const protectedPath of PROTECTED_PATHS) {
4458
+ if (normalized === protectedPath.toLowerCase() || normalized.startsWith(protectedPath.toLowerCase() + "/") || normalized.startsWith(protectedPath.toLowerCase() + "\\")) {
4459
+ return { safe: false, reason: `Cannot delete protected system path: ${protectedPath}` };
4460
+ }
4461
+ }
4462
+ if (normalized === homedir3().toLowerCase() || normalized.startsWith(homedir3().toLowerCase() + "/") && !normalized.includes("cache") && !normalized.includes("node_modules")) {
4463
+ const parts = normalized.replace(homedir3().toLowerCase(), "").split(/[\/\\]/).filter(Boolean);
4464
+ if (parts.length === 1) {
4465
+ return { safe: false, reason: "Cannot delete directories directly in home folder" };
4466
+ }
4467
+ }
4468
+ return { safe: true };
4469
+ }
4470
+ async function isProjectDirectory(pathStr) {
4471
+ try {
4472
+ const hasGit = existsSync7(join7(pathStr, ".git"));
4473
+ const hasOpencodeConfig = existsSync7(join7(pathStr, "opencode.json"));
4474
+ const hasPackageJson = existsSync7(join7(pathStr, "package.json"));
4475
+ if (hasGit && (hasOpencodeConfig || hasPackageJson)) {
4476
+ return true;
4477
+ }
4478
+ const entries = await Promise.all([
4479
+ existsSync7(join7(pathStr, ".git")) ? "git" : null,
4480
+ existsSync7(join7(pathStr, "opencode.json")) ? "opencode" : null
4481
+ ].filter(Boolean));
4482
+ return entries.length >= 2;
4483
+ } catch {
4484
+ return false;
4485
+ }
4486
+ }
4487
+ async function clearCachePaths(paths) {
4488
+ const cleared = [];
4489
+ const skipped = [];
4490
+ const blocked = [];
4491
+ for (const pathStr of paths) {
4492
+ const resolved = resolvePath(pathStr);
4493
+ const safetyCheck = isPathSafe(resolved);
4494
+ if (!safetyCheck.safe) {
4495
+ blocked.push({ path: resolved, reason: safetyCheck.reason || "Failed safety check" });
4496
+ continue;
4497
+ }
4498
+ if (!existsSync7(resolved)) {
4499
+ skipped.push(resolved);
4500
+ continue;
4501
+ }
4502
+ const isProject = await isProjectDirectory(resolved);
4503
+ if (isProject) {
4504
+ blocked.push({ path: resolved, reason: "Appears to be a project directory (contains .git + config files)" });
4505
+ continue;
4506
+ }
4507
+ try {
4508
+ await rm(resolved, { recursive: true, force: true });
4509
+ cleared.push(resolved);
4510
+ } catch (error) {
4511
+ blocked.push({ path: resolved, reason: `Failed to delete: ${error}` });
4512
+ }
4513
+ }
4514
+ return { cleared, skipped, blocked };
4515
+ }
4516
+ async function handleUpdateCommand(client, directory) {
4517
+ await client.app.log({
4518
+ body: {
4519
+ service: "opencode-manifold",
4520
+ level: "info",
4521
+ message: "Starting /manifold-update command"
4522
+ }
4523
+ });
4524
+ const settings = await readSettings(directory);
4525
+ const configuredPaths = settings.updateCachePaths || [];
4526
+ if (configuredPaths.length === 0) {
4527
+ const examplePaths = [
4528
+ "~/.cache/opencode/packages/opencode-manifold@latest",
4529
+ "~/node_modules/opencode-manifold"
4530
+ ];
4531
+ await client.tui.appendPrompt({
4532
+ body: {
4533
+ type: "text",
4534
+ text: `\uD83D\uDD04 **Manifold Plugin Update**
4535
+
4536
+ No cache paths configured in \`Manifold/settings.json\`.
4537
+
4538
+ To enable this feature, add cache paths to your settings:
4539
+
4540
+ \`\`\`json
4541
+ {
4542
+ "updateCachePaths": [
4543
+ "~/.cache/opencode/packages/opencode-manifold@latest",
4544
+ "~/node_modules/opencode-manifold"
4545
+ ]
4546
+ }
4547
+ \`\`\`
4548
+
4549
+ **Safety features:**
4550
+ • Wildcards are blocked
4551
+ • System directories are protected
4552
+ • Project directories (with .git + config) are protected
4553
+
4554
+ **macOS users:** The paths above are typical cache locations.
4555
+ **Linux/Windows users:** Add your opencode cache paths manually.
4556
+ `
4557
+ }
4558
+ });
4559
+ await client.tui.showToast({
4560
+ body: {
4561
+ type: "info",
4562
+ message: "Configure updateCachePaths in Manifold/settings.json"
4563
+ }
4564
+ });
4565
+ return;
4566
+ }
4567
+ const resolvedPaths = configuredPaths.map(resolvePath);
4568
+ await client.tui.appendPrompt({
4569
+ body: {
4570
+ type: "text",
4571
+ text: `\uD83D\uDD04 **Manifold Plugin Update**
4572
+
4573
+ The following paths will be cleared:
4574
+
4575
+ ${resolvedPaths.map((p) => `• ${p}`).join(`
4576
+ `)}
4577
+
4578
+ ⚠️ **This action is irreversible.** These paths are read from \`Manifold/settings.json\`.
4579
+ `
4580
+ }
4581
+ });
4582
+ await client.tui.publish({
4583
+ body: {
4584
+ type: "tui.prompt_append",
4585
+ data: {
4586
+ type: "text",
4587
+ text: `
4588
+
4589
+ Type 'yes' to confirm and clear cache: `
4590
+ }
4591
+ }
4592
+ });
4593
+ const response = await client.tui.control.next();
4594
+ const answer = response.data?.input?.trim().toLowerCase();
4595
+ if (answer !== "yes" && answer !== "y") {
4596
+ await client.tui.appendPrompt({
4597
+ body: {
4598
+ type: "text",
4599
+ text: `
4600
+ ❌ Cancelled. No cache cleared.
4601
+ `
4602
+ }
4603
+ });
4604
+ return;
4605
+ }
4606
+ const { cleared, skipped, blocked } = await clearCachePaths(configuredPaths);
4607
+ let message = `
4608
+ `;
4609
+ if (cleared.length > 0) {
4610
+ message += `✅ **Cleared:**
4611
+ ${cleared.map((p) => `• ${p}`).join(`
4612
+ `)}
4613
+
4614
+ `;
4615
+ }
4616
+ if (skipped.length > 0) {
4617
+ message += `⏭️ **Already clean / skipped:**
4618
+ ${skipped.map((p) => `• ${p}`).join(`
4619
+ `)}
4620
+
4621
+ `;
4622
+ }
4623
+ if (blocked.length > 0) {
4624
+ message += `\uD83D\uDEAB **Blocked (safety check):**
4625
+ `;
4626
+ for (const item of blocked) {
4627
+ message += `• ${item.path}
4628
+ Reason: ${item.reason}
4629
+ `;
4630
+ }
4631
+ message += `
4632
+ `;
4633
+ }
4634
+ if (cleared.length > 0) {
4635
+ message += `**Next step:** Restart opencode to pull the latest plugin version.
4636
+
4637
+ Your project files (.opencode/, Manifold/) are untouched — only the configured cache paths were cleared.
4638
+ `;
4639
+ } else if (blocked.length > 0) {
4640
+ message += `⚠️ No paths were cleared. Review the blocked paths above and adjust your settings if needed.
4641
+ `;
4642
+ }
4643
+ await client.tui.appendPrompt({
4644
+ body: {
4645
+ type: "text",
4646
+ text: message
4647
+ }
4648
+ });
4649
+ if (cleared.length > 0) {
4650
+ await client.tui.showToast({
4651
+ body: {
4652
+ type: "success",
4653
+ message: `Cache cleared (${cleared.length} paths). Restart opencode to update.`
4654
+ }
4655
+ });
4656
+ } else if (blocked.length > 0) {
4657
+ await client.tui.showToast({
4658
+ body: {
4659
+ type: "error",
4660
+ message: `Cache update blocked (${blocked.length} paths failed safety check)`
4661
+ }
4662
+ });
4663
+ }
4664
+ await client.app.log({
4665
+ body: {
4666
+ service: "opencode-manifold",
4667
+ level: "info",
4668
+ message: `/manifold-update complete: cleared ${cleared.length}, skipped ${skipped.length}, blocked ${blocked.length}`
4669
+ }
4670
+ });
4671
+ }
4672
+
4432
4673
  // src/index.ts
4433
4674
  var ManifoldPlugin = async (ctx) => {
4434
4675
  setPluginContext(ctx.client);
@@ -4470,6 +4711,14 @@ var ManifoldPlugin = async (ctx) => {
4470
4711
  text: "Sub-agent model configuration complete."
4471
4712
  }
4472
4713
  ];
4714
+ } else if (input.command === "manifold-update") {
4715
+ await handleUpdateCommand(ctx.client, ctx.directory);
4716
+ output.parts = [
4717
+ {
4718
+ type: "text",
4719
+ text: "Plugin cache update complete."
4720
+ }
4721
+ ];
4473
4722
  }
4474
4723
  }
4475
4724
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-manifold",
3
- "version": "0.4.8",
3
+ "version": "0.4.9",
4
4
  "description": "Multi-agent development system for opencode with persistent knowledge",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -0,0 +1,4 @@
1
+ ---
2
+ description: Clear opencode-manifold plugin cache and prompt for restart
3
+ ---
4
+ The /manifold-update command is handled by the plugin. It clears cached versions and prompts you to restart opencode.
@@ -5,5 +5,7 @@
5
5
  "recentTaskCount": 3,
6
6
  "clerkRetryEnabled": true,
7
7
  "timeout": 300,
8
- "testCommand": null
8
+ "testCommand": null,
9
+ "updateCachePaths": [
10
+ ]
9
11
  }