@nxuss/lemma 1.21.0 → 1.22.1
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/.agents/skills/lemma/SKILL.md +8 -6
- package/README.md +4 -2
- package/bin/doctor.js +131 -0
- package/bin/init.js +173 -57
- package/bin/postinstall.js +43 -0
- package/dist/cjs/cli/lemma-proxy.d.ts +2 -0
- package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
- package/dist/cjs/cli/lemma-proxy.js +41 -0
- package/dist/cjs/cli/lemma-proxy.js.map +1 -1
- package/dist/esm/cli/lemma-proxy.d.ts +2 -0
- package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
- package/dist/esm/cli/lemma-proxy.js +39 -0
- package/dist/esm/cli/lemma-proxy.js.map +1 -1
- package/lemma-proxy.cjs +19 -1
- package/package.json +4 -1
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
export declare function startBackgroundClipboardWatcher(cliOpts?: {
|
|
3
3
|
clipboard?: boolean;
|
|
4
4
|
}): void;
|
|
5
|
+
export declare const MAX_WORKSPACE_WATCHERS = 512;
|
|
6
|
+
export declare function isUnsafeWatchRoot(dir: string): boolean;
|
|
5
7
|
export declare function performAutoHeal(apply: boolean): Promise<{
|
|
6
8
|
success: boolean;
|
|
7
9
|
message: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lemma-proxy.d.ts","sourceRoot":"","sources":["../../../src/cli/lemma-proxy.ts"],"names":[],"mappings":";AA0cA,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CA4DvF;
|
|
1
|
+
{"version":3,"file":"lemma-proxy.d.ts","sourceRoot":"","sources":["../../../src/cli/lemma-proxy.ts"],"names":[],"mappings":";AA0cA,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CA4DvF;AAqfD,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGtD;AAyqDD,wBAAsB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA8KhL"}
|
|
@@ -953,6 +953,16 @@ class WriteQueue {
|
|
|
953
953
|
}
|
|
954
954
|
}
|
|
955
955
|
const usageWriteQueue = new WriteQueue();
|
|
956
|
+
// One fs.watch FD is opened per watched directory. Watching $HOME (the launchd
|
|
957
|
+
// daemon's WorkingDirectory) or a filesystem root exhausts FDs (EMFILE), crashes
|
|
958
|
+
// the process, and a KeepAlive supervisor turns that into an infinite
|
|
959
|
+
// crash/relaunch loop — on macOS each relaunch re-triggers the TCC data-access
|
|
960
|
+
// prompt. Refuse those roots outright.
|
|
961
|
+
export const MAX_WORKSPACE_WATCHERS = 512;
|
|
962
|
+
export function isUnsafeWatchRoot(dir) {
|
|
963
|
+
const resolved = path.resolve(dir);
|
|
964
|
+
return resolved === path.resolve(os.homedir()) || resolved === path.parse(resolved).root;
|
|
965
|
+
}
|
|
956
966
|
// ── Proxy Server class ─────────────────────────────────────────────────────────
|
|
957
967
|
class LemmaServer {
|
|
958
968
|
constructor(port, projectName, openBrowser = true) {
|
|
@@ -1641,12 +1651,28 @@ class LemmaServer {
|
|
|
1641
1651
|
}
|
|
1642
1652
|
startWorkspaceTimeWatcher() {
|
|
1643
1653
|
const cwd = process.cwd();
|
|
1654
|
+
if (isUnsafeWatchRoot(cwd)) {
|
|
1655
|
+
console.log(`⏭️ [TimeTravel] Skipping workspace watcher: refusing to watch ${cwd} recursively (file-descriptor exhaustion risk). Start the proxy from a project directory instead.`);
|
|
1656
|
+
return;
|
|
1657
|
+
}
|
|
1644
1658
|
const { watch } = require('fs');
|
|
1645
1659
|
// Debounced capture function
|
|
1646
1660
|
let debounceTimer = null;
|
|
1647
1661
|
const pendingChanges = new Set();
|
|
1662
|
+
// One FD per watched directory: cap it so giant trees degrade to a warning
|
|
1663
|
+
// instead of an EMFILE crash (which a KeepAlive supervisor turns into a
|
|
1664
|
+
// crash/relaunch loop).
|
|
1665
|
+
let watchCount = 0;
|
|
1666
|
+
let limitWarned = false;
|
|
1648
1667
|
const ignoreDirs = ['node_modules', '.git', 'dist', 'chroma_data', '.lemma', 'dashboard', 'bin', 'sdks'];
|
|
1649
1668
|
const watchDirRecursive = (dir) => {
|
|
1669
|
+
if (watchCount >= MAX_WORKSPACE_WATCHERS) {
|
|
1670
|
+
if (!limitWarned) {
|
|
1671
|
+
limitWarned = true;
|
|
1672
|
+
console.log(`⚠️ [TimeTravel] Watcher limit (${MAX_WORKSPACE_WATCHERS} dirs) reached at ${dir} — deeper directories won't trigger snapshots.`);
|
|
1673
|
+
}
|
|
1674
|
+
return;
|
|
1675
|
+
}
|
|
1650
1676
|
try {
|
|
1651
1677
|
const watcher = watch(dir, (eventType, filename) => {
|
|
1652
1678
|
if (!filename)
|
|
@@ -1668,6 +1694,19 @@ class LemmaServer {
|
|
|
1668
1694
|
// Prevent watcher from keeping process alive if in background
|
|
1669
1695
|
if (watcher.unref)
|
|
1670
1696
|
watcher.unref();
|
|
1697
|
+
watchCount++;
|
|
1698
|
+
// An async EMFILE/ENOSPC on a giant tree must never take down the server:
|
|
1699
|
+
// contain it to a single warning and keep serving.
|
|
1700
|
+
watcher.on('error', (err) => {
|
|
1701
|
+
if (!limitWarned) {
|
|
1702
|
+
limitWarned = true;
|
|
1703
|
+
console.log(`⚠️ [TimeTravel] Watcher error (${(err && err.code) || 'unknown'}) — snapshots degraded, server keeps running.`);
|
|
1704
|
+
}
|
|
1705
|
+
try {
|
|
1706
|
+
watcher.close();
|
|
1707
|
+
}
|
|
1708
|
+
catch { }
|
|
1709
|
+
});
|
|
1671
1710
|
// Recursively watch subfolders
|
|
1672
1711
|
const files = fs.readdirSync(dir, { withFileTypes: true });
|
|
1673
1712
|
for (const file of files) {
|