opencode-manifold 0.5.21 → 0.5.23

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.
Files changed (3) hide show
  1. package/dist/index.js +79 -100
  2. package/package.json +5 -4
  3. package/tui.js +280 -0
package/dist/index.js CHANGED
@@ -1,100 +1,6 @@
1
1
  import { createRequire } from "node:module";
2
- var __defProp = Object.defineProperty;
3
- var __returnValue = (v) => v;
4
- function __exportSetter(name, newValue) {
5
- this[name] = __returnValue.bind(null, newValue);
6
- }
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, {
10
- get: all[name],
11
- enumerable: true,
12
- configurable: true,
13
- set: __exportSetter.bind(all, name)
14
- });
15
- };
16
- var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
2
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
18
3
 
19
- // src/tools/get-model-path.ts
20
- var exports_get_model_path = {};
21
- __export(exports_get_model_path, {
22
- setPluginContext: () => setPluginContext,
23
- getModelPathTool: () => getModelPathTool,
24
- getModelPath: () => getModelPath
25
- });
26
- import { tool as tool2 } from "@opencode-ai/plugin";
27
- async function getModelPath(client, sessionID) {
28
- if (sessionID) {
29
- try {
30
- const messagesResponse = await client.session.messages({
31
- path: { id: sessionID }
32
- });
33
- if (messagesResponse.data && messagesResponse.data.length > 0) {
34
- const lastMessage = messagesResponse.data[messagesResponse.data.length - 1];
35
- if (lastMessage.info) {
36
- if (lastMessage.info.role === "assistant") {
37
- const assistantMsg = lastMessage.info;
38
- return `${assistantMsg.providerID}/${assistantMsg.modelID}`;
39
- }
40
- if (lastMessage.info.model) {
41
- const { providerID, modelID } = lastMessage.info.model;
42
- return `${providerID}/${modelID}`;
43
- }
44
- }
45
- }
46
- } catch (error) {
47
- await client.app.log({
48
- body: {
49
- service: "opencode-manifold",
50
- level: "warn",
51
- message: `Error getting model from session messages: ${error}`
52
- }
53
- });
54
- }
55
- }
56
- try {
57
- const providersResponse = await client.config.providers({});
58
- if (providersResponse.data && providersResponse.data.default) {
59
- const defaults = providersResponse.data.default;
60
- const defaultModel = defaults["model"] || defaults["small_model"];
61
- if (defaultModel && typeof defaultModel === "string") {
62
- return defaultModel;
63
- }
64
- }
65
- } catch (error) {
66
- await client.app.log({
67
- body: {
68
- service: "opencode-manifold",
69
- level: "warn",
70
- message: `Error getting default model from config: ${error}`
71
- }
72
- });
73
- }
74
- return "No active model found";
75
- }
76
- function setPluginContext(client) {
77
- pluginClient = client;
78
- }
79
- function getModelPathClient() {
80
- if (!pluginClient) {
81
- throw new Error("Plugin client not initialized");
82
- }
83
- return pluginClient;
84
- }
85
- var pluginClient = null, getModelPathTool;
86
- var init_get_model_path = __esm(() => {
87
- getModelPathTool = tool2({
88
- description: "Returns the model path (provider/model) for the currently active session. Use this to get the correct model string for agent MD file model: attributes.",
89
- args: {},
90
- async execute(_args, context) {
91
- const client = getModelPathClient();
92
- const modelPath = await getModelPath(client, context.sessionID);
93
- return modelPath;
94
- }
95
- });
96
- });
97
-
98
4
  // src/init.ts
99
5
  import { readFile, writeFile, mkdir, readdir } from "fs/promises";
100
6
  import { existsSync } from "fs";
@@ -205,10 +111,6 @@ async function ensureGlobalTemplates(ctx) {
205
111
  });
206
112
  return;
207
113
  }
208
- if (existsSync(globalTemplatesDir)) {
209
- const { rm } = await import("fs/promises");
210
- await rm(globalTemplatesDir, { recursive: true, force: true });
211
- }
212
114
  await copyFiles(bundledTemplatesDir, globalTemplatesDir);
