opencode-manifold 0.4.15 → 0.4.17
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 +102 -0
- package/dist/tui.js +109 -165
- package/package.json +1 -1
- package/src/templates/commands/manifold-models.md +0 -3
- package/src/templates/commands/manifold-update.md +0 -3
package/dist/index.js
CHANGED
|
@@ -12,6 +12,45 @@ var __dirname2 = dirname(fileURLToPath(import.meta.url));
|
|
|
12
12
|
var require2 = createRequire2(import.meta.url);
|
|
13
13
|
var bundledTemplatesDir = join(__dirname2, "..", "src", "templates");
|
|
14
14
|
var globalTemplatesDir = join(homedir(), ".config", "opencode", "manifold");
|
|
15
|
+
async function getPluginVersion() {
|
|
16
|
+
try {
|
|
17
|
+
const packageJson = require2(join(__dirname2, "..", "package.json"));
|
|
18
|
+
return packageJson.version || "unknown";
|
|
19
|
+
} catch {
|
|
20
|
+
return "unknown";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function dirHasContent(dirPath) {
|
|
24
|
+
if (!existsSync(dirPath))
|
|
25
|
+
return false;
|
|
26
|
+
try {
|
|
27
|
+
const entries = await readdir(dirPath);
|
|
28
|
+
return entries.length > 0;
|
|
29
|
+
} catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async function copyMissingFiles(src, dest) {
|
|
34
|
+
if (!existsSync(src))
|
|
35
|
+
return [];
|
|
36
|
+
await mkdir(dest, { recursive: true });
|
|
37
|
+
const copied = [];
|
|
38
|
+
const entries = await readdir(src, { withFileTypes: true });
|
|
39
|
+
for (const entry of entries) {
|
|
40
|
+
const srcPath = join(src, entry.name);
|
|
41
|
+
const destPath = join(dest, entry.name);
|
|
42
|
+
if (entry.isDirectory()) {
|
|
43
|
+
const subCopied = await copyMissingFiles(srcPath, destPath);
|
|
44
|
+
if (subCopied.length > 0) {
|
|
45
|
+
copied.push(entry.name);
|
|
46
|
+
}
|
|
47
|
+
} else if (!existsSync(destPath)) {
|
|
48
|
+
await writeFile(destPath, await readFile(srcPath));
|
|
49
|
+
copied.push(entry.name);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return copied;
|
|
53
|
+
}
|
|
15
54
|
async function copyFiles(src, dest) {
|
|
16
55
|
if (!existsSync(src))
|
|
17
56
|
return [];
|
|
@@ -65,6 +104,49 @@ async function ensureGlobalTemplates(ctx) {
|
|
|
65
104
|
}
|
|
66
105
|
});
|
|
67
106
|
}
|
|
107
|
+
async function initProject(directory, client) {
|
|
108
|
+
const initialized = [];
|
|
109
|
+
await client.app.log({
|
|
110
|
+
body: {
|
|
111
|
+
service: "opencode-manifold",
|
|
112
|
+
level: "info",
|
|
113
|
+
message: `Running /manifold-init in ${directory}`
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
if (!await dirHasContent(globalTemplatesDir)) {
|
|
117
|
+
await client.app.log({
|
|
118
|
+
body: {
|
|
119
|
+
service: "opencode-manifold",
|
|
120
|
+
level: "error",
|
|
121
|
+
message: `Global templates not found at ${globalTemplatesDir}. Plugin may not have loaded correctly.`
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
return initialized;
|
|
125
|
+
}
|
|
126
|
+
const agentsCopied = await copyMissingFiles(join(globalTemplatesDir, "agents"), join(directory, ".opencode", "agents"));
|
|
127
|
+
if (agentsCopied.length > 0) {
|
|
128
|
+
initialized.push(`agents (${agentsCopied.join(", ")})`);
|
|
129
|
+
}
|
|
130
|
+
const skillsCopied = await copyMissingFiles(join(globalTemplatesDir, "skills"), join(directory, ".opencode", "skills"));
|
|
131
|
+
if (skillsCopied.length > 0) {
|
|
132
|
+
initialized.push(`skills (${skillsCopied.join(", ")})`);
|
|
133
|
+
}
|
|
134
|
+
const manifoldCopied = await copyMissingFiles(join(globalTemplatesDir, "manifold"), join(directory, "Manifold"));
|
|
135
|
+
if (manifoldCopied.length > 0) {
|
|
136
|
+
initialized.push(`Manifold/ (${manifoldCopied.join(", ")})`);
|
|
137
|
+
}
|
|
138
|
+
const version = await getPluginVersion();
|
|
139
|
+
await writeFile(join(directory, "Manifold", "VERSION"), version + `
|
|
140
|
+
`);
|
|
141
|
+
await client.app.log({
|
|
142
|
+
body: {
|
|
143
|
+
service: "opencode-manifold",
|
|
144
|
+
level: "info",
|
|
145
|
+
message: `/manifold-init complete: ${initialized.join(", ") || "already initialized"}`
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
return initialized;
|
|
149
|
+
}
|
|
68
150
|
|
|
69
151
|
// src/tools/dispatch-task.ts
|
|
70
152
|
import { tool } from "@opencode-ai/plugin";
|
|
@@ -4148,6 +4230,26 @@ var ManifoldPlugin = async (ctx) => {
|
|
|
4148
4230
|
return {
|
|
4149
4231
|
tool: {
|
|
4150
4232
|
dispatchTask: dispatchTaskTool
|
|
4233
|
+
},
|
|
4234
|
+
"command.execute.before": async (input, output) => {
|
|
4235
|
+
if (input.command === "manifold-init") {
|
|
4236
|
+
const initialized = await initProject(ctx.directory, ctx.client);
|
|
4237
|
+
if (initialized.length > 0) {
|
|
4238
|
+
output.parts = [
|
|
4239
|
+
{
|
|
4240
|
+
type: "text",
|
|
4241
|
+
text: `Manifold initialized: ${initialized.join(", ")}`
|
|
4242
|
+
}
|
|
4243
|
+
];
|
|
4244
|
+
} else {
|
|
4245
|
+
output.parts = [
|
|
4246
|
+
{
|
|
4247
|
+
type: "text",
|
|
4248
|
+
text: "All Manifold files already present. To reset a specific component, delete the corresponding file(s) from `.opencode/agents/`, `.opencode/skills/`, or `Manifold/`, then run `/manifold-init` again."
|
|
4249
|
+
}
|
|
4250
|
+
];
|
|
4251
|
+
}
|
|
4252
|
+
}
|
|
4151
4253
|
}
|
|
4152
4254
|
};
|
|
4153
4255
|
};
|
package/dist/tui.js
CHANGED
|
@@ -5,7 +5,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
5
5
|
import { existsSync } from "fs";
|
|
6
6
|
import { join } from "path";
|
|
7
7
|
import { homedir } from "os";
|
|
8
|
-
import { readFile, writeFile, readdir
|
|
8
|
+
import { readFile, writeFile, readdir } from "fs/promises";
|
|
9
9
|
|
|
10
10
|
// node_modules/js-yaml/dist/js-yaml.mjs
|
|
11
11
|
/*! js-yaml 4.1.1 https://github.com/nodeca/js-yaml @license MIT */
|
|
@@ -2770,7 +2770,8 @@ var tui = async (api) => {
|
|
|
2770
2770
|
category: "Manifold",
|
|
2771
2771
|
slash: {
|
|
2772
2772
|
name: "manifold-models"
|
|
2773
|
-
}
|
|
2773
|
+
},
|
|
2774
|
+
onSelect: () => handleManifoldModels(api)
|
|
2774
2775
|
},
|
|
2775
2776
|
{
|
|
2776
2777
|
title: "Manifold Update",
|
|
@@ -2779,166 +2780,97 @@ var tui = async (api) => {
|
|
|
2779
2780
|
category: "Manifold",
|
|
2780
2781
|
slash: {
|
|
2781
2782
|
name: "manifold-update"
|
|
2782
|
-
}
|
|
2783
|
+
},
|
|
2784
|
+
onSelect: () => handleManifoldUpdate(api)
|
|
2783
2785
|
}
|
|
2784
2786
|
]);
|
|
2785
|
-
api.event.on("tui.command.execute", async (event) => {
|
|
2786
|
-
if (event.properties.command === "manifold-init") {
|
|
2787
|
-
await handleManifoldInit(api);
|
|
2788
|
-
} else if (event.properties.command === "manifold-models") {
|
|
2789
|
-
await handleManifoldModels(api);
|
|
2790
|
-
} else if (event.properties.command === "manifold-update") {
|
|
2791
|
-
await handleManifoldUpdate(api);
|
|
2792
|
-
}
|
|
2793
|
-
});
|
|
2794
2787
|
};
|
|
2795
|
-
|
|
2796
|
-
const { existsSync: existsSync2, mkdir: mkdir2, writeFile: writeFile2, readdir: readdir2 } = await import("fs/promises");
|
|
2797
|
-
const { join: join2 } = await import("path");
|
|
2798
|
-
if (!existsSync2(src))
|
|
2799
|
-
return [];
|
|
2800
|
-
await mkdir2(dest, { recursive: true });
|
|
2801
|
-
const copied = [];
|
|
2802
|
-
const entries = await readdir2(src, { withFileTypes: true });
|
|
2803
|
-
for (const entry of entries) {
|
|
2804
|
-
const srcPath = join2(src, entry.name);
|
|
2805
|
-
const destPath = join2(dest, entry.name);
|
|
2806
|
-
if (entry.isDirectory()) {
|
|
2807
|
-
const subCopied = await copyMissingFiles(srcPath, destPath);
|
|
2808
|
-
if (subCopied.length > 0) {
|
|
2809
|
-
copied.push(entry.name);
|
|
2810
|
-
}
|
|
2811
|
-
} else if (!existsSync2(destPath)) {
|
|
2812
|
-
await writeFile2(destPath, await readFile(srcPath));
|
|
2813
|
-
copied.push(entry.name);
|
|
2814
|
-
}
|
|
2815
|
-
}
|
|
2816
|
-
return copied;
|
|
2817
|
-
}
|
|
2818
|
-
async function handleManifoldInit(api) {
|
|
2819
|
-
const directory = api.state.path.directory;
|
|
2820
|
-
const globalTemplatesDir = join(homedir(), ".config", "opencode", "manifold");
|
|
2821
|
-
if (!existsSync(globalTemplatesDir)) {
|
|
2822
|
-
api.ui.toast({
|
|
2823
|
-
variant: "error",
|
|
2824
|
-
message: "Global templates not found. Plugin may not be installed correctly."
|
|
2825
|
-
});
|
|
2826
|
-
return;
|
|
2827
|
-
}
|
|
2828
|
-
const agentsDir = join(directory, ".opencode", "agents");
|
|
2829
|
-
const skillsDir = join(directory, ".opencode", "skills");
|
|
2830
|
-
const manifoldDir = join(directory, "Manifold");
|
|
2831
|
-
await mkdir(agentsDir, { recursive: true });
|
|
2832
|
-
await mkdir(skillsDir, { recursive: true });
|
|
2833
|
-
await mkdir(manifoldDir, { recursive: true });
|
|
2834
|
-
const agentsCopied = await copyMissingFiles(join(globalTemplatesDir, "agents"), agentsDir);
|
|
2835
|
-
const skillsCopied = await copyMissingFiles(join(globalTemplatesDir, "skills"), skillsDir);
|
|
2836
|
-
const manifoldCopied = await copyMissingFiles(join(globalTemplatesDir, "manifold"), manifoldDir);
|
|
2837
|
-
const initialized = [];
|
|
2838
|
-
if (agentsCopied.length > 0) {
|
|
2839
|
-
initialized.push(`agents (${agentsCopied.join(", ")})`);
|
|
2840
|
-
}
|
|
2841
|
-
if (skillsCopied.length > 0) {
|
|
2842
|
-
initialized.push(`skills (${skillsCopied.join(", ")})`);
|
|
2843
|
-
}
|
|
2844
|
-
if (manifoldCopied.length > 0) {
|
|
2845
|
-
initialized.push(`Manifold/ (${manifoldCopied.join(", ")})`);
|
|
2846
|
-
}
|
|
2847
|
-
const message = initialized.length > 0 ? `Manifold initialized: ${initialized.join(", ")}` : "All Manifold files already present.";
|
|
2848
|
-
api.ui.toast({
|
|
2849
|
-
variant: "success",
|
|
2850
|
-
message
|
|
2851
|
-
});
|
|
2852
|
-
}
|
|
2853
|
-
async function handleManifoldModels(api) {
|
|
2788
|
+
function handleManifoldModels(api) {
|
|
2854
2789
|
const directory = api.state.path.directory;
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2790
|
+
getManifoldAgents(directory).then((agents) => {
|
|
2791
|
+
if (agents.length === 0) {
|
|
2792
|
+
api.ui.toast({
|
|
2793
|
+
variant: "error",
|
|
2794
|
+
message: "No Manifold agents found. Run /manifold-init first."
|
|
2795
|
+
});
|
|
2796
|
+
return;
|
|
2797
|
+
}
|
|
2798
|
+
const providers = api.state.provider;
|
|
2799
|
+
const models = [];
|
|
2800
|
+
for (const provider of providers) {
|
|
2801
|
+
if (provider.models) {
|
|
2802
|
+
for (const [modelId, model] of Object.entries(provider.models)) {
|
|
2803
|
+
models.push({
|
|
2804
|
+
id: `${provider.id}/${modelId}`,
|
|
2805
|
+
name: model.name || modelId,
|
|
2806
|
+
providerID: provider.id
|
|
2807
|
+
});
|
|
2808
|
+
}
|
|
2873
2809
|
}
|
|
2874
2810
|
}
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
api.ui.dialog.setSize("medium");
|
|
2890
|
-
return new Promise((resolve) => {
|
|
2891
|
-
api.ui.ui.DialogSelect({
|
|
2811
|
+
if (models.length === 0) {
|
|
2812
|
+
api.ui.toast({
|
|
2813
|
+
variant: "error",
|
|
2814
|
+
message: "No models available. Configure providers first."
|
|
2815
|
+
});
|
|
2816
|
+
return;
|
|
2817
|
+
}
|
|
2818
|
+
models.sort((a, b) => a.name.localeCompare(b.name));
|
|
2819
|
+
const agentOptions = agents.map((agent) => ({
|
|
2820
|
+
title: `${agent} (sub-agent)`,
|
|
2821
|
+
value: agent,
|
|
2822
|
+
description: `Configure model for ${agent}`
|
|
2823
|
+
}));
|
|
2824
|
+
api.ui.dialog.replace(() => api.ui.DialogSelect({
|
|
2892
2825
|
title: "Select Manifold Sub-Agent",
|
|
2893
2826
|
options: agentOptions,
|
|
2894
|
-
onSelect:
|
|
2827
|
+
onSelect: (option) => {
|
|
2895
2828
|
const selectedAgent = option.value;
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2829
|
+
readAgentFile(selectedAgent, directory).then(({ frontmatter }) => {
|
|
2830
|
+
const currentModel = frontmatter.model || "not set";
|
|
2831
|
+
const modelOptions = models.map((model) => ({
|
|
2832
|
+
title: `${model.name}`,
|
|
2833
|
+
value: model.id,
|
|
2834
|
+
description: model.id,
|
|
2835
|
+
footer: model.id === currentModel ? "✓ Current" : undefined
|
|
2836
|
+
}));
|
|
2837
|
+
api.ui.dialog.replace(() => api.ui.DialogSelect({
|
|
2838
|
+
title: `Select Model for ${selectedAgent}`,
|
|
2839
|
+
options: modelOptions,
|
|
2840
|
+
current: currentModel !== "not set" ? currentModel : undefined,
|
|
2841
|
+
onSelect: (modelOption) => {
|
|
2842
|
+
const selectedModelId = modelOption.value;
|
|
2843
|
+
updateAgentModel(selectedAgent, selectedModelId, directory).then(() => {
|
|
2844
|
+
api.ui.toast({
|
|
2845
|
+
variant: "success",
|
|
2846
|
+
message: `Set ${selectedAgent} to ${selectedModelId}`
|
|
2847
|
+
});
|
|
2848
|
+
api.ui.dialog.clear();
|
|
2849
|
+
});
|
|
2850
|
+
}
|
|
2851
|
+
}));
|
|
2852
|
+
}).catch(() => {
|
|
2853
|
+
api.ui.toast({
|
|
2854
|
+
variant: "error",
|
|
2855
|
+
message: `Error reading agent file for ${selectedAgent}`
|
|
2856
|
+
});
|
|
2916
2857
|
});
|
|
2917
2858
|
}
|
|
2918
|
-
});
|
|
2859
|
+
}));
|
|
2919
2860
|
});
|
|
2920
2861
|
}
|
|
2921
|
-
|
|
2862
|
+
function handleManifoldUpdate(api) {
|
|
2922
2863
|
const directory = api.state.path.directory;
|
|
2923
|
-
const { rm } = await import("fs/promises");
|
|
2924
2864
|
const settingsPath = join(directory, "Manifold", "settings.json");
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
const
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
const pathsToClear = [...new Set([...configuredPaths, globalConfigDir])];
|
|
2935
|
-
const resolvedPaths = pathsToClear.map((p) => {
|
|
2936
|
-
const expanded = p.startsWith("~") ? join(homedir(), p.slice(1)) : p;
|
|
2937
|
-
return expanded;
|
|
2938
|
-
});
|
|
2939
|
-
api.ui.dialog.setSize("large");
|
|
2940
|
-
return new Promise((resolve) => {
|
|
2941
|
-
api.ui.ui.DialogSelect({
|
|
2865
|
+
const proceed = (settings) => {
|
|
2866
|
+
const globalConfigDir = join(homedir(), ".config", "opencode", "manifold");
|
|
2867
|
+
const configuredPaths = settings.updateCachePaths || [];
|
|
2868
|
+
const pathsToClear = [...new Set([...configuredPaths, globalConfigDir])];
|
|
2869
|
+
const resolvedPaths = pathsToClear.map((p) => {
|
|
2870
|
+
const expanded = p.startsWith("~") ? join(homedir(), p.slice(1)) : p;
|
|
2871
|
+
return expanded;
|
|
2872
|
+
});
|
|
2873
|
+
api.ui.dialog.replace(() => api.ui.DialogSelect({
|
|
2942
2874
|
title: "Manifold Plugin Update",
|
|
2943
2875
|
options: [
|
|
2944
2876
|
{
|
|
@@ -2954,31 +2886,43 @@ async function handleManifoldUpdate(api) {
|
|
|
2954
2886
|
description: "Do not clear cache"
|
|
2955
2887
|
}
|
|
2956
2888
|
],
|
|
2957
|
-
onSelect:
|
|
2889
|
+
onSelect: (option) => {
|
|
2958
2890
|
if (option.value === "cancel") {
|
|
2959
|
-
|
|
2891
|
+
api.ui.dialog.clear();
|
|
2960
2892
|
return;
|
|
2961
2893
|
}
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
try {
|
|
2894
|
+
import("fs/promises").then(({ rm }) => {
|
|
2895
|
+
const cleared = [];
|
|
2896
|
+
const promises = resolvedPaths.map((pathStr) => {
|
|
2966
2897
|
if (existsSync(pathStr)) {
|
|
2967
|
-
|
|
2968
|
-
|
|
2898
|
+
return rm(pathStr, { recursive: true, force: true }).then(() => {
|
|
2899
|
+
cleared.push(pathStr);
|
|
2900
|
+
}).catch(() => {});
|
|
2969
2901
|
}
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2902
|
+
return Promise.resolve();
|
|
2903
|
+
});
|
|
2904
|
+
Promise.all(promises).then(() => {
|
|
2905
|
+
api.ui.toast({
|
|
2906
|
+
variant: cleared.length > 0 ? "success" : "error",
|
|
2907
|
+
message: cleared.length > 0 ? `Cache cleared. Restart opencode to update.` : `No paths cleared or update blocked`
|
|
2908
|
+
});
|
|
2909
|
+
api.ui.dialog.clear();
|
|
2910
|
+
});
|
|
2977
2911
|
});
|
|
2978
|
-
resolve();
|
|
2979
2912
|
}
|
|
2980
|
-
});
|
|
2981
|
-
}
|
|
2913
|
+
}));
|
|
2914
|
+
};
|
|
2915
|
+
if (existsSync(settingsPath)) {
|
|
2916
|
+
readFile(settingsPath, "utf-8").then((content) => {
|
|
2917
|
+
try {
|
|
2918
|
+
proceed(JSON.parse(content));
|
|
2919
|
+
} catch {
|
|
2920
|
+
proceed({});
|
|
2921
|
+
}
|
|
2922
|
+
}).catch(() => proceed({}));
|
|
2923
|
+
} else {
|
|
2924
|
+
proceed({});
|
|
2925
|
+
}
|
|
2982
2926
|
}
|
|
2983
2927
|
export {
|
|
2984
2928
|
tui
|
package/package.json
CHANGED