@massa-ai/opencode-plugin 1.41.0 → 1.43.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.
@@ -552,6 +552,7 @@ var init_massa_ai_config = __esm(() => {
552
552
  // ../../packages/shared/dist/config/config-loader.js
553
553
  var exports_config_loader = {};
554
554
  __export(exports_config_loader, {
555
+ writeFileAtomically: () => writeFileAtomically,
555
556
  saveConfig: () => saveConfig,
556
557
  migrateDataDirOnce: () => migrateDataDirOnce,
557
558
  loadConfigSafe: () => loadConfigSafe,
@@ -636,15 +637,17 @@ function migrateDataDirOnce() {
636
637
  function __resetMigrationForTests() {
637
638
  migrationAttempted = false;
638
639
  }
639
- function saveConfig(config) {
640
- if (!fs.existsSync(CONFIG_DIR)) {
641
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
640
+ function writeFileAtomically(targetPath, content) {
641
+ const dir = path3.dirname(targetPath);
642
+ if (!fs.existsSync(dir)) {
643
+ fs.mkdirSync(dir, { recursive: true });
642
644
  }
643
645
  const unique = `${process.pid}.${++tempFileCounter}.${crypto.randomBytes(6).toString("hex")}`;
644
- const tempFile = path3.join(CONFIG_DIR, `.config.json.${unique}.tmp`);
646
+ const tempFile = path3.join(dir, `.${path3.basename(targetPath)}.${unique}.tmp`);
645
647
  try {
646
- fs.writeFileSync(tempFile, JSON.stringify(config, null, 2));
647
- fs.renameSync(tempFile, CONFIG_FILE);
648
+ fs.writeFileSync(tempFile, content, { mode: 384 });
649
+ fs.chmodSync(tempFile, 384);
650
+ fs.renameSync(tempFile, targetPath);
648
651
  } catch (error) {
649
652
  try {
650
653
  fs.unlinkSync(tempFile);
@@ -652,6 +655,9 @@ function saveConfig(config) {
652
655
  throw error;
653
656
  }
654
657
  }
658
+ function saveConfig(config) {
659
+ writeFileAtomically(CONFIG_FILE, JSON.stringify(config, null, 2));
660
+ }
655
661
  function initConfig() {
656
662
  if (!fs.existsSync(CONFIG_FILE)) {
657
663
  saveConfig(defaultMassaAiConfig);
@@ -1785,7 +1791,7 @@ function listProfiles(opts = {}) {
1785
1791
  installed,
1786
1792
  skipped: false,
1787
1793
  skipReason: null,
1788
- activeProfile: platform?.modelProfile?.profile ?? "balanced",
1794
+ activeProfile: platform?.modelProfile?.profile ?? opts.hostDefaults?.[host] ?? "balanced",
1789
1795
  bundleVersion: platform?.plugin?.version ?? null,
1790
1796
  availableProfiles
1791
1797
  };
@@ -1941,12 +1947,123 @@ function orderRows(universe, rows) {
1941
1947
  function reportSucceeded(report) {
1942
1948
  return report.hosts.every((h) => h.status === "switched" || h.status === "skipped");
1943
1949
  }
1944
- // src/config-cli.ts
1945
- import { promises as fs6 } from "fs";
1950
+ // ../../packages/shared/dist/profile-switch/variant-sync.js
1951
+ import fs6 from "fs";
1946
1952
  import path9 from "path";
1953
+ import crypto4 from "crypto";
1954
+ var tempFileCounter2 = 0;
1955
+ function writeFileIntoDirAtomically(destDir, destName, content) {
1956
+ const unique = `${process.pid}.${++tempFileCounter2}.${crypto4.randomBytes(6).toString("hex")}`;
1957
+ const tempFile = path9.join(destDir, `.${destName}.${unique}.tmp`);
1958
+ try {
1959
+ fs6.writeFileSync(tempFile, content);
1960
+ fs6.renameSync(tempFile, path9.join(destDir, destName));
1961
+ } catch (error) {
1962
+ try {
1963
+ fs6.unlinkSync(tempFile);
1964
+ } catch {}
1965
+ throw error;
1966
+ }
1967
+ }
1968
+ function isSafeDirName(name) {
1969
+ if (name === "." || name === "..")
1970
+ return false;
1971
+ if (name.includes("/") || name.includes("\\") || name.includes(path9.sep))
1972
+ return false;
1973
+ return path9.basename(name) === name;
1974
+ }
1975
+ function syncHost(host, sourceRoot, targetHome) {
1976
+ const layout = resolveHostLayout(host, { targetHome });
1977
+ if (layout.route === "skip") {
1978
+ return { host, status: "skipped", profiles: [], retained: [], files: 0, reason: layout.reason };
1979
+ }
1980
+ const srcDir = path9.join(sourceRoot, "apps", `${host}-plugin`, "agent-profiles");
1981
+ if (!fs6.existsSync(srcDir) || !fs6.statSync(srcDir).isDirectory()) {
1982
+ return { host, status: "skipped", profiles: [], retained: [], files: 0, reason: "no generated variants for this host" };
1983
+ }
1984
+ if (!fs6.existsSync(layout.variantsRoot)) {
1985
+ return {
1986
+ host,
1987
+ status: "skipped",
1988
+ profiles: [],
1989
+ retained: [],
1990
+ files: 0,
1991
+ reason: `variant tree not present at ${layout.variantsRoot} \u2014 run the plugin installer ` + "or an initial profile switch"
1992
+ };
1993
+ }
1994
+ const profiles = [];
1995
+ let files = 0;
1996
+ for (const entry of fs6.readdirSync(srcDir, { withFileTypes: true })) {
1997
+ if (!entry.isDirectory())
1998
+ continue;
1999
+ if (!isSafeDirName(entry.name))
2000
+ continue;
2001
+ const srcProfileDir = path9.join(srcDir, entry.name);
2002
+ const destProfileDir = path9.join(layout.variantsRoot, entry.name);
2003
+ fs6.mkdirSync(destProfileDir, { recursive: true });
2004
+ for (const fileEntry of fs6.readdirSync(srcProfileDir, { withFileTypes: true })) {
2005
+ if (!fileEntry.isFile())
2006
+ continue;
2007
+ const content = fs6.readFileSync(path9.join(srcProfileDir, fileEntry.name));
2008
+ writeFileIntoDirAtomically(destProfileDir, fileEntry.name, content);
2009
+ files++;
2010
+ }
2011
+ profiles.push(entry.name);
2012
+ }
2013
+ const retained = fs6.readdirSync(layout.variantsRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && !profiles.includes(e.name)).map((e) => e.name).sort();
2014
+ return { host, status: "synced", profiles: profiles.sort(), retained, files };
2015
+ }
2016
+ function syncGeneratedVariants(opts) {
2017
+ const hosts = opts.hosts ?? HOSTS;
2018
+ if (!opts.sourceRoot) {
2019
+ return hosts.map((host) => ({
2020
+ host,
2021
+ status: "skipped",
2022
+ profiles: [],
2023
+ retained: [],
2024
+ files: 0,
2025
+ reason: "no source checkout \u2014 nothing to sync"
2026
+ }));
2027
+ }
2028
+ const sourceRoot = opts.sourceRoot;
2029
+ return hosts.map((host) => {
2030
+ try {
2031
+ return syncHost(host, sourceRoot, opts.targetHome);
2032
+ } catch (err) {
2033
+ return { host, status: "failed", profiles: [], retained: [], files: 0, error: err.message };
2034
+ }
2035
+ });
2036
+ }
2037
+ // ../../packages/shared/dist/profile-switch/repo-root.js
2038
+ import fs7 from "fs";
2039
+ import path10 from "path";
2040
+ function findRepoRootWithMarker(startDir, marker, maxLevels) {
2041
+ let dir = startDir;
2042
+ for (let i = 0;i <= maxLevels; i++) {
2043
+ if (fs7.existsSync(path10.join(dir, marker)))
2044
+ return dir;
2045
+ const parent = path10.dirname(dir);
2046
+ if (parent === dir)
2047
+ break;
2048
+ dir = parent;
2049
+ }
2050
+ return null;
2051
+ }
2052
+ // src/config-cli.ts
2053
+ import { promises as fs8 } from "fs";
2054
+ import path11 from "path";
1947
2055
  import os6 from "os";
1948
2056
  import { fileURLToPath } from "url";
1949
- var __dirname2 = path9.dirname(fileURLToPath(import.meta.url));
2057
+ var __dirname2 = path11.dirname(fileURLToPath(import.meta.url));
2058
+ var GENERATOR_MARKER = "scripts/generate-subagent-artifacts.ts";
2059
+ var GENERATOR_MARKER_MAX_LEVELS = 6;
2060
+ function formatVariantSync(results) {
2061
+ for (const r of results) {
2062
+ if (r.status === "synced") {
2063
+ console.log(` synced ${r.host}: ${r.files} file(s) across ${r.profiles.length} profile(s)`);
2064
+ }
2065
+ }
2066
+ }
1950
2067
  function help() {
1951
2068
  console.log(`
1952
2069
  massa-ai-config - Configuration manager for massa-ai
@@ -2148,18 +2265,18 @@ Using defaults:`);
2148
2265
  return 1;
2149
2266
  }
2150
2267
  const scope = typeof options.project === "boolean" ? "project" : "user";
2151
- const agentsDir = scope === "project" ? path9.join(process.cwd(), ".opencode/agents") : path9.join(process.env.XDG_CONFIG_HOME && process.env.XDG_CONFIG_HOME.trim() || path9.join(os6.homedir(), ".config"), "opencode", "agents");
2152
- const sourceAgentsDir = path9.resolve(__dirname2, "..", "agents");
2268
+ const agentsDir = scope === "project" ? path11.join(process.cwd(), ".opencode/agents") : path11.join(process.env.XDG_CONFIG_HOME && process.env.XDG_CONFIG_HOME.trim() || path11.join(os6.homedir(), ".config"), "opencode", "agents");
2269
+ const sourceAgentsDir = path11.resolve(__dirname2, "..", "agents");
2153
2270
  if (subcommand === "install") {
2154
- await fs6.mkdir(agentsDir, { recursive: true });
2271
+ await fs8.mkdir(agentsDir, { recursive: true });
2155
2272
  let count = 0;
2156
- const entries = await fs6.readdir(sourceAgentsDir);
2273
+ const entries = await fs8.readdir(sourceAgentsDir);
2157
2274
  for (const entry of entries) {
2158
2275
  if (!entry.startsWith("massa-ai-") || !entry.endsWith(".md"))
2159
2276
  continue;
2160
- const src = path9.join(sourceAgentsDir, entry);
2161
- const dest = path9.join(agentsDir, entry);
2162
- await fs6.copyFile(src, dest);
2277
+ const src = path11.join(sourceAgentsDir, entry);
2278
+ const dest = path11.join(agentsDir, entry);
2279
+ await fs8.copyFile(src, dest);
2163
2280
  count++;
2164
2281
  }
2165
2282
  console.log(`+ ${count} subagent specialists (generated from skills/agents/*/SKILL.md)`);
@@ -2167,14 +2284,14 @@ Using defaults:`);
2167
2284
  } else {
2168
2285
  let removed = 0;
2169
2286
  try {
2170
- const entries = await fs6.readdir(agentsDir);
2287
+ const entries = await fs8.readdir(agentsDir);
2171
2288
  for (const entry of entries) {
2172
2289
  if (!entry.startsWith("massa-ai-") || !entry.endsWith(".md"))
2173
2290
  continue;
2174
- const filePath = path9.join(agentsDir, entry);
2175
- const content = await fs6.readFile(filePath, "utf8");
2291
+ const filePath = path11.join(agentsDir, entry);
2292
+ const content = await fs8.readFile(filePath, "utf8");
2176
2293
  if (content.includes("massa-ai-owned: true")) {
2177
- await fs6.unlink(filePath);
2294
+ await fs8.unlink(filePath);
2178
2295
  removed++;
2179
2296
  }
2180
2297
  }
@@ -2210,6 +2327,8 @@ Using defaults:`);
2210
2327
  return 1;
2211
2328
  }
2212
2329
  try {
2330
+ const sourceRoot = findRepoRootWithMarker(__dirname2, GENERATOR_MARKER, GENERATOR_MARKER_MAX_LEVELS);
2331
+ formatVariantSync(syncGeneratedVariants({ sourceRoot }));
2213
2332
  const report = switchProfile({
2214
2333
  profile: name,
2215
2334
  host: hostOpt,
package/dist/index.js CHANGED
@@ -551,6 +551,7 @@ var init_massa_ai_config = __esm(() => {
551
551
  // ../../packages/shared/dist/config/config-loader.js
552
552
  var exports_config_loader = {};
553
553
  __export(exports_config_loader, {
554
+ writeFileAtomically: () => writeFileAtomically,
554
555
  saveConfig: () => saveConfig,
555
556
  migrateDataDirOnce: () => migrateDataDirOnce,
556
557
  loadConfigSafe: () => loadConfigSafe,
@@ -635,15 +636,17 @@ function migrateDataDirOnce() {
635
636
  function __resetMigrationForTests() {
636
637
  migrationAttempted = false;
637
638
  }
638
- function saveConfig(config) {
639
- if (!fs.existsSync(CONFIG_DIR)) {
640
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
639
+ function writeFileAtomically(targetPath, content) {
640
+ const dir = path3.dirname(targetPath);
641
+ if (!fs.existsSync(dir)) {
642
+ fs.mkdirSync(dir, { recursive: true });
641
643
  }
642
644
  const unique = `${process.pid}.${++tempFileCounter}.${crypto.randomBytes(6).toString("hex")}`;
643
- const tempFile = path3.join(CONFIG_DIR, `.config.json.${unique}.tmp`);
645
+ const tempFile = path3.join(dir, `.${path3.basename(targetPath)}.${unique}.tmp`);
644
646
  try {
645
- fs.writeFileSync(tempFile, JSON.stringify(config, null, 2));
646
- fs.renameSync(tempFile, CONFIG_FILE);
647
+ fs.writeFileSync(tempFile, content, { mode: 384 });
648
+ fs.chmodSync(tempFile, 384);
649
+ fs.renameSync(tempFile, targetPath);
647
650
  } catch (error) {
648
651
  try {
649
652
  fs.unlinkSync(tempFile);
@@ -651,6 +654,9 @@ function saveConfig(config) {
651
654
  throw error;
652
655
  }
653
656
  }
657
+ function saveConfig(config) {
658
+ writeFileAtomically(CONFIG_FILE, JSON.stringify(config, null, 2));
659
+ }
654
660
  function initConfig() {
655
661
  if (!fs.existsSync(CONFIG_FILE)) {
656
662
  saveConfig(defaultMassaAiConfig);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massa-ai/opencode-plugin",
3
- "version": "1.41.0",
3
+ "version": "1.43.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",
@@ -24,8 +24,8 @@
24
24
  "dependencies": {
25
25
  "@opencode-ai/plugin": "^1.2.15",
26
26
  "@opencode-ai/sdk": "^1.2.15",
27
- "@massa-ai/core": "^1.41.0",
28
- "@massa-ai/shared": "^1.41.0"
27
+ "@massa-ai/core": "^1.43.0",
28
+ "@massa-ai/shared": "^1.43.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/node": "^22.10.5",