213
115
  const globalCommandsDir = join(homedir(), ".config", "opencode", "commands");
214
116
  const initCommandSrc = join(bundledTemplatesDir, "commands", "manifold-init.md");
@@ -608,8 +510,78 @@ function slugify(s) {
608
510
  return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").substring(0, 40);
609
511
  }
610
512
 
513
+ // src/tools/get-model-path.ts
514
+ import { tool as tool2 } from "@opencode-ai/plugin";
515
+ async function getModelPath(client, sessionID) {
516
+ if (sessionID) {
517
+ try {
518
+ const messagesResponse = await client.session.messages({
519
+ path: { id: sessionID }
520
+ });
521
+ if (messagesResponse.data && messagesResponse.data.length > 0) {
522
+ const lastMessage = messagesResponse.data[messagesResponse.data.length - 1];
523
+ if (lastMessage.info) {
524
+ if (lastMessage.info.role === "assistant") {
525
+ const assistantMsg = lastMessage.info;
526
+ return `${assistantMsg.providerID}/${assistantMsg.modelID}`;
527
+ }
528
+ if (lastMessage.info.model) {
529
+ const { providerID, modelID } = lastMessage.info.model;
530
+ return `${providerID}/${modelID}`;
531
+ }
532
+ }
533
+ }
534
+ } catch (error) {
535
+ await client.app.log({
536
+ body: {
537
+ service: "opencode-manifold",
538
+ level: "warn",
539
+ message: `Error getting model from session messages: ${error}`
540
+ }
541
+ });
542
+ }
543
+ }
544
+ try {
545
+ const providersResponse = await client.config.providers({});
546
+ if (providersResponse.data && providersResponse.data.default) {
547
+ const defaults = providersResponse.data.default;
548
+ const defaultModel = defaults["model"] || defaults["small_model"];
549
+ if (defaultModel && typeof defaultModel === "string") {
550
+ return defaultModel;
551
+ }
552
+ }
553
+ } catch (error) {
554
+ await client.app.log({
555
+ body: {
556
+ service: "opencode-manifold",
557
+ level: "warn",
558
+ message: `Error getting default model from config: ${error}`
559
+ }
560
+ });
561
+ }
562
+ return "No active model found";
563
+ }
564
+ var pluginClient = null;
565
+ function setPluginContext(client) {
566
+ pluginClient = client;
567
+ }
568
+ function getModelPathClient() {
569
+ if (!pluginClient) {
570
+ throw new Error("Plugin client not initialized");
571
+ }
572
+ return pluginClient;
573
+ }
574
+ var getModelPathTool = tool2({
575
+ description: "Returns the model path (provider/model) for the currently active session. Use this to get the correct model string for agent MD file model: attributes.",
576
+ args: {},
577
+ async execute(_args, context) {
578
+ const client = getModelPathClient();
579
+ const modelPath = await getModelPath(client, context.sessionID);
580
+ return modelPath;
581
+ }
582
+ });
583
+
611
584
  // src/index.ts
