@highflame/overwatch 1.0.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.
Files changed (156) hide show
  1. package/README.md +337 -0
  2. package/bin/overwatch +12 -0
  3. package/dist/auth/cli-oauth.d.ts +13 -0
  4. package/dist/auth/cli-oauth.d.ts.map +1 -0
  5. package/dist/auth/html-utils.d.ts +20 -0
  6. package/dist/auth/html-utils.d.ts.map +1 -0
  7. package/dist/auth/index.d.ts +10 -0
  8. package/dist/auth/index.d.ts.map +1 -0
  9. package/dist/auth/oauth.d.ts +81 -0
  10. package/dist/auth/oauth.d.ts.map +1 -0
  11. package/dist/auth/pkce.d.ts +26 -0
  12. package/dist/auth/pkce.d.ts.map +1 -0
  13. package/dist/auth/token-store.d.ts +44 -0
  14. package/dist/auth/token-store.d.ts.map +1 -0
  15. package/dist/bin/overwatch +12 -0
  16. package/dist/cli.d.ts +6 -0
  17. package/dist/cli.d.ts.map +1 -0
  18. package/dist/cli.js +5449 -0
  19. package/dist/cli.js.map +7 -0
  20. package/dist/config/index.d.ts +5 -0
  21. package/dist/config/index.d.ts.map +1 -0
  22. package/dist/config/manager.d.ts +54 -0
  23. package/dist/config/manager.d.ts.map +1 -0
  24. package/dist/daemon.d.ts +11 -0
  25. package/dist/daemon.d.ts.map +1 -0
  26. package/dist/daemon.js +6004 -0
  27. package/dist/daemon.js.map +7 -0
  28. package/dist/data/ingestor.d.ts +31 -0
  29. package/dist/data/ingestor.d.ts.map +1 -0
  30. package/dist/data/processor.d.ts +96 -0
  31. package/dist/data/processor.d.ts.map +1 -0
  32. package/dist/data/reader.d.ts +24 -0
  33. package/dist/data/reader.d.ts.map +1 -0
  34. package/dist/data/recorder.d.ts +12 -0
  35. package/dist/data/recorder.d.ts.map +1 -0
  36. package/dist/engines/cedar.d.ts +41 -0
  37. package/dist/engines/cedar.d.ts.map +1 -0
  38. package/dist/engines/remote.d.ts +21 -0
  39. package/dist/engines/remote.d.ts.map +1 -0
  40. package/dist/engines/yara.d.ts +12 -0
  41. package/dist/engines/yara.d.ts.map +1 -0
  42. package/dist/handlers/dashboard-handler.d.ts +7 -0
  43. package/dist/handlers/dashboard-handler.d.ts.map +1 -0
  44. package/dist/handlers/hook-handler.d.ts +23 -0
  45. package/dist/handlers/hook-handler.d.ts.map +1 -0
  46. package/dist/handlers/oauth-handler.d.ts +12 -0
  47. package/dist/handlers/oauth-handler.d.ts.map +1 -0
  48. package/dist/handlers/scan-handler.d.ts +13 -0
  49. package/dist/handlers/scan-handler.d.ts.map +1 -0
  50. package/dist/handlers/utils.d.ts +11 -0
  51. package/dist/handlers/utils.d.ts.map +1 -0
  52. package/dist/hooks/claudecode/hooks.json.template +20 -0
  53. package/dist/hooks/cursor/hooks.json.template +74 -0
  54. package/dist/hooks/universal-hook.sh +36 -0
  55. package/dist/http/server.d.ts +38 -0
  56. package/dist/http/server.d.ts.map +1 -0
  57. package/dist/index.d.ts +8 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +5941 -0
  60. package/dist/index.js.map +7 -0
  61. package/dist/installer.d.ts +25 -0
  62. package/dist/installer.d.ts.map +1 -0
  63. package/dist/javelin/admin-client.d.ts +75 -0
  64. package/dist/javelin/admin-client.d.ts.map +1 -0
  65. package/dist/javelin/client.d.ts +30 -0
  66. package/dist/javelin/client.d.ts.map +1 -0
  67. package/dist/javelin/config-reader.d.ts +70 -0
  68. package/dist/javelin/config-reader.d.ts.map +1 -0
  69. package/dist/javelin/index.d.ts +5 -0
  70. package/dist/javelin/index.d.ts.map +1 -0
  71. package/dist/javelin/types.d.ts +81 -0
  72. package/dist/javelin/types.d.ts.map +1 -0
  73. package/dist/lib/policy-engine.d.ts +34 -0
  74. package/dist/lib/policy-engine.d.ts.map +1 -0
  75. package/dist/lib/policy-manager.d.ts +86 -0
  76. package/dist/lib/policy-manager.d.ts.map +1 -0
  77. package/dist/module.d.ts +52 -0
  78. package/dist/module.d.ts.map +1 -0
  79. package/dist/pipeline/context-mapper.d.ts +16 -0
  80. package/dist/pipeline/context-mapper.d.ts.map +1 -0
  81. package/dist/pipeline/extractors/claude-extractor.d.ts +48 -0
  82. package/dist/pipeline/extractors/claude-extractor.d.ts.map +1 -0
  83. package/dist/pipeline/extractors/cursor-extractor.d.ts +44 -0
  84. package/dist/pipeline/extractors/cursor-extractor.d.ts.map +1 -0
  85. package/dist/pipeline/extractors/github-copilot-extractor.d.ts +49 -0
  86. package/dist/pipeline/extractors/github-copilot-extractor.d.ts.map +1 -0
  87. package/dist/pipeline/extractors/index.d.ts +47 -0
  88. package/dist/pipeline/extractors/index.d.ts.map +1 -0
  89. package/dist/pipeline/extractors/registry.d.ts +38 -0
  90. package/dist/pipeline/extractors/registry.d.ts.map +1 -0
  91. package/dist/pipeline/hook-pipeline.d.ts +25 -0
  92. package/dist/pipeline/hook-pipeline.d.ts.map +1 -0
  93. package/dist/policy.cedar +783 -0
  94. package/dist/rules/pre/command_injection.yar +60 -0
  95. package/dist/rules/pre/cross_origin_escalation.yar +106 -0
  96. package/dist/rules/pre/mcp_config_risk.yar +35 -0
  97. package/dist/rules/pre/path_traversal.yar +50 -0
  98. package/dist/rules/pre/prompt_injection.yar +101 -0
  99. package/dist/rules/pre/secrets_leakage.yar +100 -0
  100. package/dist/rules/pre/sql_injection.yar +65 -0
  101. package/dist/scanner.d.ts +80 -0
  102. package/dist/scanner.d.ts.map +1 -0
  103. package/dist/service.d.ts +18 -0
  104. package/dist/service.d.ts.map +1 -0
  105. package/dist/services/interface.d.ts +11 -0
  106. package/dist/services/interface.d.ts.map +1 -0
  107. package/dist/services/launchd.d.ts +12 -0
  108. package/dist/services/launchd.d.ts.map +1 -0
  109. package/dist/services/systemd.d.ts +12 -0
  110. package/dist/services/systemd.d.ts.map +1 -0
  111. package/dist/services/windows.d.ts +7 -0
  112. package/dist/services/windows.d.ts.map +1 -0
  113. package/dist/skills/index.d.ts +7 -0
  114. package/dist/skills/index.d.ts.map +1 -0
  115. package/dist/skills/scanner.d.ts +44 -0
  116. package/dist/skills/scanner.d.ts.map +1 -0
  117. package/dist/skills/types.d.ts +29 -0
  118. package/dist/skills/types.d.ts.map +1 -0
  119. package/dist/types/config.d.ts +165 -0
  120. package/dist/types/config.d.ts.map +1 -0
  121. package/dist/types/events.d.ts +225 -0
  122. package/dist/types/events.d.ts.map +1 -0
  123. package/dist/types/index.d.ts +6 -0
  124. package/dist/types/index.d.ts.map +1 -0
  125. package/dist/types/remote-policy.d.ts +129 -0
  126. package/dist/types/remote-policy.d.ts.map +1 -0
  127. package/dist/types/requests.d.ts +45 -0
  128. package/dist/types/requests.d.ts.map +1 -0
  129. package/dist/types/responses.d.ts +60 -0
  130. package/dist/types/responses.d.ts.map +1 -0
  131. package/dist/ui/images/highflame-mono.png +0 -0
  132. package/dist/ui/views/dashboard.ejs +301 -0
  133. package/dist/ui/views/dashboard.js +785 -0
  134. package/dist/ui/views/partials/commands-table.ejs +54 -0
  135. package/dist/ui/views/partials/events-table.ejs +36 -0
  136. package/dist/ui/views/partials/filter-dropdown.ejs +12 -0
  137. package/dist/ui/views/partials/overview-charts.ejs +149 -0
  138. package/dist/ui/views/partials/scans-table.ejs +136 -0
  139. package/dist/ui/views/partials/sessions-table.ejs +50 -0
  140. package/dist/ui/views/partials/stats-grid.ejs +23 -0
  141. package/dist/ui/views/partials/threats-table.ejs +60 -0
  142. package/dist/utils/index.d.ts +3 -0
  143. package/dist/utils/index.d.ts.map +1 -0
  144. package/dist/utils/logger.d.ts +28 -0
  145. package/dist/utils/logger.d.ts.map +1 -0
  146. package/dist/utils/performance.d.ts +26 -0
  147. package/dist/utils/performance.d.ts.map +1 -0
  148. package/dist/utils/port-manager.d.ts +6 -0
  149. package/dist/utils/port-manager.d.ts.map +1 -0
  150. package/dist/yara/engine.d.ts +58 -0
  151. package/dist/yara/engine.d.ts.map +1 -0
  152. package/dist/yara/index.d.ts +5 -0
  153. package/dist/yara/index.d.ts.map +1 -0
  154. package/lib/platform-loader.js +210 -0
  155. package/package.json +63 -0
  156. package/scripts/postinstall.js +121 -0
