opencode-manifold 0.4.16 → 0.4.18
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 +107 -167
- 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 */
|
|
@@ -2768,175 +2768,103 @@ var tui = async (api) => {
|
|
|
2768
2768
|
value: "manifold-models",
|
|
2769
2769
|
description: "Set the model for a Manifold sub-agent",
|
|
2770
2770
|
category: "Manifold",
|
|
2771
|
-
|
|
2772
|
-
name: "manifold-models"
|
|
2773
|
-
}
|
|
2771
|
+
onSelect: () => handleManifoldModels(api)
|
|
2774
2772
|
},
|
|
2775
2773
|
{
|
|
2776
2774
|
title: "Manifold Update",
|
|
2777
2775
|
value: "manifold-update",
|
|
2778
2776
|
description: "Clear opencode-manifold plugin cache and prompt for restart",
|
|
2779
2777
|
category: "Manifold",
|
|
2780
|
-
|
|
2781
|
-
name: "manifold-update"
|
|
2782
|
-
}
|
|
2778
|
+
onSelect: () => handleManifoldUpdate(api)
|
|
2783
2779
|
}
|
|
2784
2780
|
]);
|
|
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
2781
|
};
|
|
2795
|
-
|
|
2796
|
-
if (!existsSync(src))
|
|
2797
|
-
return [];
|
|
2798
|
-
await mkdir(dest, { recursive: true });
|
|
2799
|
-
const copied = [];
|
|
2800
|
-
const entries = await readdir(src, { withFileTypes: true });
|
|
2801
|
-
for (const entry of entries) {
|
|
2802
|
-
const srcPath = join(src, entry.name);
|
|
2803
|
-
const destPath = join(dest, entry.name);
|
|
2804
|
-
if (entry.isDirectory()) {
|
|
2805
|
-
const subCopied = await copyMissingFiles(srcPath, destPath);
|
|
2806
|
-
if (subCopied.length > 0) {
|
|
2807
|
-
copied.push(entry.name);
|
|
2808
|
-
}
|
|
2809
|
-
} else if (!existsSync(destPath)) {
|
|
2810
|
-
await writeFile(destPath, await readFile(srcPath));
|
|
2811
|
-
copied.push(entry.name);
|
|
2812
|
-
}
|
|
2813
|
-
}
|
|
2814
|
-
return copied;
|
|
2815
|
-
}
|
|
2816
|
-
async function handleManifoldInit(api) {
|
|
2782
|
+
function handleManifoldModels(api) {
|
|
2817
2783
|
const directory = api.state.path.directory;
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
initialized.push(`agents (${agentsCopied.join(", ")})`);
|
|
2838
|
-
}
|
|
2839
|
-
if (skillsCopied.length > 0) {
|
|
2840
|
-
initialized.push(`skills (${skillsCopied.join(", ")})`);
|
|
2841
|
-
}
|
|
2842
|
-
if (manifoldCopied.length > 0) {
|
|
2843
|
-
initialized.push(`Manifold/ (${manifoldCopied.join(", ")})`);
|
|
2844
|
-
}
|
|
2845
|
-
const message = initialized.length > 0 ? `Manifold initialized: ${initialized.join(", ")}` : "All Manifold files already present.";
|
|
2846
|
-
api.ui.toast({
|
|
2847
|
-
variant: "success",
|
|
2848
|
-
message
|
|
2849
|
-
});
|
|
2850
|
-
}
|
|
2851
|
-
async function handleManifoldModels(api) {
|
|
2852
|
-
const directory = api.state.path.directory;
|
|
2853
|
-
const agents = await getManifoldAgents(directory);
|
|
2854
|
-
if (agents.length === 0) {
|
|
2855
|
-
api.ui.toast({
|
|
2856
|
-
variant: "error",
|
|
2857
|
-
message: "No Manifold agents found. Run /manifold-init first."
|
|
2858
|
-
});
|
|
2859
|
-
return;
|
|
2860
|
-
}
|
|
2861
|
-
const providers = api.state.provider;
|
|
2862
|
-
const models = [];
|
|
2863
|
-
for (const provider of providers) {
|
|
2864
|
-
if (provider.models) {
|
|
2865
|
-
for (const [modelId, model] of Object.entries(provider.models)) {
|
|
2866
|
-
models.push({
|
|
2867
|
-
id: `${provider.id}/${modelId}`,
|
|
2868
|
-
name: model.name || modelId,
|
|
2869
|
-
providerID: provider.id
|
|
2870
|
-
});
|
|
2784
|
+
getManifoldAgents(directory).then((agents) => {
|
|
2785
|
+
if (agents.length === 0) {
|
|
2786
|
+
api.ui.toast({
|
|
2787
|
+
variant: "error",
|
|
2788
|
+
message: "No Manifold agents found. Run /manifold-init first."
|
|
2789
|
+
});
|
|
2790
|
+
return;
|
|
2791
|
+
}
|
|
2792
|
+
const providers = api.state.provider;
|
|
2793
|
+
const models = [];
|
|
2794
|
+
for (const provider of providers) {
|
|
2795
|
+
if (provider.models) {
|
|
2796
|
+
for (const [modelId, model] of Object.entries(provider.models)) {
|
|
2797
|
+
models.push({
|
|
2798
|
+
id: `${provider.id}/${modelId}`,
|
|
2799
|
+
name: model.name || modelId,
|
|
2800
|
+
providerID: provider.id
|
|
2801
|
+
});
|
|
2802
|
+
}
|
|
2871
2803
|
}
|
|
2872
2804
|
}
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
api.ui.dialog.setSize("medium");
|
|
2888
|
-
return new Promise((resolve) => {
|
|
2889
|
-
api.ui.ui.DialogSelect({
|
|
2805
|
+
if (models.length === 0) {
|
|
2806
|
+
api.ui.toast({
|
|
2807
|
+
variant: "error",
|
|
2808
|
+
message: "No models available. Configure providers first."
|
|
2809
|
+
});
|
|
2810
|
+
return;
|
|
2811
|
+
}
|
|
2812
|
+
models.sort((a, b) => a.name.localeCompare(b.name));
|
|
2813
|
+
const agentOptions = agents.map((agent) => ({
|
|
2814
|
+
title: `${agent} (sub-agent)`,
|
|
2815
|
+
value: agent,
|
|
2816
|
+
description: `Configure model for ${agent}`
|
|
2817
|
+
}));
|
|
2818
|
+
api.ui.dialog.replace(() => api.ui.DialogSelect({
|
|
2890
2819
|
title: "Select Manifold Sub-Agent",
|
|
2891
2820
|
options: agentOptions,
|
|
2892
|
-
onSelect:
|
|
2821
|
+
onSelect: (option) => {
|
|
2893
2822
|
const selectedAgent = option.value;
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2823
|
+
readAgentFile(selectedAgent, directory).then(({ frontmatter }) => {
|
|
2824
|
+
const currentModel = frontmatter.model || "not set";
|
|
2825
|
+
const modelOptions = models.map((model) => ({
|
|
2826
|
+
title: `${model.name}`,
|
|
2827
|
+
value: model.id,
|
|
2828
|
+
description: model.id,
|
|
2829
|
+
footer: model.id === currentModel ? "✓ Current" : undefined
|
|
2830
|
+
}));
|
|
2831
|
+
api.ui.dialog.replace(() => api.ui.DialogSelect({
|
|
2832
|
+
title: `Select Model for ${selectedAgent}`,
|
|
2833
|
+
options: modelOptions,
|
|
2834
|
+
current: currentModel !== "not set" ? currentModel : undefined,
|
|
2835
|
+
onSelect: (modelOption) => {
|
|
2836
|
+
const selectedModelId = modelOption.value;
|
|
2837
|
+
updateAgentModel(selectedAgent, selectedModelId, directory).then(() => {
|
|
2838
|
+
api.ui.toast({
|
|
2839
|
+
variant: "success",
|
|
2840
|
+
message: `Set ${selectedAgent} to ${selectedModelId}`
|
|
2841
|
+
});
|
|
2842
|
+
api.ui.dialog.clear();
|
|
2843
|
+
});
|
|
2844
|
+
}
|
|
2845
|
+
}));
|
|
2846
|
+
}).catch(() => {
|
|
2847
|
+
api.ui.toast({
|
|
2848
|
+
variant: "error",
|
|
2849
|
+
message: `Error reading agent file for ${selectedAgent}`
|
|
2850
|
+
});
|
|
2914
2851
|
});
|
|
2915
2852
|
}
|
|
2916
|
-
});
|
|
2853
|
+
}));
|
|
2917
2854
|
});
|
|
2918
2855
|
}
|
|
2919
|
-
|
|
2856
|
+
function handleManifoldUpdate(api) {
|
|
2920
2857
|
const directory = api.state.path.directory;
|
|
2921
|
-
const { rm } = await import("fs/promises");
|
|
2922
2858
|
const settingsPath = join(directory, "Manifold", "settings.json");
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
const
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
const pathsToClear = [...new Set([...configuredPaths, globalConfigDir])];
|
|
2933
|
-
const resolvedPaths = pathsToClear.map((p) => {
|
|
2934
|
-
const expanded = p.startsWith("~") ? join(homedir(), p.slice(1)) : p;
|
|
2935
|
-
return expanded;
|
|
2936
|
-
});
|
|
2937
|
-
api.ui.dialog.setSize("large");
|
|
2938
|
-
return new Promise((resolve) => {
|
|
2939
|
-
api.ui.ui.DialogSelect({
|
|
2859
|
+
const proceed = (settings) => {
|
|
2860
|
+
const globalConfigDir = join(homedir(), ".config", "opencode", "manifold");
|
|
2861
|
+
const configuredPaths = settings.updateCachePaths || [];
|
|
2862
|
+
const pathsToClear = [...new Set([...configuredPaths, globalConfigDir])];
|
|
2863
|
+
const resolvedPaths = pathsToClear.map((p) => {
|
|
2864
|
+
const expanded = p.startsWith("~") ? join(homedir(), p.slice(1)) : p;
|
|
2865
|
+
return expanded;
|
|
2866
|
+
});
|
|
2867
|
+
api.ui.dialog.replace(() => api.ui.DialogSelect({
|
|
2940
2868
|
title: "Manifold Plugin Update",
|
|
2941
2869
|
options: [
|
|
2942
2870
|
{
|
|
@@ -2952,31 +2880,43 @@ async function handleManifoldUpdate(api) {
|
|
|
2952
2880
|
description: "Do not clear cache"
|
|
2953
2881
|
}
|
|
2954
2882
|
],
|
|
2955
|
-
onSelect:
|
|
2883
|
+
onSelect: (option) => {
|
|
2956
2884
|
if (option.value === "cancel") {
|
|
2957
|
-
|
|
2885
|
+
api.ui.dialog.clear();
|
|
2958
2886
|
return;
|
|
2959
2887
|
}
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
try {
|
|
2888
|
+
import("fs/promises").then(({ rm }) => {
|
|
2889
|
+
const cleared = [];
|
|
2890
|
+
const promises = resolvedPaths.map((pathStr) => {
|
|
2964
2891
|
if (existsSync(pathStr)) {
|
|
2965
|
-
|
|
2966
|
-
|
|
2892
|
+
return rm(pathStr, { recursive: true, force: true }).then(() => {
|
|
2893
|
+
cleared.push(pathStr);
|
|
2894
|
+
}).catch(() => {});
|
|
2967
2895
|
}
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2896
|
+
return Promise.resolve();
|
|
2897
|
+
});
|
|
2898
|
+
Promise.all(promises).then(() => {
|
|
2899
|
+
api.ui.toast({
|
|
2900
|
+
variant: cleared.length > 0 ? "success" : "error",
|
|
2901
|
+
message: cleared.length > 0 ? `Cache cleared. Restart opencode to update.` : `No paths cleared or update blocked`
|
|
2902
|
+
});
|
|
2903
|
+
api.ui.dialog.clear();
|
|
2904
|
+
});
|
|
2975
2905
|
});
|
|
2976
|
-
resolve();
|
|
2977
2906
|
}
|
|
2978
|
-
});
|
|
2979
|
-
}
|
|
2907
|
+
}));
|
|
2908
|
+
};
|
|
2909
|
+
if (existsSync(settingsPath)) {
|
|
2910
|
+
readFile(settingsPath, "utf-8").then((content) => {
|
|
2911
|
+
try {
|
|
2912
|
+
proceed(JSON.parse(content));
|
|
2913
|
+
} catch {
|
|
2914
|
+
proceed({});
|
|
2915
|
+
}
|
|
2916
|
+
}).catch(() => proceed({}));
|
|
2917
|
+
} else {
|
|
2918
|
+
proceed({});
|
|
2919
|
+
}
|
|
2980
2920
|
}
|
|
2981
2921
|
export {
|
|
2982
2922
|
tui
|
package/package.json
CHANGED