@massa-ai/opencode-plugin 1.35.1 → 1.37.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.
@@ -995,7 +995,8 @@ var defaultConfig = {
995
995
  },
996
996
  logging: {
997
997
  level: process.env.LOG_LEVEL || fileConfig.logging?.level || "info",
998
- enableMetrics: process.env.ENABLE_METRICS === "true" || process.env.ENABLE_METRICS === undefined && !!fileConfig.logging?.enableMetrics
998
+ enableMetrics: process.env.ENABLE_METRICS === "true" || process.env.ENABLE_METRICS === undefined && !!fileConfig.logging?.enableMetrics,
999
+ file: process.env.MASSA_AI_LOG_FILE || fileConfig.logging?.file || undefined
999
1000
  },
1000
1001
  synapse: {
1001
1002
  enabled: process.env.SYNAPSE_ENABLED !== "false",
@@ -1276,6 +1277,7 @@ var TaskStatus;
1276
1277
  TaskStatus2["PAUSED"] = "paused";
1277
1278
  })(TaskStatus || (TaskStatus = {}));
1278
1279
  // ../../packages/shared/dist/utils/logger.js
1280
+ import fs2 from "fs";
1279
1281
  var LogLevel;
1280
1282
  (function(LogLevel2) {
1281
1283
  LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
@@ -1287,17 +1289,20 @@ var LogLevel;
1287
1289
  class Logger {
1288
1290
  _level;
1289
1291
  _enableMetrics;
1292
+ _logFilePath;
1290
1293
  _initialized = false;
1291
1294
  constructor() {}
1292
1295
  ensureInitialized() {
1293
1296
  if (!this._initialized) {
1294
1297
  try {
1295
- const configLevel = config.get("logging").level;
1296
- this._level = this.parseLogLevel(configLevel);
1297
- this._enableMetrics = config.get("logging").enableMetrics;
1298
+ const loggingConfig = config.get("logging");
1299
+ this._level = this.parseLogLevel(loggingConfig.level);
1300
+ this._enableMetrics = loggingConfig.enableMetrics;
1301
+ this._logFilePath = loggingConfig.file;
1298
1302
  } catch {
1299
1303
  this._level = LogLevel.INFO;
1300
1304
  this._enableMetrics = false;
1305
+ this._logFilePath = undefined;
1301
1306
  }
1302
1307
  this._initialized = true;
1303
1308
  }
@@ -1310,6 +1315,10 @@ class Logger {
1310
1315
  this.ensureInitialized();
1311
1316
  return this._enableMetrics;
1312
1317
  }
1318
+ get logFilePath() {
1319
+ this.ensureInitialized();
1320
+ return this._logFilePath;
1321
+ }
1313
1322
  parseLogLevel(level) {
1314
1323
  const levels = {
1315
1324
  debug: LogLevel.DEBUG,
@@ -1329,6 +1338,13 @@ class Logger {
1329
1338
  }
1330
1339
  write(message, _level) {
1331
1340
  console.error(message);
1341
+ const filePath = this.logFilePath;
1342
+ if (filePath) {
1343
+ try {
1344
+ fs2.appendFileSync(filePath, message + `
1345
+ `);
1346
+ } catch {}
1347
+ }
1332
1348
  }
1333
1349
  debug(message, meta) {
1334
1350
  if (this.shouldLog(LogLevel.DEBUG)) {
@@ -1532,7 +1548,7 @@ function detectRoute(platform) {
1532
1548
  };
1533
1549
  }
1534
1550
  // ../../packages/shared/dist/profile-switch/state.js
1535
- import fs2 from "fs";
1551
+ import fs3 from "fs";
1536
1552
  import path6 from "path";
1537
1553
 
1538
1554
  class InstallStateError extends Error {
@@ -1569,7 +1585,7 @@ function validateShape(raw, filePath) {
1569
1585
  function readInstallState(filePath) {
1570
1586
  let text;
1571
1587
  try {
1572
- text = fs2.readFileSync(filePath, "utf-8");
1588
+ text = fs3.readFileSync(filePath, "utf-8");
1573
1589
  } catch (err) {
1574
1590
  const code = err.code;
1575
1591
  if (code === "ENOENT")
@@ -1589,8 +1605,8 @@ function writeInstallState(filePath, state) {
1589
1605
  const text = `${JSON.stringify(validated, null, 2)}
1590
1606
  `;
1591
1607
  try {
1592
- fs2.mkdirSync(path6.dirname(filePath), { recursive: true });
1593
- fs2.writeFileSync(filePath, text);
1608
+ fs3.mkdirSync(path6.dirname(filePath), { recursive: true });
1609
+ fs3.writeFileSync(filePath, text);
1594
1610
  } catch (err) {
1595
1611
  throw UnwritableInstallStateError(filePath, err.message);
1596
1612
  }
@@ -1607,7 +1623,7 @@ function updatePlatform(filePath, host, patch) {
1607
1623
  return next;
1608
1624
  }
1609
1625
  // ../../packages/shared/dist/profile-switch/lock.js
1610
- import fs3 from "fs";
1626
+ import fs4 from "fs";
1611
1627
  import path7 from "path";
1612
1628
  import os4 from "os";
1613
1629
  import crypto2 from "crypto";
@@ -1645,7 +1661,7 @@ var DEFAULT_IDENTITY = {
1645
1661
  function readOwner(ownerPath) {
1646
1662
  let raw;
1647
1663
  try {
1648
- raw = JSON.parse(fs3.readFileSync(ownerPath, "utf-8"));
1664
+ raw = JSON.parse(fs4.readFileSync(ownerPath, "utf-8"));
1649
1665
  } catch {
1650
1666
  return null;
1651
1667
  }
@@ -1661,7 +1677,7 @@ function releaseIfOwned(lockDir, ownerPath, token) {
1661
1677
  const owner = readOwner(ownerPath);
1662
1678
  if (owner === null || owner.token !== token)
1663
1679
  return;
1664
- fs3.rmSync(lockDir, { recursive: true, force: true });
1680
+ fs4.rmSync(lockDir, { recursive: true, force: true });
1665
1681
  }
1666
1682
  function acquireLock(stateFilePath, options = {}) {
1667
1683
  const lockDir = `${stateFilePath}.switch.lock`;
@@ -1670,11 +1686,11 @@ function acquireLock(stateFilePath, options = {}) {
1670
1686
  const identity = options.identity ?? DEFAULT_IDENTITY;
1671
1687
  const staleAfterMs = options.staleAfterMs ?? DEFAULT_STALE_AFTER_MS;
1672
1688
  const createFresh = () => {
1673
- fs3.mkdirSync(lockDir);
1689
+ fs4.mkdirSync(lockDir);
1674
1690
  const pid = identity.pid();
1675
1691
  const startedAt = identity.processStart(pid);
1676
1692
  if (startedAt == null) {
1677
- fs3.rmSync(lockDir, { recursive: true, force: true });
1693
+ fs4.rmSync(lockDir, { recursive: true, force: true });
1678
1694
  throw LockAcquireError(lockDir, "could not determine this process's start-time identity");
1679
1695
  }
1680
1696
  const token = crypto2.randomUUID();
@@ -1685,8 +1701,8 @@ function acquireLock(stateFilePath, options = {}) {
1685
1701
  token,
1686
1702
  timestamp: clock.now()
1687
1703
  };
1688
- fs3.mkdirSync(path7.dirname(ownerPath), { recursive: true });
1689
- fs3.writeFileSync(ownerPath, JSON.stringify(record));
1704
+ fs4.mkdirSync(path7.dirname(ownerPath), { recursive: true });
1705
+ fs4.writeFileSync(ownerPath, JSON.stringify(record));
1690
1706
  return { lockDir, release: () => releaseIfOwned(lockDir, ownerPath, token) };
1691
1707
  };
1692
1708
  try {
@@ -1701,11 +1717,11 @@ function acquireLock(stateFilePath, options = {}) {
1701
1717
  throw LockHeldError(lockDir);
1702
1718
  const reclaimDir = `${lockDir}.reclaim.${owner.token}`;
1703
1719
  try {
1704
- fs3.renameSync(lockDir, reclaimDir);
1720
+ fs4.renameSync(lockDir, reclaimDir);
1705
1721
  } catch {
1706
1722
  throw LockHeldError(lockDir);
1707
1723
  }
1708
- fs3.rmSync(reclaimDir, { recursive: true, force: true });
1724
+ fs4.rmSync(reclaimDir, { recursive: true, force: true });
1709
1725
  try {
1710
1726
  return createFresh();
1711
1727
  } catch {
@@ -1713,7 +1729,7 @@ function acquireLock(stateFilePath, options = {}) {
1713
1729
  }
1714
1730
  }
1715
1731
  // ../../packages/shared/dist/profile-switch/engine.js
1716
- import fs4 from "fs";
1732
+ import fs5 from "fs";
1717
1733
  import path8 from "path";
1718
1734
  import os5 from "os";
1719
1735
  import crypto3 from "crypto";
@@ -1755,7 +1771,7 @@ function listProfiles(opts = {}) {
1755
1771
  availableProfiles: []
1756
1772
  };
1757
1773
  }
1758
- const installed = fs4.existsSync(layout.activeDir);
1774
+ const installed = fs5.existsSync(layout.activeDir);
1759
1775
  const availableProfiles = listVariantProfiles(layout);
1760
1776
  const platform = state.platforms[host];
1761
1777
  return {
@@ -1771,9 +1787,9 @@ function listProfiles(opts = {}) {
1771
1787
  return { hosts };
1772
1788
  }
1773
1789
  function listVariantProfiles(layout) {
1774
- if (!fs4.existsSync(layout.variantsRoot))
1790
+ if (!fs5.existsSync(layout.variantsRoot))
1775
1791
  return [];
1776
- return fs4.readdirSync(layout.variantsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
1792
+ return fs5.readdirSync(layout.variantsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
1777
1793
  }
1778
1794
  function matchesGlob(filename, glob) {
1779
1795
  const starIdx = glob.indexOf("*");
@@ -1786,32 +1802,32 @@ function matchesGlob(filename, glob) {
1786
1802
  function assertStateWritable(stateFilePath) {
1787
1803
  const dir = path8.dirname(stateFilePath);
1788
1804
  try {
1789
- fs4.mkdirSync(dir, { recursive: true });
1805
+ fs5.mkdirSync(dir, { recursive: true });
1790
1806
  } catch (err) {
1791
1807
  throw UnwritableInstallStateError(stateFilePath, err.message);
1792
1808
  }
1793
- const checkPath = fs4.existsSync(stateFilePath) ? stateFilePath : dir;
1809
+ const checkPath = fs5.existsSync(stateFilePath) ? stateFilePath : dir;
1794
1810
  try {
1795
- fs4.accessSync(checkPath, fs4.constants.W_OK);
1811
+ fs5.accessSync(checkPath, fs5.constants.W_OK);
1796
1812
  } catch (err) {
1797
1813
  throw UnwritableInstallStateError(stateFilePath, err.message);
1798
1814
  }
1799
1815
  }
1800
1816
  function copyFileRouteVariant(layout, variantDir) {
1801
- fs4.mkdirSync(layout.activeDir, { recursive: true });
1817
+ fs5.mkdirSync(layout.activeDir, { recursive: true });
1802
1818
  let changed = 0;
1803
- for (const entry of fs4.readdirSync(variantDir, { withFileTypes: true })) {
1819
+ for (const entry of fs5.readdirSync(variantDir, { withFileTypes: true })) {
1804
1820
  if (!entry.isFile() || !matchesGlob(entry.name, layout.activeGlob))
1805
1821
  continue;
1806
- fs4.copyFileSync(path8.join(variantDir, entry.name), path8.join(layout.activeDir, entry.name));
1822
+ fs5.copyFileSync(path8.join(variantDir, entry.name), path8.join(layout.activeDir, entry.name));
1807
1823
  changed++;
1808
1824
  }
1809
1825
  return changed;
1810
1826
  }
1811
1827
  function repointOpencodeVariant(layout, variantDir) {
1812
- fs4.mkdirSync(layout.activeDir, { recursive: true });
1828
+ fs5.mkdirSync(layout.activeDir, { recursive: true });
1813
1829
  let changed = 0;
1814
- for (const entry of fs4.readdirSync(variantDir, { withFileTypes: true })) {
1830
+ for (const entry of fs5.readdirSync(variantDir, { withFileTypes: true })) {
1815
1831
  if (!entry.isFile() || !matchesGlob(entry.name, layout.activeGlob))
1816
1832
  continue;
1817
1833
  const dest = path8.join(layout.activeDir, entry.name);
@@ -1819,15 +1835,15 @@ function repointOpencodeVariant(layout, variantDir) {
1819
1835
  let destExists = true;
1820
1836
  let destIsSymlink = false;
1821
1837
  try {
1822
- destIsSymlink = fs4.lstatSync(dest).isSymbolicLink();
1838
+ destIsSymlink = fs5.lstatSync(dest).isSymbolicLink();
1823
1839
  } catch {
1824
1840
  destExists = false;
1825
1841
  }
1826
1842
  if (destExists && !destIsSymlink)
1827
1843
  continue;
1828
1844
  const tmp = `${dest}.massa-ai-switch.${crypto3.randomUUID()}`;
1829
- fs4.symlinkSync(target, tmp);
1830
- fs4.renameSync(tmp, dest);
1845
+ fs5.symlinkSync(target, tmp);
1846
+ fs5.renameSync(tmp, dest);
1831
1847
  changed++;
1832
1848
  }
1833
1849
  return changed;
@@ -1849,13 +1865,13 @@ function switchProfile(opts) {
1849
1865
  if (fileHosts.length === 0) {
1850
1866
  return { profile: opts.profile, dryRun, hosts: orderRows(universe, skipRows), restartRequired: false };
1851
1867
  }
1852
- const installedFileHosts = fileHosts.filter((h) => fs4.existsSync(h.layout.activeDir));
1868
+ const installedFileHosts = fileHosts.filter((h) => fs5.existsSync(h.layout.activeDir));
1853
1869
  if (installedFileHosts.length === 0)
1854
1870
  throw NoHostsDetectedError();
1855
1871
  const withAvailability = fileHosts.map((h) => {
1856
- const variantsRootExists = fs4.existsSync(h.layout.variantsRoot);
1872
+ const variantsRootExists = fs5.existsSync(h.layout.variantsRoot);
1857
1873
  const variantDir = h.layout.variantDir(opts.profile);
1858
- const available = variantsRootExists && fs4.existsSync(variantDir) && fs4.statSync(variantDir).isDirectory();
1874
+ const available = variantsRootExists && fs5.existsSync(variantDir) && fs5.statSync(variantDir).isDirectory();
1859
1875
  return { ...h, variantsRootExists, variantDir, available };
1860
1876
  });
1861
1877
  if (!withAvailability.some((h) => h.available)) {
@@ -1920,7 +1936,7 @@ function reportSucceeded(report) {
1920
1936
  return report.hosts.every((h) => h.status === "switched" || h.status === "skipped");
1921
1937
  }
1922
1938
  // src/config-cli.ts
1923
- import { promises as fs5 } from "fs";
1939
+ import { promises as fs6 } from "fs";
1924
1940
  import path9 from "path";
1925
1941
  import os6 from "os";
1926
1942
  import { fileURLToPath } from "url";
@@ -2129,15 +2145,15 @@ Using defaults:`);
2129
2145
  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");
2130
2146
  const sourceAgentsDir = path9.resolve(__dirname2, "..", "agents");
2131
2147
  if (subcommand === "install") {
2132
- await fs5.mkdir(agentsDir, { recursive: true });
2148
+ await fs6.mkdir(agentsDir, { recursive: true });
2133
2149
  let count = 0;
2134
- const entries = await fs5.readdir(sourceAgentsDir);
2150
+ const entries = await fs6.readdir(sourceAgentsDir);
2135
2151
  for (const entry of entries) {
2136
2152
  if (!entry.startsWith("massa-ai-") || !entry.endsWith(".md"))
2137
2153
  continue;
2138
2154
  const src = path9.join(sourceAgentsDir, entry);
2139
2155
  const dest = path9.join(agentsDir, entry);
2140
- await fs5.copyFile(src, dest);
2156
+ await fs6.copyFile(src, dest);
2141
2157
  count++;
2142
2158
  }
2143
2159
  console.log(`+ ${count} subagent specialists (generated from skills/agents/*/SKILL.md)`);
@@ -2145,14 +2161,14 @@ Using defaults:`);
2145
2161
  } else {
2146
2162
  let removed = 0;
2147
2163
  try {
2148
- const entries = await fs5.readdir(agentsDir);
2164
+ const entries = await fs6.readdir(agentsDir);
2149
2165
  for (const entry of entries) {
2150
2166
  if (!entry.startsWith("massa-ai-") || !entry.endsWith(".md"))
2151
2167
  continue;
2152
2168
  const filePath = path9.join(agentsDir, entry);
2153
- const content = await fs5.readFile(filePath, "utf8");
2169
+ const content = await fs6.readFile(filePath, "utf8");
2154
2170
  if (content.includes("massa-ai-owned: true")) {
2155
- await fs5.unlink(filePath);
2171
+ await fs6.unlink(filePath);
2156
2172
  removed++;
2157
2173
  }
2158
2174
  }
package/dist/index.js CHANGED
@@ -994,7 +994,8 @@ var defaultConfig = {
994
994
  },
995
995
  logging: {
996
996
  level: process.env.LOG_LEVEL || fileConfig.logging?.level || "info",
997
- enableMetrics: process.env.ENABLE_METRICS === "true" || process.env.ENABLE_METRICS === undefined && !!fileConfig.logging?.enableMetrics
997
+ enableMetrics: process.env.ENABLE_METRICS === "true" || process.env.ENABLE_METRICS === undefined && !!fileConfig.logging?.enableMetrics,
998
+ file: process.env.MASSA_AI_LOG_FILE || fileConfig.logging?.file || undefined
998
999
  },
999
1000
  synapse: {
1000
1001
  enabled: process.env.SYNAPSE_ENABLED !== "false",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massa-ai/opencode-plugin",
3
- "version": "1.35.1",
3
+ "version": "1.37.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.35.1",
28
- "@massa-ai/shared": "^1.35.1"
27
+ "@massa-ai/core": "^1.37.0",
28
+ "@massa-ai/shared": "^1.37.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/node": "^22.10.5",