@@ -0,0 +1,58 @@
1
+ /**
2
+ * YARA Engine - Native YARA pattern matching using @litko/yara-x
3
+ *
4
+ * Provides local YARA scanning for content validation without
5
+ * requiring external binaries.
6
+ */
7
+ /**
8
+ * Individual pattern match data from YARA
9
+ */
10
+ export interface YaraMatchData {
11
+ identifier: string;
12
+ data: string;
13
+ offset: number;
14
+ length: number;
15
+ }
16
+ export interface YaraMatch {
17
+ rule: string;
18
+ namespace?: string;
19
+ severity: string;
20
+ category: string;
21
+ description?: string;
22
+ metadata?: Record<string, unknown>;
23
+ tags?: string[];
24
+ matches?: YaraMatchData[];
25
+ }
26
+ /**
27
+ * YARA Engine - compiles and runs YARA rules
28
+ */
29
+ export declare class YaraEngine {
30
+ private rules;
31
+ private rulesLoaded;
32
+ private rulesCount;
33
+ /**
34
+ * Load and compile YARA rules from a directory
35
+ */
36
+ loadRules(rulesDir: string): Promise<void>;
37
+ /**
38
+ * Check if engine is ready for scanning
39
+ */
40
+ isReady(): boolean;
41
+ /**
42
+ * Get number of loaded rule files
43
+ */
44
+ getRulesCount(): number;
45
+ /**
46
+ * Scan content synchronously
47
+ */
48
+ scan(content: string): YaraMatch[];
49
+ /**
50
+ * Scan content asynchronously (for large content)
51
+ */
52
+ scanAsync(content: string): Promise<YaraMatch[]>;
53
+ /**
54
+ * Parse raw matches into structured format
55
+ */
56
+ private parseMatches;
57
+ }
58
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/yara/engine.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,UAAU,CAAK;IAEvB;;OAEG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuDhD;;OAEG;IACH,OAAO,IAAI,OAAO;IAIlB;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE;IAgBlC;;OAEG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAgBtD;;OAEG;IACH,OAAO,CAAC,YAAY;CA6BrB"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * YARA module exports
3
+ */
4
+ export { YaraEngine, type YaraMatch, type YaraMatchData } from "./engine";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/yara/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Platform Loader
3
+ *
4
+ * Runtime platform detection and binary/module loading for @highflame/overwatch.
5
+ * Follows the esbuild distribution pattern with platform-specific optionalDependencies.
6
+ *
7
+ * Loading order:
8
+ * 1. Try loading from @highflame/overwatch-{platform} package (npm install)
9
+ * 2. Fall back to local bin/
10
+ * 3. Fall back to ~/.overwatch/bin/ and system PATH
11
+ */
12
+
13
+ const path = require('path');
14
+ const fs = require('fs');
15
+ const os = require('os');
16
+
17
+ // Platform mapping: Node.js platform/arch -> package suffix and Rust target
18
+ const PLATFORM_MAP = {
19
+ 'darwin-arm64': {
20
+ package: '@highflame/overwatch-darwin-arm64',
21
+ rustTarget: 'aarch64-apple-darwin',
22
+ binaryName: 'ramparts-aarch64-apple-darwin',
23
+ },
24
+ 'darwin-x64': {
25
+ package: '@highflame/overwatch-darwin-x64',
26
+ rustTarget: 'x86_64-apple-darwin',
27
+ binaryName: 'ramparts-x86_64-apple-darwin',
28
+ },
29
+ 'linux-x64': {
30
+ package: '@highflame/overwatch-linux-x64',
31
+ rustTarget: 'x86_64-unknown-linux-gnu',
32
+ binaryName: 'ramparts-x86_64-unknown-linux-gnu',
33
+ },
34
+ 'linux-arm64': {
35
+ package: '@highflame/overwatch-linux-arm64',
36
+ rustTarget: 'aarch64-unknown-linux-gnu',
37
+ binaryName: 'ramparts-aarch64-unknown-linux-gnu',
38
+ },
39
+ };
40
+
41
+ /**
42
+ * Get current platform key (e.g., "darwin-arm64")
43
+ * @returns {string}
44
+ */
45
+ function getPlatformKey() {
46
+ return `${process.platform}-${process.arch}`;
47
+ }
48
+
49
+ /**
50
+ * Get platform configuration for current platform
51
+ * @returns {object|null}
52
+ */
53
+ function getPlatformConfig() {
54
+ const key = getPlatformKey();
55
+ return PLATFORM_MAP[key] || null;
56
+ }
57
+
58
+ /**
59
+ * Try to load the platform-specific package
60
+ * Uses indirect require to prevent bundler analysis (esbuild, webpack)
61
+ * @returns {object|null} The loaded platform package or null
62
+ */
63
+ function loadPlatformPackage() {
64
+ const config = getPlatformConfig();
65
+ if (!config) {
66
+ return null;
67
+ }
68
+
69
+ try {
70
+ // Use indirect require to prevent bundler from analyzing this
71
+ // This allows the optionalDependencies to work correctly
72
+ const dynamicRequire = typeof __non_webpack_require__ !== 'undefined'
73
+ ? __non_webpack_require__
74
+ : require;
75
+ return dynamicRequire(config.package);
76
+ } catch (error) {
77
+ // Package not installed - this is expected when using local dev setup
78
+ return null;
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Get the guardian package root directory
84
+ * Works from both dist/ and lib/ locations
85
+ * @returns {string}
86
+ */
87
+ function getPackageRoot() {
88
+ // This file is in lib/, so go up one level
89
+ // When bundled, __dirname will be dist/, so this still works
90
+ let currentDir = __dirname;
91
+
92
+ // Handle various directory structures
93
+ const baseName = path.basename(currentDir);
94
+ if (baseName === 'lib' || baseName === 'dist') {
95
+ return path.resolve(currentDir, '..');
96
+ }
97
+
98
+ // If we're deeply nested (e.g., dist/lib), go up appropriately
99
+ return path.resolve(currentDir, '..');
100
+ }
101
+
102
+ /**
103
+ * Get the path to the ramparts binary
104
+ *
105
+ * Search order:
106
+ * 1. Platform package (npm optionalDependency)
107
+ * 2. Local bin/ directory (dev mode)
108
+ * 3. ~/.overwatch/bin/
109
+ * 4. System PATH
110
+ *
111
+ * @returns {string|null} Path to binary or null if not found
112
+ */
113
+ function getRampartsBinaryPath() {
114
+ const config = getPlatformConfig();
115
+
116
+ // 1. Try platform package first
117
+ const platformPkg = loadPlatformPackage();
118
+ if (platformPkg && typeof platformPkg.getRampartsBinaryPath === 'function') {
119
+ const binaryPath = platformPkg.getRampartsBinaryPath();
120
+ if (binaryPath && fs.existsSync(binaryPath)) {
121
+ return binaryPath;
122
+ }
123
+ }
124
+
125
+ // 2. Try local bin/ directory (dev mode)
126
+ const packageRoot = getPackageRoot();
127
+ const localPaths = [];
128
+
129
+ if (config) {
130
+ // Platform-specific binary name
131
+ localPaths.push(path.join(packageRoot, 'bin', config.binaryName));
132
+ }
133
+
134
+ // Generic paths
135
+ localPaths.push(
136
+ path.join(packageRoot, 'bin', 'ramparts'),
137
+ path.join(packageRoot, 'dist', 'bin', 'ramparts'),
138
+ );
139
+
140
+ for (const p of localPaths) {
141
+ if (fs.existsSync(p)) {
142
+ return p;
143
+ }
144
+ }
145
+
146
+ // 3. Try ~/.overwatch/bin/
147
+ const overwatchPaths = [];
148
+ if (config) {
149
+ overwatchPaths.push(path.join(os.homedir(), '.overwatch', 'bin', config.binaryName));
150
+ }
151
+ overwatchPaths.push(path.join(os.homedir(), '.overwatch', 'bin', 'ramparts'));
152
+
153
+ for (const p of overwatchPaths) {
154
+ if (fs.existsSync(p)) {
155
+ return p;
156
+ }
157
+ }
158
+
159
+ // 4. Try PATH as last resort
160
+ try {
161
+ const { execSync } = require('child_process');
162
+ const which = execSync('which ramparts', { encoding: 'utf-8' }).trim();
163
+ if (which && fs.existsSync(which)) {
164
+ return which;
165
+ }
166
+ } catch {
167
+ // Not in PATH
168
+ }
169
+
170
+ return null;
171
+ }
172
+
173
+
174
+ /**
175
+ * Check if the current platform is supported
176
+ * @returns {boolean}
177
+ */
178
+ function isPlatformSupported() {
179
+ return getPlatformConfig() !== null;
180
+ }
181
+
182
+ /**
183
+ * Get a helpful error message when platform binaries are not found
184
+ * @returns {string}
185
+ */
186
+ function getPlatformNotFoundMessage() {
187
+ const key = getPlatformKey();
188
+ const config = getPlatformConfig();
189
+
190
+ if (!config) {
191
+ return `Unsupported platform: ${key}. Supported platforms: ${Object.keys(PLATFORM_MAP).join(', ')}`;
192
+ }
193
+
194
+ return `Platform binaries not found for ${key}.\n` +
195
+ `\n` +
196
+ `To fix this, either:\n` +
197
+ ` 1. Install the platform package: npm install ${config.package}\n` +
198
+ ` 2. Run the native deps build: ./scripts/build-native-deps.sh\n` +
199
+ ` 3. Place binaries in ~/.overwatch/bin/\n`;
200
+ }
201
+
202
+ module.exports = {
203
+ getPlatformKey,
204
+ getPlatformConfig,
205
+ loadPlatformPackage,
206
+ getRampartsBinaryPath,
207
+ isPlatformSupported,
208
+ getPlatformNotFoundMessage,
209
+ PLATFORM_MAP,
210
+ };
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@highflame/overwatch",
3
+ "version": "1.0.0",
4
+ "description": "Standalone security daemon for IDE-agnostic AI agent security",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "bin": {
8
+ "overwatch": "./bin/overwatch",
9
+ "overwatch-daemon": "./dist/daemon.js"
10
+ },
11
+ "scripts": {
12
+ "build": "node esbuild.config.mjs && tsc --emitDeclarationOnly",
13
+ "build:watch": "node esbuild.config.mjs --watch",
14
+ "typecheck": "tsc --noEmit",
15
+ "clean": "rm -rf dist",
16
+ "prebuild": "npm run clean",
17
+ "prepublishOnly": "npm run build",
18
+ "postinstall": "node scripts/postinstall.js || true"
19
+ },
20
+ "keywords": [
21
+ "security",
22
+ "validation",
23
+ "javelin",
24
+ "guardrails",
25
+ "daemon",
26
+ "ipc",
27
+ "ai-security",
28
+ "mcp",
29
+ "ide-security",
30
+ "cursor",
31
+ "claude-code"
32
+ ],
33
+ "author": "Highflame AI",
34
+ "engines": {
35
+ "node": ">=18.0.0"
36
+ },
37
+ "dependencies": {
38
+ "@highflame/policy": "^1.1.3",
39
+ "@litko/yara-x": "^0.4.0",
40
+ "commander": "^11.1.0",
41
+ "ejs": "^3.1.9",
42
+ "open": "^11.0.0"
43
+ },
44
+ "optionalDependencies": {
45
+ "@highflame/overwatch-darwin-arm64": "1.0.0",
46
+ "@highflame/overwatch-darwin-x64": "1.0.0",
47
+ "@highflame/overwatch-linux-arm64": "1.0.0",
48
+ "@highflame/overwatch-linux-x64": "1.0.0"
49
+ },
50
+ "devDependencies": {
51
+ "@types/ejs": "^3.1.5",
52
+ "@types/node": "^18.19.130",
53
+ "esbuild": "^0.20.2",
54
+ "typescript": "^5.9.3"
55
+ },
56
+ "files": [
57
+ "dist",
58
+ "lib",
59
+ "scripts",
60
+ "README.md",
61
+ "LICENSE"
62
+ ]
63
+ }
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Postinstall Script for @highflame/overwatch
5
+ *
6
+ * Automatically starts the daemon and installs Cursor hooks.
7
+ */
8
+
9
+ const { spawn } = require('child_process');
10
+ const path = require('path');
11
+
12
+ // CI environment detection
13
+ const CI_ENV_VARS = [
14
+ 'CI',
15
+ 'CONTINUOUS_INTEGRATION',
16
+ 'GITHUB_ACTIONS',
17
+ 'TRAVIS',
18
+ 'CIRCLECI',
19
+ 'JENKINS',
20
+ 'GITLAB_CI',
21
+ 'BUILDKITE',
22
+ 'DRONE',
23
+ 'TEAMCITY_VERSION',
24
+ ];
25
+
26
+ function isCI() {
27
+ return CI_ENV_VARS.some(envVar => process.env[envVar]);
28
+ }
29
+
30
+ function shouldSkip() {
31
+ // Skip in CI environments
32
+ if (isCI()) {
33
+ return true;
34
+ }
35
+
36
+ // Skip if GUARDIAN_SKIP_POSTINSTALL is set
37
+ if (process.env.GUARDIAN_SKIP_POSTINSTALL) {
38
+ return true;
39
+ }
40
+
41
+ // Skip during npm pack/publish
42
+ if (process.env.npm_command === 'pack' || process.env.npm_command === 'publish') {
43
+ return true;
44
+ }
45
+
46
+ // Skip if called from postinstall (prevent recursion)
47
+ if (process.env.GUARDIAN_POSTINSTALL) {
48
+ return true;
49
+ }
50
+
51
+ return false;
52
+ }
53
+
54
+ /**
55
+ * Run a command and return a promise
56
+ */
57
+ function runCommand(command, args, options = {}) {
58
+ return new Promise((resolve, reject) => {
59
+ const proc = spawn(command, args, {
60
+ stdio: options.silent ? 'ignore' : 'inherit',
61
+ env: {
62
+ ...process.env,
63
+ GUARDIAN_POSTINSTALL: '1', // Prevent recursion
64
+ },
65
+ ...options,
66
+ });
67
+
68
+ proc.on('close', (code) => {
69
+ if (code === 0) {
70
+ resolve();
71
+ } else {
72
+ reject(new Error(`Command failed with code ${code}`));
73
+ }
74
+ });
75
+
76
+ proc.on('error', reject);
77
+ });
78
+ }
79
+
80
+ async function main() {
81
+ if (shouldSkip()) {
82
+ return;
83
+ }
84
+
85
+ console.log('');
86
+ console.log('[overwatch] Setting up Overwatch Guardian...');
87
+ console.log('');
88
+
89
+ // Run CLI directly via Node.js
90
+ const cliPath = path.join(__dirname, '..', 'dist', 'cli.js');
91
+
92
+ try {
93
+ // Step 1: Start the daemon
94
+ console.log('[overwatch] Starting Guardian daemon...');
95
+ await runCommand(process.execPath, [cliPath, 'start']);
96
+ console.log('[overwatch] ✅ Daemon started');
97
+ } catch (error) {
98
+ console.log('[overwatch] ⚠️ Could not start daemon automatically');
99
+ console.log('[overwatch] Run manually: overwatch start');
100
+ }
101
+
102
+ try {
103
+ // Step 2: Install Cursor hooks
104
+ console.log('[overwatch] Installing Cursor hooks...');
105
+ await runCommand(process.execPath, [cliPath, 'install', 'cursor']);
106
+ console.log('[overwatch] ✅ Cursor hooks installed');
107
+ } catch (error) {
108
+ console.log('[overwatch] ⚠️ Could not install Cursor hooks automatically');
109
+ console.log('[overwatch] Run manually: overwatch install cursor');
110
+ }
111
+
112
+ console.log('');
113
+ console.log('[overwatch] Setup complete!');
114
+ console.log('[overwatch] Check status: overwatch status');
115
+ console.log('');
116
+ }
117
+
118
+ main().catch((error) => {
119
+ // Don't fail the install on postinstall errors
120
+ console.error('[overwatch] Postinstall warning:', error.message);
121
+ });