@monoes/cli 1.2.1 → 1.2.2

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.
@@ -824,6 +824,199 @@ export const graphifyVisualizeTool = {
824
824
  }
825
825
  },
826
826
  };
827
+ // ── Watch PID helpers ─────────────────────────────────────────────────────────
828
+ function getPidPath(cwd) {
829
+ return resolve(join(cwd, '.monobrain', 'graph', 'watch.pid'));
830
+ }
831
+ function readWatchPid(cwd) {
832
+ const pidPath = getPidPath(cwd);
833
+ if (!existsSync(pidPath))
834
+ return null;
835
+ try {
836
+ const pid = parseInt(readFileSync(pidPath, 'utf-8').trim(), 10);
837
+ return isNaN(pid) ? null : pid;
838
+ }
839
+ catch {
840
+ return null;
841
+ }
842
+ }
843
+ function isProcessRunning(pid) {
844
+ try {
845
+ process.kill(pid, 0);
846
+ return true;
847
+ }
848
+ catch {
849
+ return false;
850
+ }
851
+ }
852
+ // ── Watch tools ───────────────────────────────────────────────────────────────
853
+ export const graphifyWatchTool = {
854
+ name: 'graphify_watch',
855
+ description: 'Start a background file watcher that automatically rebuilds the knowledge graph ' +
856
+ '(graph.json + graph.html) whenever source files change. Uses a 2-second debounce ' +
857
+ 'so rapid saves do not trigger repeated rebuilds. The watcher runs as a detached ' +
858
+ 'background process — call graphify_watch_stop to stop it.',
859
+ category: 'graphify',
860
+ tags: ['knowledge-graph', 'watch', 'auto-rebuild'],
861
+ inputSchema: {
862
+ type: 'object',
863
+ properties: {
864
+ path: {
865
+ type: 'string',
866
+ description: 'Project root to watch (defaults to current project root)',
867
+ },
868
+ debounce: {
869
+ type: 'number',
870
+ description: 'Debounce delay in milliseconds (default 2000)',
871
+ default: 2000,
872
+ },
873
+ extensions: {
874
+ type: 'string',
875
+ description: 'Comma-separated list of file extensions to watch (default: ts,js,tsx,jsx,py,go,rs,java,cs,rb,cpp,c)',
876
+ default: 'ts,js,tsx,jsx,py,go,rs,java,cs,rb,cpp,c',
877
+ },
878
+ },
879
+ },
880
+ handler: async (params) => {
881
+ const cwd = getProjectCwd();
882
+ const targetPath = params.path || cwd;
883
+ const debounceMs = params.debounce || 2000;
884
+ const extensions = ((params.extensions) || 'ts,js,tsx,jsx,py,go,rs,java,cs,rb,cpp,c')
885
+ .split(',')
886
+ .map((e) => e.trim())
887
+ .filter(Boolean);
888
+ // Check if already running
889
+ const existingPid = readWatchPid(targetPath);
890
+ if (existingPid !== null && isProcessRunning(existingPid)) {
891
+ return {
892
+ success: false,
893
+ message: `Watcher already running (PID ${existingPid})`,
894
+ hint: 'Call graphify_watch_stop first to restart.',
895
+ };
896
+ }
897
+ const pidPath = getPidPath(targetPath);
898
+ const outputDir = resolve(join(targetPath, '.monobrain', 'graph'));
899
+ const watcherScript = `
900
+ import { watch } from 'chokidar';
901
+ import { writeFileSync, mkdirSync } from 'fs';
902
+
903
+ const TARGET = ${JSON.stringify(targetPath)};
904
+ const OUTPUT_DIR = ${JSON.stringify(outputDir)};
905
+ const PID_PATH = ${JSON.stringify(pidPath)};
906
+ const DEBOUNCE_MS = ${debounceMs};
907
+ const EXTS = new Set(${JSON.stringify(extensions)});
908
+ const IGNORE = [/node_modules/, /\\.git/, /\\.monobrain/, /dist[\\/]/, /\\.next/, /\\.turbo/, /coverage/];
909
+
910
+ mkdirSync(OUTPUT_DIR, { recursive: true });
911
+ writeFileSync(PID_PATH, String(process.pid));
912
+ console.log('[graphify-watch] PID', process.pid, '— watching', TARGET);
913
+
914
+ let timer = null;
915
+
916
+ async function rebuild() {
917
+ const start = Date.now();
918
+ console.log('[graphify-watch] Change detected — rebuilding graph…');
919
+ try {
920
+ const { buildGraph } = await import('@monoes/graph');
921
+ const { exportHTML } = await import('@monoes/graph');
922
+ const { graph: serialized } = await buildGraph(TARGET, { outputDir: OUTPUT_DIR });
923
+ exportHTML(serialized, OUTPUT_DIR);
924
+ console.log('[graphify-watch] Done in', Date.now() - start, 'ms');
925
+ } catch (err) {
926
+ console.error('[graphify-watch] Build error:', err.message ?? err);
927
+ }
928
+ }
929
+
930
+ const watcher = watch(TARGET, {
931
+ ignored: (p) => IGNORE.some((r) => r.test(p)),
932
+ persistent: true,
933
+ ignoreInitial: true,
934
+ awaitWriteFinish: { stabilityThreshold: 300, pollInterval: 100 },
935
+ });
936
+
937
+ watcher.on('all', (event, filePath) => {
938
+ const ext = filePath.split('.').pop() ?? '';
939
+ if (!EXTS.has(ext)) return;
940
+ if (timer) clearTimeout(timer);
941
+ timer = setTimeout(rebuild, DEBOUNCE_MS);
942
+ });
943
+
944
+ watcher.on('error', (err) => console.error('[graphify-watch] Watcher error:', err));
945
+ process.on('SIGINT', () => process.exit(0));
946
+ process.on('SIGTERM', () => process.exit(0));
947
+ `;
948
+ try {
949
+ const { spawn } = await import('child_process');
950
+ const { writeFileSync, mkdirSync } = await import('fs');
951
+ mkdirSync(outputDir, { recursive: true });
952
+ const scriptPath = resolve(join(outputDir, '_watcher.mjs'));
953
+ writeFileSync(scriptPath, watcherScript);
954
+ const child = spawn(process.execPath, [scriptPath], {
955
+ detached: true,
956
+ stdio: 'ignore',
957
+ env: { ...process.env },
958
+ });
959
+ child.unref();
960
+ await new Promise((r) => setTimeout(r, 500));
961
+ const pid = readWatchPid(targetPath) ?? child.pid;
962
+ return {
963
+ success: true,
964
+ pid,
965
+ watching: targetPath,
966
+ debounceMs,
967
+ extensions,
968
+ message: `Graph watcher started (PID ${pid}). graph.json + graph.html will rebuild on file changes.`,
969
+ hint: 'Call graphify_watch_stop to stop.',
970
+ };
971
+ }
972
+ catch (err) {
973
+ return { error: true, message: String(err) };
974
+ }
975
+ },
976
+ };
977
+ export const graphifyWatchStopTool = {
978
+ name: 'graphify_watch_stop',
979
+ description: 'Stop the background file watcher started by graphify_watch.',
980
+ category: 'graphify',
981
+ tags: ['knowledge-graph', 'watch'],
982
+ inputSchema: {
983
+ type: 'object',
984
+ properties: {
985
+ path: {
986
+ type: 'string',
987
+ description: 'Project root (defaults to current project root)',
988
+ },
989
+ },
990
+ },
991
+ handler: async (params) => {
992
+ const cwd = getProjectCwd();
993
+ const targetPath = params.path || cwd;
994
+ const pid = readWatchPid(targetPath);
995
+ if (pid === null) {
996
+ return { success: false, message: 'No watcher PID found — watcher may not be running.' };
997
+ }
998
+ if (!isProcessRunning(pid)) {
999
+ try {
1000
+ const { unlinkSync } = await import('fs');
1001
+ unlinkSync(getPidPath(targetPath));
1002
+ }
1003
+ catch { /* ignore */ }
1004
+ return { success: false, message: `Process ${pid} is not running (stale PID cleaned up).` };
1005
+ }
1006
+ try {
1007
+ process.kill(pid, 'SIGTERM');
1008
+ try {
1009
+ const { unlinkSync } = await import('fs');
1010
+ unlinkSync(getPidPath(targetPath));
1011
+ }
1012
+ catch { /* ignore */ }
1013
+ return { success: true, message: `Watcher (PID ${pid}) stopped.` };
1014
+ }
1015
+ catch (err) {
1016
+ return { error: true, message: `Failed to stop PID ${pid}: ${String(err)}` };
1017
+ }
1018
+ },
1019
+ };
827
1020
  // ── Exports ───────────────────────────────────────────────────────────────────
828
1021
  export const graphifyTools = [
829
1022
  graphifyBuildTool,
@@ -835,6 +1028,8 @@ export const graphifyTools = [
835
1028
  graphifyStatsTool,
836
1029
  graphifySurprisesTool,
837
1030
  graphifyVisualizeTool,
1031
+ graphifyWatchTool,
1032
+ graphifyWatchStopTool,
838
1033
  ];
839
1034
  export default graphifyTools;
840
1035
  //# sourceMappingURL=graphify-tools.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monoes/cli",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "type": "module",
5
5
  "description": "Monobrain CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
6
6
  "main": "dist/src/index.js",