612
- init_get_model_path();
613
585
  var ManifoldPlugin = async (ctx) => {
614
586
  setPluginContext(ctx.client);
615
587
  const { client, directory } = ctx;
@@ -626,7 +598,14 @@ var ManifoldPlugin = async (ctx) => {
626
598
  execute_task: executeTaskTool(client, directory)
627
599
  },
628
600
  "command.execute.before": async (input, output) => {
629
- if (input.command === "manifold-init") {
601
+ await client.app.log({
602
+ body: {
603
+ service: "opencode-manifold",
604
+ level: "info",
605
+ message: `Command intercepted: ${input.command}`
606
+ }
607
+ });
608
+ if (input.command === "manifold-init" || input.command === "/manifold-init") {
630
609
  const initialized = await initProject(directory, client);
631
610
  if (initialized.length > 0) {
632
611
  output.parts = [
package/package.json CHANGED
@@ -1,22 +1,23 @@
1
1
  {
2
2
  "name": "opencode-manifold",
3
- "version": "0.5.21",
3
+ "version": "0.5.23",
4
4
  "description": "Multi-agent development system for opencode with persistent knowledge",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
7
7
  "exports": {
8
8
  ".": "./dist/index.js",
9
- "./tui": "./dist/tui.js"
9
+ "./tui": "./tui.js"
10
10
  },
11
11
  "opencode": {
12
- "tui": "dist/tui.js"
12
+ "tui": "tui.js"
13
13
  },
14
14
  "scripts": {
15
- "build": "bun build src/index.ts src/tui.ts --outdir dist --target node --external \"@opencode-ai/*\" --external \"zod\" --external \"better-sqlite3\"",
15
+ "build": "bun build src/index.ts --outdir dist --target node --external \"@opencode-ai/*\" --external \"zod\" --external \"better-sqlite3\" && bun build src/tui.ts --outfile tui.js --target node --external \"@opencode-ai/*\" --external \"zod\" --external \"better-sqlite3\"",
16
16
  "dev": "bun run build --watch"
17
17
  },
18
18
  "files": [
19
19
  "dist",
20
+ "tui.js",
20
21
  "src/templates"
21
22
  ],
22
23
  "dependencies": {
package/tui.js ADDED
@@ -0,0 +1,280 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __returnValue = (v) => v;
3
+ function __exportSetter(name, newValue) {
4
+ this[name] = __returnValue.bind(null, newValue);
5
+ }
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: true,
11
+ configurable: true,
12
+ set: __exportSetter.bind(all, name)
13
+ });
14
+ };
15
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
16
+
17
+ // src/tools/get-model-path.ts
18
+ var exports_get_model_path = {};
19
+ __export(exports_get_model_path, {
20
+ setPluginContext: () => setPluginContext,
21
+ getModelPathTool: () => getModelPathTool,
22
+ getModelPath: () => getModelPath
23
+ });
24
+ import { tool } from "@opencode-ai/plugin";
25
+ async function getModelPath(client, sessionID) {
26
+ if (sessionID) {
27
+ try {
28
+ const messagesResponse = await client.session.messages({
29
+ path: { id: sessionID }
30
+ });
31
+ if (messagesResponse.data && messagesResponse.data.length > 0) {
32
+ const lastMessage = messagesResponse.data[messagesResponse.data.length - 1];
33
+ if (lastMessage.info) {
34
+ if (lastMessage.info.role === "assistant") {
35
+ const assistantMsg = lastMessage.info;
36
+ return `${assistantMsg.providerID}/${assistantMsg.modelID}`;
37
+ }
38
+ if (lastMessage.info.model) {
39
+ const { providerID, modelID } = lastMessage.info.model;
40
+ return `${providerID}/${modelID}`;
41
+ }
42
+ }
43
+ }
44
+ } catch (error) {
45
+ await client.app.log({
46
+ body: {
47
+ service: "opencode-manifold",
48
+ level: "warn",
49
+ message: `Error getting model from session messages: ${error}`
50
+ }
51
+ });
52
+ }
53
+ }
54
+ try {
55
+ const providersResponse = await client.config.providers({});
56
+ if (providersResponse.data && providersResponse.data.default) {
57
+ const defaults = providersResponse.data.default;
58
+ const defaultModel = defaults["model"] || defaults["small_model"];
59
+ if (defaultModel && typeof defaultModel === "string") {
60
+ return defaultModel;
61
+ }
62
+ }
63
+ } catch (error) {
64
+ await client.app.log({
65
+ body: {
66
+ service: "opencode-manifold",
67
+ level: "warn",
68
+ message: `Error getting default model from config: ${error}`
69
+ }
70
+ });
71
+ }
72
+ return "No active model found";
73
+ }
74
+ function setPluginContext(client) {
75
+ pluginClient = client;
76
+ }
77
+ function getModelPathClient() {
78
+ if (!pluginClient) {
79
+ throw new Error("Plugin client not initialized");
80
+ }
81
+ return pluginClient;
82
+ }
83
+ var pluginClient = null, getModelPathTool;
84
+ var init_get_model_path = __esm(() => {
85
+ getModelPathTool = tool({
86
+ description: "Returns the model path (provider/model) for the currently active session. Use this to get the correct model string for agent MD file model: attributes.",
87
+ args: {},
88
+ async execute(_args, context) {
89
+ const client = getModelPathClient();
90
+ const modelPath = await getModelPath(client, context.sessionID);
91
+ return modelPath;
92
+ }
93
+ });
94
+ });
95
+
96
+ // src/init.ts
97
+ import { readFile, writeFile, mkdir, readdir } from "fs/promises";
98
+ import { existsSync } from "fs";
99
+ import { join, dirname } from "path";
100
+ import { fileURLToPath } from "url";
101
+ import { homedir } from "os";
102
+ import { createRequire } from "module";
103
+ var __dirname2 = dirname(fileURLToPath(import.meta.url));
104
+ var require2 = createRequire(import.meta.url);
105
+ function getBundledTemplatesDir() {
106
+ const possiblePaths = [
107
+ join(__dirname2, "..", "src", "templates"),
108
+ join(__dirname2, "templates"),
109
+ join(__dirname2, "..", "templates")
110
+ ];
111
+ for (const p of possiblePaths) {
112
+ if (existsSync(p))
113
+ return p;
114
+ }
115
+ return possiblePaths[0];
116
+ }
117
+ var bundledTemplatesDir = getBundledTemplatesDir();
118
+ var globalTemplatesDir = join(homedir(), ".config", "opencode", "manifold");
119
+ async function getPluginVersion() {
120
+ try {
121
+ const packageJson = require2(join(__dirname2, "..", "package.json"));
122
+ return packageJson.version || "unknown";
123
+ } catch {
124
+ return "unknown";
125
+ }
126
+ }
127
+ async function dirHasContent(dirPath) {
128
+ if (!existsSync(dirPath))
129
+ return false;
130
+ try {
131
+ const entries = await readdir(dirPath);
132
+ return entries.length > 0;
133
+ } catch {
134
+ return false;
135
+ }
136
+ }
137
+ async function copyMissingFiles(src, dest) {
138
+ if (!existsSync(src))
139
+ return [];
140
+ await mkdir(dest, { recursive: true });
141
+ const copied = [];
142
+ const entries = await readdir(src, { withFileTypes: true });
143
+ for (const entry of entries) {
144
+ const srcPath = join(src, entry.name);
145
+ const destPath = join(dest, entry.name);
146
+ if (entry.isDirectory()) {
147
+ const subCopied = await copyMissingFiles(srcPath, destPath);
148
+ if (subCopied.length > 0) {
149
+ copied.push(entry.name);
150
+ }
151
+ } else if (!existsSync(destPath)) {
152
+ await writeFile(destPath, await readFile(srcPath));
153
+ copied.push(entry.name);
154
+ }
155
+ }
156
+ return copied;
157
+ }
158
+ async function copyFile(src, dest) {
159
+ if (!existsSync(src))
160
+ return;
161
+ const destDir = dirname(dest);
162
+ if (!existsSync(destDir)) {
163
+ await mkdir(destDir, { recursive: true });
164
+ }
165
+ await writeFile(dest, await readFile(src));
166
+ }
167
+ async function initProject(directory, client) {
168
+ const initialized = [];
169
+ await client.app.log({
170
+ body: {
171
+ service: "opencode-manifold",
172
+ level: "info",
173
+ message: `Running /manifold-init in ${directory}`
174
+ }
175
+ });
176
+ if (!await dirHasContent(globalTemplatesDir)) {
177
+ await client.app.log({
178
+ body: {
179
+ service: "opencode-manifold",
180
+ level: "error",
181
+ message: `Global templates not found at ${globalTemplatesDir}. Plugin may not have loaded correctly.`
182
+ }
183
+ });
184
+ return initialized;
185
+ }
186
+ const agentsCopied = await copyMissingFiles(join(globalTemplatesDir, "agents"), join(directory, ".opencode", "agents"));
187
+ if (agentsCopied.length > 0) {
188
+ initialized.push(`agents (${agentsCopied.join(", ")})`);
189
+ }
190
+ const skillsCopied = await copyMissingFiles(join(globalTemplatesDir, "skills"), join(directory, ".opencode", "skills"));
191
+ if (skillsCopied.length > 0) {
192
+ initialized.push(`skills (${skillsCopied.join(", ")})`);
193
+ }
194
+ const manifoldCopied = await copyMissingFiles(join(globalTemplatesDir, "manifold"), join(directory, "Manifold"));
195
+ if (manifoldCopied.length > 0) {
196
+ initialized.push(`Manifold/ (${manifoldCopied.join(", ")})`);
197
+ }
198
+ const projectCommandsDir = join(directory, ".opencode", "commands");
199
+ const commandsToCopy = [];
200
+ const commandsInitialized = [];
201
+ for (const cmd of commandsToCopy) {
202
+ const src = join(globalTemplatesDir, "commands", cmd);
203
+ const dest = join(projectCommandsDir, cmd);
204
+ if (existsSync(src) && !existsSync(dest)) {
205
+ await copyFile(src, dest);
206
+ commandsInitialized.push(cmd);
207
+ }
208
+ }
209
+ if (commandsInitialized.length > 0) {
210
+ initialized.push(`commands (${commandsInitialized.join(", ")})`);
211
+ }
212
+ const version = await getPluginVersion();
213
+ await writeFile(join(directory, "Manifold", "VERSION"), version + `
214
+ `);
215
+ await client.app.log({
216
+ body: {
217
+ service: "opencode-manifold",
218
+ level: "info",
219
+ message: `/manifold-init complete: ${initialized.join(", ") || "already initialized"}`
220
+ }
221
+ });
222
+ return initialized;
223
+ }
224
+
225
+ // src/tui.ts
226
+ var tui = async (api) => {
227
+ api.command.register(() => [
228
+ {
229
+ title: "Manifold Init",
230
+ value: "manifold-init",
231
+ description: "Initialize Manifold agents, skills, and settings in this project",
232
+ category: "Manifold",
233
+ slash: { name: "manifold-init" },
234
+ onSelect: async () => {
235
+ try {
236
+ const directory = api.state.project?.directory;
237
+ if (!directory) {
238
+ api.ui.toast({
239
+ variant: "error",
240
+ message: "No project directory found"
241
+ });
242
+ return;
243
+ }
244
+ const initialized = await initProject(directory, api.client);
245
+ api.ui.toast({
246
+ variant: "success",
247
+ message: `Manifold initialized: ${initialized.join(", ") || "already setup"}`
248
+ });
249
+ } catch (error) {
250
+ api.ui.toast({
251
+ variant: "error",
252
+ message: `Init failed: ${error}`
253
+ });
254
+ }
255
+ }
256
+ },
257
+ {
258
+ title: "Get Model Path",
259
+ value: "manifold-model-path",
260
+ description: "Return the currently active model path for agent MD files",
261
+ category: "Manifold",
262
+ slash: { name: "manifold-model-path" },
263
+ onSelect: () => {
264
+ const sessionID = api.state.session?.id;
265
+ if (!sessionID) {
266
+ api.ui.toast({ variant: "error", message: "No active session" });
267
+ return;
268
+ }
269
+ Promise.resolve().then(() => (init_get_model_path(), exports_get_model_path)).then(({ getModelPath: getModelPath2 }) => {
270
+ getModelPath2(api.client, sessionID).then((modelPath) => {
271
+ api.ui.toast({ variant: "success", message: modelPath });
272
+ });
273
+ });
274
+ }
275
+ }
276
+ ]);
277
+ };
278
+ export {
279
+ tui
280
+ };