@massa-ai/opencode-plugin 1.2.1 → 1.4.0

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.
@@ -557,7 +557,8 @@ __export(exports_config_loader, {
557
557
  getConfigPath: () => getConfigPath,
558
558
  getConfigForEnv: () => getConfigForEnv,
559
559
  getConfigDir: () => getConfigDir,
560
- configExists: () => configExists
560
+ configExists: () => configExists,
561
+ __resetMigrationForTests: () => __resetMigrationForTests
561
562
  });
562
563
  import fs from "fs";
563
564
  import path3 from "path";
@@ -627,6 +628,9 @@ function migrateDataDirOnce() {
627
628
  console.error(`[massa-ai] Data directory migration skipped:`, err);
628
629
  }
629
630
  }
631
+ function __resetMigrationForTests() {
632
+ migrationAttempted = false;
633
+ }
630
634
  function saveConfig(config) {
631
635
  if (!fs.existsSync(CONFIG_DIR)) {
632
636
  fs.mkdirSync(CONFIG_DIR, { recursive: true });
@@ -636,7 +640,7 @@ function saveConfig(config) {
636
640
  function initConfig() {
637
641
  if (!fs.existsSync(CONFIG_FILE)) {
638
642
  saveConfig(defaultMassaAiConfig);
639
- console.log(`Created default config at ${CONFIG_FILE}`);
643
+ console.error(`Created default config at ${CONFIG_FILE}`);
640
644
  }
641
645
  }
642
646
  function getConfigForEnv() {
@@ -686,7 +690,7 @@ function findEnvFile() {
686
690
  return;
687
691
  }
688
692
  var envPath = findEnvFile();
689
- import_dotenv.config({ path: envPath });
693
+ import_dotenv.config({ path: envPath, quiet: true });
690
694
  try {
691
695
  const { loadConfigSafe: loadConfigSafe2, migrateDataDirOnce: migrateDataDirOnce2 } = (init_config_loader(), __toCommonJS(exports_config_loader));
692
696
  migrateDataDirOnce2();
@@ -1136,8 +1140,6 @@ import { promises as fs2 } from "fs";
1136
1140
  import path5 from "path";
1137
1141
  import os3 from "os";
1138
1142
  import { fileURLToPath } from "url";
1139
- var args = process.argv.slice(2);
1140
- var command = args[0];
1141
1143
  var __dirname2 = path5.dirname(fileURLToPath(import.meta.url));
1142
1144
  function help() {
1143
1145
  console.log(`
@@ -1160,7 +1162,7 @@ Commands:
1160
1162
  --model <name> Model name
1161
1163
  --base-url <url> Base URL (for ollama)
1162
1164
 
1163
- agents Manage the 12 subagent specialist definitions
1165
+ agents Manage the 15 subagent specialist definitions
1164
1166
  agents install [--user|--project] Write 12 agent .md files
1165
1167
  agents uninstall [--user|--project] Remove only massa-ai-owned agents
1166
1168
 
@@ -1173,13 +1175,13 @@ Examples:
1173
1175
  massa-ai-config agents install --user
1174
1176
  `);
1175
1177
  }
1176
- function parseOptions(args2) {
1178
+ function parseOptions(args) {
1177
1179
  const options = {};
1178
- for (let i = 0;i < args2.length; i++) {
1179
- if (args2[i].startsWith("--")) {
1180
- const key = args2[i].slice(2);
1181
- if (i + 1 < args2.length && !args2[i + 1].startsWith("--")) {
1182
- options[key] = args2[i + 1];
1180
+ for (let i = 0;i < args.length; i++) {
1181
+ if (args[i].startsWith("--")) {
1182
+ const key = args[i].slice(2);
1183
+ if (i + 1 < args.length && !args[i + 1].startsWith("--")) {
1184
+ options[key] = args[i + 1];
1183
1185
  i++;
1184
1186
  } else {
1185
1187
  options[key] = true;
@@ -1188,166 +1190,178 @@ function parseOptions(args2) {
1188
1190
  }
1189
1191
  return options;
1190
1192
  }
1191
- if (!command || command === "--help" || command === "-h") {
1192
- help();
1193
- process.exit(0);
1194
- }
1195
- var options = parseOptions(args.slice(1));
1196
- switch (command) {
1197
- case "init": {
1198
- initConfig();
1199
- if (options.mistral && typeof options.mistral === "string") {
1200
- const config2 = loadConfig();
1201
- config2.embedding = {
1202
- provider: "mistral",
1203
- model: "mistral-embed",
1204
- apiKey: options.mistral,
1205
- dimensions: 1024
1206
- };
1207
- saveConfig(config2);
1208
- console.log("\u2713 Configured for Mistral embeddings");
1209
- } else if (options.openai && typeof options.openai === "string") {
1210
- const config2 = loadConfig();
1211
- config2.embedding = {
1212
- provider: "openai",
1213
- model: "text-embedding-3-small",
1214
- apiKey: options.openai,
1215
- dimensions: 1536
1216
- };
1217
- saveConfig(config2);
1218
- console.log("\u2713 Configured for OpenAI embeddings");
1219
- } else {
1220
- console.log("\u2713 Configured for Ollama (local) embeddings");
1221
- }
1222
- console.log(`
1223
- Config file: ${getConfigPath()}`);
1224
- break;
1225
- }
1226
- case "path": {
1227
- console.log(getConfigPath());
1228
- break;
1193
+ async function runCli(argv) {
1194
+ const args = argv;
1195
+ const command = args[0];
1196
+ if (!command || command === "--help" || command === "-h") {
1197
+ help();
1198
+ return 0;
1229
1199
  }
1230
- case "show": {
1231
- if (!configExists()) {
1232
- console.log("No config file found. Run `massa-ai-config init` to create one.");
1200
+ const options = parseOptions(args.slice(1));
1201
+ switch (command) {
1202
+ case "init": {
1203
+ initConfig();
1204
+ if (options.mistral && typeof options.mistral === "string") {
1205
+ const config2 = loadConfig();
1206
+ config2.embedding = {
1207
+ provider: "mistral",
1208
+ model: "mistral-embed",
1209
+ apiKey: options.mistral,
1210
+ dimensions: 1024
1211
+ };
1212
+ saveConfig(config2);
1213
+ console.log("\u2713 Configured for Mistral embeddings");
1214
+ } else if (options.openai && typeof options.openai === "string") {
1215
+ const config2 = loadConfig();
1216
+ config2.embedding = {
1217
+ provider: "openai",
1218
+ model: "text-embedding-3-small",
1219
+ apiKey: options.openai,
1220
+ dimensions: 1536
1221
+ };
1222
+ saveConfig(config2);
1223
+ console.log("\u2713 Configured for OpenAI embeddings");
1224
+ } else {
1225
+ console.log("\u2713 Configured for Ollama (local) embeddings");
1226
+ }
1233
1227
  console.log(`
1234
- Using defaults:`);
1235
- console.log(JSON.stringify(defaultMassaAiConfig, null, 2));
1236
- process.exit(0);
1237
- }
1238
- const config2 = loadConfig();
1239
- console.log(JSON.stringify(config2, null, 2));
1240
- break;
1241
- }
1242
- case "set": {
1243
- const key = args[1];
1244
- const value = args[2];
1245
- if (!key || !value) {
1246
- console.error("Usage: massa-ai-config set <key> <value>");
1247
- process.exit(1);
1228
+ Config file: ${getConfigPath()}`);
1229
+ break;
1248
1230
  }
1249
- const config2 = loadConfig();
1250
- const keys = key.split(".");
1251
- let obj = config2;
1252
- for (let i = 0;i < keys.length - 1; i++) {
1253
- obj = obj[keys[i]];
1231
+ case "path": {
1232
+ console.log(getConfigPath());
1233
+ break;
1254
1234
  }
1255
- const parsedValue = isNaN(Number(value)) ? value : Number(value);
1256
- obj[keys[keys.length - 1]] = parsedValue;
1257
- saveConfig(config2);
1258
- console.log(`\u2713 Set ${key} = ${value}`);
1259
- break;
1260
- }
1261
- case "use": {
1262
- const provider = args[1];
1263
- if (!provider || !["ollama", "mistral", "openai"].includes(provider)) {
1264
- console.error("Provider must be: ollama, mistral, or openai");
1265
- process.exit(1);
1235
+ case "show": {
1236
+ if (!configExists()) {
1237
+ console.log("No config file found. Run `massa-ai-config init` to create one.");
1238
+ console.log(`
1239
+ Using defaults:`);
1240
+ console.log(JSON.stringify(defaultMassaAiConfig, null, 2));
1241
+ return 0;
1242
+ }
1243
+ const config2 = loadConfig();
1244
+ console.log(JSON.stringify(config2, null, 2));
1245
+ break;
1266
1246
  }
1267
- const config2 = loadConfig();
1268
- if (provider === "ollama") {
1269
- config2.embedding = {
1270
- provider: "ollama",
1271
- model: options.model || "nomic-embed-text:latest",
1272
- baseURL: options["base-url"] || "http://localhost:11434",
1273
- dimensions: 768
1274
- };
1275
- } else if (provider === "mistral") {
1276
- if (!options["api-key"]) {
1277
- console.error("Error: --api-key required for Mistral");
1278
- process.exit(1);
1247
+ case "set": {
1248
+ const key = args[1];
1249
+ const value = args[2];
1250
+ if (!key || !value) {
1251
+ console.error("Usage: massa-ai-config set <key> <value>");
1252
+ return 1;
1279
1253
  }
1280
- config2.embedding = {
1281
- provider: "mistral",
1282
- model: options.model || "mistral-embed",
1283
- apiKey: options["api-key"],
1284
- dimensions: 1024
1285
- };
1286
- } else if (provider === "openai") {
1287
- if (!options["api-key"]) {
1288
- console.error("Error: --api-key required for OpenAI");
1289
- process.exit(1);
1254
+ const config2 = loadConfig();
1255
+ const keys = key.split(".");
1256
+ let obj = config2;
1257
+ for (let i = 0;i < keys.length - 1; i++) {
1258
+ obj = obj[keys[i]];
1290
1259
  }
1291
- config2.embedding = {
1292
- provider: "openai",
1293
- model: options.model || "text-embedding-3-small",
1294
- apiKey: options["api-key"],
1295
- dimensions: 1536
1296
- };
1260
+ const parsedValue = isNaN(Number(value)) ? value : Number(value);
1261
+ obj[keys[keys.length - 1]] = parsedValue;
1262
+ saveConfig(config2);
1263
+ console.log(`\u2713 Set ${key} = ${value}`);
1264
+ break;
1297
1265
  }
1298
- saveConfig(config2);
1299
- console.log(`\u2713 Switched to ${provider} embeddings`);
1300
- console.log(` Model: ${config2.embedding.model}`);
1301
- break;
1302
- }
1303
- case "agents": {
1304
- const subcommand = args[1];
1305
- if (subcommand !== "install" && subcommand !== "uninstall") {
1306
- console.error("Usage: massa-ai-config agents <install|uninstall> [--user|--project]");
1307
- process.exit(1);
1266
+ case "use": {
1267
+ const provider = args[1];
1268
+ if (!provider || !["ollama", "mistral", "openai"].includes(provider)) {
1269
+ console.error("Provider must be: ollama, mistral, or openai");
1270
+ return 1;
1271
+ }
1272
+ const config2 = loadConfig();
1273
+ if (provider === "ollama") {
1274
+ config2.embedding = {
1275
+ provider: "ollama",
1276
+ model: options.model || "nomic-embed-text:latest",
1277
+ baseURL: options["base-url"] || "http://localhost:11434",
1278
+ dimensions: 768
1279
+ };
1280
+ } else if (provider === "mistral") {
1281
+ if (!options["api-key"]) {
1282
+ console.error("Error: --api-key required for Mistral");
1283
+ return 1;
1284
+ }
1285
+ config2.embedding = {
1286
+ provider: "mistral",
1287
+ model: options.model || "mistral-embed",
1288
+ apiKey: options["api-key"],
1289
+ dimensions: 1024
1290
+ };
1291
+ } else if (provider === "openai") {
1292
+ if (!options["api-key"]) {
1293
+ console.error("Error: --api-key required for OpenAI");
1294
+ return 1;
1295
+ }
1296
+ config2.embedding = {
1297
+ provider: "openai",
1298
+ model: options.model || "text-embedding-3-small",
1299
+ apiKey: options["api-key"],
1300
+ dimensions: 1536
1301
+ };
1302
+ }
1303
+ saveConfig(config2);
1304
+ console.log(`\u2713 Switched to ${provider} embeddings`);
1305
+ console.log(` Model: ${config2.embedding.model}`);
1306
+ break;
1308
1307
  }
1309
- const scope = typeof options.project === "boolean" ? "project" : "user";
1310
- const agentsDir = scope === "project" ? path5.join(process.cwd(), ".opencode/agents") : path5.join(process.env.XDG_CONFIG_HOME && process.env.XDG_CONFIG_HOME.trim() || path5.join(os3.homedir(), ".config"), "opencode", "agents");
1311
- const sourceAgentsDir = path5.resolve(__dirname2, "..", "agents");
1312
- if (subcommand === "install") {
1313
- await fs2.mkdir(agentsDir, { recursive: true });
1314
- let count = 0;
1315
- const entries = await fs2.readdir(sourceAgentsDir);
1316
- for (const entry of entries) {
1317
- if (!entry.startsWith("massa-ai-") || !entry.endsWith(".md"))
1318
- continue;
1319
- const src = path5.join(sourceAgentsDir, entry);
1320
- const dest = path5.join(agentsDir, entry);
1321
- await fs2.copyFile(src, dest);
1322
- count++;
1308
+ case "agents": {
1309
+ const subcommand = args[1];
1310
+ if (subcommand !== "install" && subcommand !== "uninstall") {
1311
+ console.error("Usage: massa-ai-config agents <install|uninstall> [--user|--project]");
1312
+ return 1;
1323
1313
  }
1324
- console.log(`+ ${count} subagent specialists: investigator, planner, builder, reviewer, context-curator, verification-agent, requirements-analyst, architecture-specialist, test-engineer, documentation-agent, audit-specialist, mobile-specialist`);
1325
- console.log(` written to: ${agentsDir}`);
1326
- } else {
1327
- let removed = 0;
1328
- try {
1329
- const entries = await fs2.readdir(agentsDir);
1314
+ const scope = typeof options.project === "boolean" ? "project" : "user";
1315
+ const agentsDir = scope === "project" ? path5.join(process.cwd(), ".opencode/agents") : path5.join(process.env.XDG_CONFIG_HOME && process.env.XDG_CONFIG_HOME.trim() || path5.join(os3.homedir(), ".config"), "opencode", "agents");
1316
+ const sourceAgentsDir = path5.resolve(__dirname2, "..", "agents");
1317
+ if (subcommand === "install") {
1318
+ await fs2.mkdir(agentsDir, { recursive: true });
1319
+ let count = 0;
1320
+ const entries = await fs2.readdir(sourceAgentsDir);
1330
1321
  for (const entry of entries) {
1331
1322
  if (!entry.startsWith("massa-ai-") || !entry.endsWith(".md"))
1332
1323
  continue;
1333
- const filePath = path5.join(agentsDir, entry);
1334
- const content = await fs2.readFile(filePath, "utf8");
1335
- if (content.includes("massa-ai-owned: true")) {
1336
- await fs2.unlink(filePath);
1337
- removed++;
1324
+ const src = path5.join(sourceAgentsDir, entry);
1325
+ const dest = path5.join(agentsDir, entry);
1326
+ await fs2.copyFile(src, dest);
1327
+ count++;
1328
+ }
1329
+ console.log(`+ ${count} subagent specialists (generated from skills/agents/*/SKILL.md)`);
1330
+ console.log(` written to: ${agentsDir}`);
1331
+ } else {
1332
+ let removed = 0;
1333
+ try {
1334
+ const entries = await fs2.readdir(agentsDir);
1335
+ for (const entry of entries) {
1336
+ if (!entry.startsWith("massa-ai-") || !entry.endsWith(".md"))
1337
+ continue;
1338
+ const filePath = path5.join(agentsDir, entry);
1339
+ const content = await fs2.readFile(filePath, "utf8");
1340
+ if (content.includes("massa-ai-owned: true")) {
1341
+ await fs2.unlink(filePath);
1342
+ removed++;
1343
+ }
1338
1344
  }
1345
+ } catch (e) {
1346
+ if (e.code !== "ENOENT")
1347
+ throw e;
1339
1348
  }
1340
- } catch (e) {
1341
- if (e.code !== "ENOENT")
1342
- throw e;
1349
+ console.log(`- removed ${removed} massa-ai-owned agent files from ${agentsDir}`);
1350
+ console.log(" User agents preserved.");
1343
1351
  }
1344
- console.log(`- removed ${removed} massa-ai-owned agent files from ${agentsDir}`);
1345
- console.log(" User agents preserved.");
1352
+ break;
1346
1353
  }
1347
- break;
1354
+ default:
1355
+ console.error(`Unknown command: ${command}`);
1356
+ help();
1357
+ return 1;
1348
1358
  }
1349
- default:
1350
- console.error(`Unknown command: ${command}`);
1351
- help();
1352
- process.exit(1);
1359
+ return 0;
1353
1360
  }
1361
+ if (import.meta.main) {
1362
+ runCli(process.argv.slice(2)).then((code) => process.exit(code));
1363
+ }
1364
+ export {
1365
+ runCli,
1366
+ parseOptions
1367
+ };
package/dist/index.js CHANGED
@@ -556,7 +556,8 @@ __export(exports_config_loader, {
556
556
  getConfigPath: () => getConfigPath,
557
557
  getConfigForEnv: () => getConfigForEnv,
558
558
  getConfigDir: () => getConfigDir,
559
- configExists: () => configExists
559
+ configExists: () => configExists,
560
+ __resetMigrationForTests: () => __resetMigrationForTests
560
561
  });
561
562
  import fs from "fs";
562
563
  import path3 from "path";
@@ -626,6 +627,9 @@ function migrateDataDirOnce() {
626
627
  console.error(`[massa-ai] Data directory migration skipped:`, err);
627
628
  }
628
629
  }
630
+ function __resetMigrationForTests() {
631
+ migrationAttempted = false;
632
+ }
629
633
  function saveConfig(config2) {
630
634
  if (!fs.existsSync(CONFIG_DIR)) {
631
635
  fs.mkdirSync(CONFIG_DIR, { recursive: true });
@@ -635,7 +639,7 @@ function saveConfig(config2) {
635
639
  function initConfig() {
636
640
  if (!fs.existsSync(CONFIG_FILE)) {
637
641
  saveConfig(defaultMassaAiConfig);
638
- console.log(`Created default config at ${CONFIG_FILE}`);
642
+ console.error(`Created default config at ${CONFIG_FILE}`);
639
643
  }
640
644
  }
641
645
  function getConfigForEnv() {
@@ -13005,7 +13009,7 @@ function findEnvFile() {
13005
13009
  return;
13006
13010
  }
13007
13011
  var envPath = findEnvFile();
13008
- import_dotenv.config({ path: envPath });
13012
+ import_dotenv.config({ path: envPath, quiet: true });
13009
13013
  try {
13010
13014
  const { loadConfigSafe: loadConfigSafe2, migrateDataDirOnce: migrateDataDirOnce2 } = (init_config_loader(), __toCommonJS(exports_config_loader));
13011
13015
  migrateDataDirOnce2();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massa-ai/opencode-plugin",
3
- "version": "1.2.1",
3
+ "version": "1.4.0",
4
4
  "description": "massa-ai plugin for OpenCode - Semantic code search, memory, and context compression",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -21,8 +21,8 @@
21
21
  "dependencies": {
22
22
  "@opencode-ai/plugin": "^1.2.15",
23
23
  "@opencode-ai/sdk": "^1.2.15",
24
- "@massa-ai/core": "^1.2.1",
25
- "@massa-ai/shared": "^1.2.1"
24
+ "@massa-ai/core": "^1.4.0",
25
+ "@massa-ai/shared": "^1.4.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^22.10.5",