@two7722/sentinel-guard 1.1.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 (88) hide show
  1. package/dist/__tests__/rules-engine.test.d.ts +1 -0
  2. package/dist/__tests__/rules-engine.test.js +69 -0
  3. package/dist/__tests__/rules-engine.test.js.map +1 -0
  4. package/dist/__tests__/transport-encryption.test.d.ts +1 -0
  5. package/dist/__tests__/transport-encryption.test.js +95 -0
  6. package/dist/__tests__/transport-encryption.test.js.map +1 -0
  7. package/dist/api/client.d.ts +27 -0
  8. package/dist/api/client.js +91 -0
  9. package/dist/api/client.js.map +1 -0
  10. package/dist/cli/bootstrap.d.ts +12 -0
  11. package/dist/cli/bootstrap.js +132 -0
  12. package/dist/cli/bootstrap.js.map +1 -0
  13. package/dist/cli/index.d.ts +2 -0
  14. package/dist/cli/index.js +534 -0
  15. package/dist/cli/index.js.map +1 -0
  16. package/dist/crypto/keys.d.ts +40 -0
  17. package/dist/crypto/keys.js +125 -0
  18. package/dist/crypto/keys.js.map +1 -0
  19. package/dist/crypto/transport-encryption.d.ts +13 -0
  20. package/dist/crypto/transport-encryption.js +62 -0
  21. package/dist/crypto/transport-encryption.js.map +1 -0
  22. package/dist/install/setup.d.ts +2 -0
  23. package/dist/install/setup.js +80 -0
  24. package/dist/install/setup.js.map +1 -0
  25. package/dist/lib/budget.d.ts +14 -0
  26. package/dist/lib/budget.js +93 -0
  27. package/dist/lib/budget.js.map +1 -0
  28. package/dist/lib/claude-process.d.ts +16 -0
  29. package/dist/lib/claude-process.js +98 -0
  30. package/dist/lib/claude-process.js.map +1 -0
  31. package/dist/lib/daemon.d.ts +6 -0
  32. package/dist/lib/daemon.js +218 -0
  33. package/dist/lib/daemon.js.map +1 -0
  34. package/dist/lib/diff.d.ts +5 -0
  35. package/dist/lib/diff.js +85 -0
  36. package/dist/lib/diff.js.map +1 -0
  37. package/dist/lib/doctor.d.ts +1 -0
  38. package/dist/lib/doctor.js +108 -0
  39. package/dist/lib/doctor.js.map +1 -0
  40. package/dist/lib/history.d.ts +22 -0
  41. package/dist/lib/history.js +62 -0
  42. package/dist/lib/history.js.map +1 -0
  43. package/dist/lib/logger.d.ts +11 -0
  44. package/dist/lib/logger.js +62 -0
  45. package/dist/lib/logger.js.map +1 -0
  46. package/dist/lib/modes.d.ts +22 -0
  47. package/dist/lib/modes.js +58 -0
  48. package/dist/lib/modes.js.map +1 -0
  49. package/dist/lib/overrides.d.ts +13 -0
  50. package/dist/lib/overrides.js +74 -0
  51. package/dist/lib/overrides.js.map +1 -0
  52. package/dist/lib/session.d.ts +32 -0
  53. package/dist/lib/session.js +68 -0
  54. package/dist/lib/session.js.map +1 -0
  55. package/dist/lib/summarizer.d.ts +5 -0
  56. package/dist/lib/summarizer.js +46 -0
  57. package/dist/lib/summarizer.js.map +1 -0
  58. package/dist/lib/tunnel.d.ts +2 -0
  59. package/dist/lib/tunnel.js +48 -0
  60. package/dist/lib/tunnel.js.map +1 -0
  61. package/dist/relay/pending.d.ts +27 -0
  62. package/dist/relay/pending.js +65 -0
  63. package/dist/relay/pending.js.map +1 -0
  64. package/dist/rules/engine.d.ts +31 -0
  65. package/dist/rules/engine.js +203 -0
  66. package/dist/rules/engine.js.map +1 -0
  67. package/dist/server/http.d.ts +8 -0
  68. package/dist/server/http.js +359 -0
  69. package/dist/server/http.js.map +1 -0
  70. package/dist/socket/client.d.ts +16 -0
  71. package/dist/socket/client.js +81 -0
  72. package/dist/socket/client.js.map +1 -0
  73. package/dist/transport/cloudkit.d.ts +30 -0
  74. package/dist/transport/cloudkit.js +162 -0
  75. package/dist/transport/cloudkit.js.map +1 -0
  76. package/dist/transport/factory.d.ts +6 -0
  77. package/dist/transport/factory.js +20 -0
  78. package/dist/transport/factory.js.map +1 -0
  79. package/dist/transport/interface.d.ts +25 -0
  80. package/dist/transport/interface.js +13 -0
  81. package/dist/transport/interface.js.map +1 -0
  82. package/dist/transport/local.d.ts +46 -0
  83. package/dist/transport/local.js +320 -0
  84. package/dist/transport/local.js.map +1 -0
  85. package/dist/transport/remote.d.ts +17 -0
  86. package/dist/transport/remote.js +83 -0
  87. package/dist/transport/remote.js.map +1 -0
  88. package/package.json +44 -0
@@ -0,0 +1,320 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.LocalTransport = void 0;
7
+ const net_1 = __importDefault(require("net"));
8
+ const crypto_1 = require("crypto");
9
+ const child_process_1 = require("child_process");
10
+ const tweetnacl_1 = __importDefault(require("tweetnacl"));
11
+ const tweetnacl_util_1 = require("tweetnacl-util");
12
+ const bonjour_service_1 = require("bonjour-service");
13
+ const pending_1 = require("../relay/pending");
14
+ const logger_1 = require("../lib/logger");
15
+ const os_1 = require("os");
16
+ const transport_encryption_1 = require("../crypto/transport-encryption");
17
+ const claude_process_1 = require("../lib/claude-process");
18
+ const TCP_PORT = 7750;
19
+ const SERVICE_TYPE = 'sentinel';
20
+ const PROTOCOL = 'tcp';
21
+ /**
22
+ * Local transport — TCP server + Bonjour (mDNS) for LAN-direct mode.
23
+ *
24
+ * - Opens a TCP server on port 7750
25
+ * - Publishes _sentinel._tcp via Bonjour so iOS can auto-discover
26
+ * - iOS connects directly, same JSON message format as remote mode
27
+ * - Messages are newline-delimited JSON over raw TCP
28
+ */
29
+ class LocalTransport {
30
+ mode = 'local';
31
+ server = null;
32
+ bonjour = null;
33
+ iosSocket = null;
34
+ buffer = '';
35
+ static MAX_BUFFER_SIZE = 1_048_576; // 1 MB
36
+ decisionCb = null;
37
+ rulesUpdateCb = null;
38
+ userMessageCb = null;
39
+ activeClaudeProcess = null;
40
+ get isConnected() {
41
+ return this.iosSocket !== null && !this.iosSocket.destroyed;
42
+ }
43
+ async start() {
44
+ return new Promise((resolve, reject) => {
45
+ this.server = net_1.default.createServer((socket) => {
46
+ // Accept one iOS connection at a time
47
+ if (this.iosSocket && !this.iosSocket.destroyed) {
48
+ logger_1.log.warn('[local] New connection replacing old one');
49
+ this.iosSocket.destroy();
50
+ }
51
+ this.iosSocket = socket;
52
+ this.buffer = '';
53
+ logger_1.log.success(`[local] iOS connected from ${socket.remoteAddress}`);
54
+ // Send handshake with X25519 ephemeral public key for key agreement.
55
+ // The transport key is derived: HMAC-SHA256(sharedSecret, "sentinel-transport-v2").
56
+ // This replaces sending the raw symmetric key in plaintext.
57
+ const ephemeral = tweetnacl_1.default.box.keyPair();
58
+ const handshake = JSON.stringify({
59
+ event: 'handshake',
60
+ data: {
61
+ version: '3',
62
+ x25519PublicKey: (0, tweetnacl_util_1.encodeBase64)(ephemeral.publicKey),
63
+ // Still include ek for backward compatibility with older iOS versions
64
+ ek: (0, transport_encryption_1.getTransportKeyBase64)(),
65
+ },
66
+ }) + '\n';
67
+ socket.write(handshake);
68
+ // Store ephemeral secret key for this connection to derive shared key
69
+ // when iOS responds with its public key
70
+ socket._ephemeralSecretKey = ephemeral.secretKey;
71
+ setTimeout(() => {
72
+ this.send('workspace_info', {
73
+ cwd: process.cwd(),
74
+ hostname: require('os').hostname(),
75
+ });
76
+ }, 500);
77
+ socket.on('data', (chunk) => {
78
+ this.buffer += chunk.toString();
79
+ if (this.buffer.length > LocalTransport.MAX_BUFFER_SIZE) {
80
+ logger_1.log.error('[local] Buffer exceeded 1MB, dropping connection');
81
+ this.buffer = '';
82
+ socket.destroy();
83
+ return;
84
+ }
85
+ this.processBuffer();
86
+ });
87
+ socket.on('close', () => {
88
+ logger_1.log.warn('[local] iOS disconnected');
89
+ // Clear ephemeral key material
90
+ if (socket._ephemeralSecretKey) {
91
+ socket._ephemeralSecretKey = null;
92
+ }
93
+ if (this.iosSocket === socket)
94
+ this.iosSocket = null;
95
+ });
96
+ socket.on('error', (err) => {
97
+ logger_1.log.error(`[local] Socket error: ${err.message}`);
98
+ if (this.iosSocket === socket)
99
+ this.iosSocket = null;
100
+ });
101
+ });
102
+ this.server.listen(TCP_PORT, () => {
103
+ logger_1.log.success(`[local] TCP server listening on port ${TCP_PORT}`);
104
+ this.publishBonjour();
105
+ resolve();
106
+ });
107
+ this.server.on('error', (err) => {
108
+ logger_1.log.error(`[local] Server error: ${err.message}`);
109
+ reject(err);
110
+ });
111
+ });
112
+ }
113
+ publishBonjour() {
114
+ this.bonjour = new bonjour_service_1.Bonjour();
115
+ this.bonjour.publish({
116
+ name: `Sentinel-${process.env.USER ?? 'mac'}`,
117
+ type: SERVICE_TYPE,
118
+ protocol: PROTOCOL,
119
+ port: TCP_PORT,
120
+ txt: { version: '2', ek: (0, transport_encryption_1.getTransportKeyBase64)() }, // ek = encryption key
121
+ });
122
+ logger_1.log.success(`[local] Bonjour: publishing _${SERVICE_TYPE}._${PROTOCOL}`);
123
+ const ip = getLocalIP();
124
+ if (ip)
125
+ logger_1.log.info(`[local] LAN address: ${ip}:${TCP_PORT}`);
126
+ }
127
+ /** Process newline-delimited messages from buffer (encrypted or plain) */
128
+ processBuffer() {
129
+ const lines = this.buffer.split('\n');
130
+ this.buffer = lines.pop() ?? '';
131
+ const key = (0, transport_encryption_1.getTransportKey)();
132
+ for (const line of lines) {
133
+ if (!line.trim())
134
+ continue;
135
+ try {
136
+ // Try decrypt first (encrypted messages are base64, not JSON)
137
+ let json;
138
+ if (line.startsWith('{')) {
139
+ json = line; // Plain JSON fallback (handshake)
140
+ }
141
+ else {
142
+ const decrypted = (0, transport_encryption_1.decryptMessage)(line, key);
143
+ if (!decrypted) {
144
+ logger_1.log.debug('[local] Decrypt failed');
145
+ continue;
146
+ }
147
+ json = decrypted;
148
+ }
149
+ const msg = JSON.parse(json);
150
+ this.handleMessage(msg);
151
+ }
152
+ catch {
153
+ logger_1.log.debug(`[local] Parse error: ${line.slice(0, 40)}`);
154
+ }
155
+ }
156
+ }
157
+ handleMessage(msg) {
158
+ if (msg.event === 'decision') {
159
+ const { requestId, action } = msg.data;
160
+ logger_1.log.info(`[local] Decision: ${requestId} → ${action}`);
161
+ pending_1.pending.resolve(requestId, action);
162
+ this.decisionCb?.(requestId, action);
163
+ }
164
+ else if (msg.event === 'rules_update') {
165
+ const rules = msg.data?.rules;
166
+ if (rules) {
167
+ logger_1.log.info(`[local] Rules update from iOS: ${rules.length} custom rules`);
168
+ this.rulesUpdateCb?.(rules);
169
+ }
170
+ }
171
+ else if (msg.event === 'user_message') {
172
+ const text = msg.data?.text;
173
+ if (text) {
174
+ logger_1.log.info(`[local] Message from iOS: ${text}`);
175
+ this.userMessageCb?.(text);
176
+ this.runClaude(text);
177
+ }
178
+ }
179
+ else if (msg.event === 'interrupt') {
180
+ logger_1.log.info('[local] Interrupt from iOS');
181
+ (0, claude_process_1.interruptClaude)();
182
+ }
183
+ else if (msg.event === 'heartbeat_ack') {
184
+ // iOS responded to heartbeat
185
+ }
186
+ }
187
+ /** Send a notification to iOS */
188
+ sendNotification(title, message) {
189
+ this.send('notification', { title, message });
190
+ }
191
+ sendEvent(data) {
192
+ const type = data.type;
193
+ if (type === 'terminal') {
194
+ this.send('terminal', data);
195
+ }
196
+ else {
197
+ this.send('activity', data);
198
+ }
199
+ }
200
+ runClaude(message) {
201
+ this.send('terminal', { type: 'terminal', text: `> ${message}` });
202
+ this.sendEvent({ type: 'claude_status', status: 'thinking', message });
203
+ // Kill any previous Claude process before starting a new one
204
+ if (this.activeClaudeProcess && !this.activeClaudeProcess.killed) {
205
+ this.activeClaudeProcess.kill('SIGTERM');
206
+ }
207
+ const child = (0, child_process_1.spawn)('claude', ['--continue', '--print', message], {
208
+ stdio: ['ignore', 'pipe', 'pipe'],
209
+ env: { ...process.env },
210
+ });
211
+ this.activeClaudeProcess = child;
212
+ let output = '';
213
+ let lineBuffer = '';
214
+ const streamLines = (chunk) => {
215
+ lineBuffer += chunk.toString();
216
+ const lines = lineBuffer.split('\n');
217
+ lineBuffer = lines.pop() ?? '';
218
+ for (const line of lines) {
219
+ if (line.trim()) {
220
+ this.send('terminal', { type: 'terminal', text: line });
221
+ }
222
+ }
223
+ output += chunk.toString();
224
+ };
225
+ child.stdout?.on('data', streamLines);
226
+ child.stderr?.on('data', streamLines);
227
+ child.on('close', (code) => {
228
+ if (lineBuffer.trim()) {
229
+ this.send('terminal', { type: 'terminal', text: lineBuffer });
230
+ }
231
+ const trimmed = output.trim();
232
+ this.sendEvent({
233
+ type: 'claude_response',
234
+ message: trimmed || (code === 0 ? '完成(无输出)' : '无活跃会话'),
235
+ exitCode: code,
236
+ });
237
+ logger_1.log.success(`[local] Claude responded (${trimmed.length} chars, exit ${code})`);
238
+ });
239
+ child.on('error', (err) => {
240
+ logger_1.log.error(`[local] Claude error: ${err.message}`);
241
+ this.sendEvent({
242
+ type: 'claude_response',
243
+ message: `错误: ${err.message}`,
244
+ exitCode: -1,
245
+ });
246
+ });
247
+ }
248
+ /** Send a JSON message to connected iOS */
249
+ send(event, data) {
250
+ if (!this.iosSocket || this.iosSocket.destroyed)
251
+ return;
252
+ const msg = JSON.stringify({ event, data }) + '\n';
253
+ this.iosSocket.write(msg);
254
+ }
255
+ async sendApprovalRequest(payload) {
256
+ if (!this.isConnected)
257
+ throw new Error('iOS not connected');
258
+ const requestId = (0, crypto_1.randomBytes)(12).toString('hex');
259
+ // Map server risk levels to iOS RiskLevel enum values
260
+ const riskMap = {
261
+ low: 'require_confirm',
262
+ medium: 'require_confirm',
263
+ high: 'require_faceid',
264
+ };
265
+ this.send('approval_request', {
266
+ id: requestId,
267
+ toolName: payload.toolName,
268
+ toolInput: payload.toolInput,
269
+ riskLevel: riskMap[payload.riskLevel] ?? 'require_confirm',
270
+ macDeviceId: 'local',
271
+ timestamp: new Date().toISOString(),
272
+ timeoutAt: new Date(Date.now() + 120_000).toISOString(),
273
+ ...(payload.diff ? { diff: payload.diff } : {}),
274
+ ...(payload.contextSummary ? { contextSummary: payload.contextSummary } : {}),
275
+ });
276
+ return requestId;
277
+ }
278
+ onDecision(cb) {
279
+ this.decisionCb = cb;
280
+ }
281
+ /** Register callback for rules updates from iOS */
282
+ onRulesUpdate(cb) {
283
+ this.rulesUpdateCb = cb;
284
+ }
285
+ /** Register callback for user messages from iOS */
286
+ onUserMessage(cb) {
287
+ this.userMessageCb = cb;
288
+ }
289
+ stop() {
290
+ if (this.activeClaudeProcess && !this.activeClaudeProcess.killed) {
291
+ this.activeClaudeProcess.kill('SIGTERM');
292
+ this.activeClaudeProcess = null;
293
+ }
294
+ this.iosSocket?.destroy();
295
+ this.iosSocket = null;
296
+ this.server?.close();
297
+ this.server = null;
298
+ if (this.bonjour) {
299
+ this.bonjour.unpublishAll();
300
+ this.bonjour.destroy();
301
+ this.bonjour = null;
302
+ }
303
+ }
304
+ /** Get info for pairing display */
305
+ getConnectionInfo() {
306
+ return { ip: getLocalIP() ?? '0.0.0.0', port: TCP_PORT };
307
+ }
308
+ }
309
+ exports.LocalTransport = LocalTransport;
310
+ function getLocalIP() {
311
+ const nets = (0, os_1.networkInterfaces)();
312
+ for (const name of Object.keys(nets)) {
313
+ for (const net of nets[name] ?? []) {
314
+ if (net.family === 'IPv4' && !net.internal)
315
+ return net.address;
316
+ }
317
+ }
318
+ return null;
319
+ }
320
+ //# sourceMappingURL=local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/transport/local.ts"],"names":[],"mappings":";;;;;;AAAA,8CAAsB;AACtB,mCAAqC;AACrC,iDAAiD;AACjD,0DAA6B;AAC7B,mDAA8C;AAC9C,qDAA0C;AAE1C,8CAA2C;AAC3C,0CAAoC;AACpC,2BAAuC;AAEvC,yEAAwH;AACxH,0DAAwD;AAExD,MAAM,QAAQ,GAAG,IAAI,CAAC;AACtB,MAAM,YAAY,GAAG,UAAU,CAAC;AAChC,MAAM,QAAQ,GAAG,KAAK,CAAC;AAEvB;;;;;;;GAOG;AACH,MAAa,cAAc;IAChB,IAAI,GAAG,OAAgB,CAAC;IAEzB,MAAM,GAAsB,IAAI,CAAC;IACjC,OAAO,GAAmB,IAAI,CAAC;IAC/B,SAAS,GAAsB,IAAI,CAAC;IACpC,MAAM,GAAG,EAAE,CAAC;IACZ,MAAM,CAAU,eAAe,GAAG,SAAS,CAAC,CAAC,OAAO;IACpD,UAAU,GAA6E,IAAI,CAAC;IAC5F,aAAa,GAAqC,IAAI,CAAC;IACvD,aAAa,GAAoC,IAAI,CAAC;IACtD,mBAAmB,GAAgD,IAAI,CAAC;IAEhF,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,SAAS,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;IAC9D,CAAC;IAED,KAAK,CAAC,KAAK;QACT,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,MAAM,GAAG,aAAG,CAAC,YAAY,CAAC,CAAC,MAAM,EAAE,EAAE;gBACxC,sCAAsC;gBACtC,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;oBAChD,YAAG,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;oBACrD,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;gBAC3B,CAAC;gBAED,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC;gBACxB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;gBACjB,YAAG,CAAC,OAAO,CAAC,8BAA8B,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;gBAElE,qEAAqE;gBACrE,oFAAoF;gBACpF,4DAA4D;gBAC5D,MAAM,SAAS,GAAG,mBAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;gBACrC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;oBAC/B,KAAK,EAAE,WAAW;oBAClB,IAAI,EAAE;wBACJ,OAAO,EAAE,GAAG;wBACZ,eAAe,EAAE,IAAA,6BAAY,EAAC,SAAS,CAAC,SAAS,CAAC;wBAClD,sEAAsE;wBACtE,EAAE,EAAE,IAAA,4CAAqB,GAAE;qBAC5B;iBACF,CAAC,GAAG,IAAI,CAAC;gBACV,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;gBAExB,sEAAsE;gBACtE,wCAAwC;gBACvC,MAAc,CAAC,mBAAmB,GAAG,SAAS,CAAC,SAAS,CAAC;gBAE1D,UAAU,CAAC,GAAG,EAAE;oBACd,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE;wBAC1B,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;wBAClB,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;qBACnC,CAAC,CAAC;gBACL,CAAC,EAAE,GAAG,CAAC,CAAC;gBAER,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;oBAC1B,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;oBAChC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,cAAc,CAAC,eAAe,EAAE,CAAC;wBACxD,YAAG,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;wBAC9D,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;wBACjB,MAAM,CAAC,OAAO,EAAE,CAAC;wBACjB,OAAO;oBACT,CAAC;oBACD,IAAI,CAAC,aAAa,EAAE,CAAC;gBACvB,CAAC,CAAC,CAAC;gBAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;oBACtB,YAAG,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;oBACrC,+BAA+B;oBAC/B,IAAK,MAAc,CAAC,mBAAmB,EAAE,CAAC;wBACvC,MAAc,CAAC,mBAAmB,GAAG,IAAI,CAAC;oBAC7C,CAAC;oBACD,IAAI,IAAI,CAAC,SAAS,KAAK,MAAM;wBAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;gBACvD,CAAC,CAAC,CAAC;gBAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;oBACzB,YAAG,CAAC,KAAK,CAAC,yBAAyB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;oBAClD,IAAI,IAAI,CAAC,SAAS,KAAK,MAAM;wBAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;gBACvD,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,EAAE;gBAChC,YAAG,CAAC,OAAO,CAAC,wCAAwC,QAAQ,EAAE,CAAC,CAAC;gBAChE,IAAI,CAAC,cAAc,EAAE,CAAC;gBACtB,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC9B,YAAG,CAAC,KAAK,CAAC,yBAAyB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;gBAClD,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,cAAc;QACpB,IAAI,CAAC,OAAO,GAAG,IAAI,yBAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;YACnB,IAAI,EAAE,YAAY,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,KAAK,EAAE;YAC7C,IAAI,EAAE,YAAY;YAClB,QAAQ,EAAE,QAAQ;YAClB,IAAI,EAAE,QAAQ;YACd,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,IAAA,4CAAqB,GAAE,EAAE,EAAE,sBAAsB;SAC3E,CAAC,CAAC;QACH,YAAG,CAAC,OAAO,CAAC,gCAAgC,YAAY,KAAK,QAAQ,EAAE,CAAC,CAAC;QAEzE,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC;QACxB,IAAI,EAAE;YAAE,YAAG,CAAC,IAAI,CAAC,wBAAwB,EAAE,IAAI,QAAQ,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,0EAA0E;IAClE,aAAa;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;QAChC,MAAM,GAAG,GAAG,IAAA,sCAAe,GAAE,CAAC;QAE9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;gBAAE,SAAS;YAC3B,IAAI,CAAC;gBACH,8DAA8D;gBAC9D,IAAI,IAAY,CAAC;gBACjB,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACzB,IAAI,GAAG,IAAI,CAAC,CAAC,kCAAkC;gBACjD,CAAC;qBAAM,CAAC;oBACN,MAAM,SAAS,GAAG,IAAA,qCAAc,EAAC,IAAI,EAAE,GAAG,CAAC,CAAC;oBAC5C,IAAI,CAAC,SAAS,EAAE,CAAC;wBAAC,YAAG,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;wBAAC,SAAS;oBAAC,CAAC;oBAClE,IAAI,GAAG,SAAS,CAAC;gBACnB,CAAC;gBACD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC7B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;YAC1B,CAAC;YAAC,MAAM,CAAC;gBACP,YAAG,CAAC,KAAK,CAAC,wBAAwB,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;IACH,CAAC;IAEO,aAAa,CAAC,GAAiC;QACrD,IAAI,GAAG,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;YAC7B,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC;YACvC,YAAG,CAAC,IAAI,CAAC,qBAAqB,SAAS,MAAM,MAAM,EAAE,CAAC,CAAC;YACvD,iBAAO,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YACnC,IAAI,CAAC,UAAU,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACvC,CAAC;aAAM,IAAI,GAAG,CAAC,KAAK,KAAK,cAAc,EAAE,CAAC;YACxC,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,KAA2B,CAAC;YACpD,IAAI,KAAK,EAAE,CAAC;gBACV,YAAG,CAAC,IAAI,CAAC,kCAAkC,KAAK,CAAC,MAAM,eAAe,CAAC,CAAC;gBACxE,IAAI,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;aAAM,IAAI,GAAG,CAAC,KAAK,KAAK,cAAc,EAAE,CAAC;YACxC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,IAA0B,CAAC;YAClD,IAAI,IAAI,EAAE,CAAC;gBACT,YAAG,CAAC,IAAI,CAAC,6BAA6B,IAAI,EAAE,CAAC,CAAC;gBAC9C,IAAI,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,CAAC;gBAC3B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;aAAM,IAAI,GAAG,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;YACrC,YAAG,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;YACvC,IAAA,gCAAe,GAAE,CAAC;QACpB,CAAC;aAAM,IAAI,GAAG,CAAC,KAAK,KAAK,eAAe,EAAE,CAAC;YACzC,6BAA6B;QAC/B,CAAC;IACH,CAAC;IAED,iCAAiC;IACjC,gBAAgB,CAAC,KAAa,EAAE,OAAe;QAC7C,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,SAAS,CAAC,IAA6B;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,IAA0B,CAAC;QAC7C,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAEO,SAAS,CAAC,OAAe;QAC/B,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE,EAAE,CAAC,CAAC;QAClE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;QAEvE,6DAA6D;QAC7D,IAAI,IAAI,CAAC,mBAAmB,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,CAAC;YACjE,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC3C,CAAC;QAED,MAAM,KAAK,GAAG,IAAA,qBAAO,EAAC,QAAQ,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE;YAClE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;YACjC,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;SACxB,CAAC,CAAC;QACH,IAAI,CAAC,mBAAmB,GAAG,KAAK,CAAC;QAEjC,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,UAAU,GAAG,EAAE,CAAC;QAEpB,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,EAAE;YACpC,UAAU,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACrC,UAAU,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;YAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;oBAChB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC1D,CAAC;YACH,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC7B,CAAC,CAAC;QAEF,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QACtC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QAEtC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,IAAI,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC;gBACtB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;YAChE,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;YAC9B,IAAI,CAAC,SAAS,CAAC;gBACb,IAAI,EAAE,iBAAiB;gBACvB,OAAO,EAAE,OAAO,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;gBACtD,QAAQ,EAAE,IAAI;aACf,CAAC,CAAC;YACH,YAAG,CAAC,OAAO,CAAC,6BAA6B,OAAO,CAAC,MAAM,gBAAgB,IAAI,GAAG,CAAC,CAAC;QAClF,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,YAAG,CAAC,KAAK,CAAC,yBAAyB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YAClD,IAAI,CAAC,SAAS,CAAC;gBACb,IAAI,EAAE,iBAAiB;gBACvB,OAAO,EAAE,OAAO,GAAG,CAAC,OAAO,EAAE;gBAC7B,QAAQ,EAAE,CAAC,CAAC;aACb,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,2CAA2C;IACnC,IAAI,CAAC,KAAa,EAAE,IAAS;QACnC,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS;YAAE,OAAO;QACxD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;QACnD,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,OAAwB;QAChD,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAE5D,MAAM,SAAS,GAAG,IAAA,oBAAW,EAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClD,sDAAsD;QACtD,MAAM,OAAO,GAA2B;YACtC,GAAG,EAAE,iBAAiB;YACtB,MAAM,EAAE,iBAAiB;YACzB,IAAI,EAAE,gBAAgB;SACvB,CAAC;QAEF,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE;YAC5B,EAAE,EAAE,SAAS;YACb,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,iBAAiB;YAC1D,WAAW,EAAE,OAAO;YACpB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC,WAAW,EAAE;YACvD,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/C,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9E,CAAC,CAAC;QAEH,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,UAAU,CAAC,EAAmE;QAC5E,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;IACvB,CAAC;IAED,mDAAmD;IACnD,aAAa,CAAC,EAA2B;QACvC,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;IAC1B,CAAC;IAED,mDAAmD;IACnD,aAAa,CAAC,EAA0B;QACtC,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;IAC1B,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,mBAAmB,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,CAAC;YACjE,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACzC,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC;QAClC,CAAC;QACD,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC;QAC1B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;YAC5B,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACvB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,CAAC;IACH,CAAC;IAED,mCAAmC;IACnC,iBAAiB;QACf,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC3D,CAAC;;AA5SH,wCA6SC;AAED,SAAS,UAAU;IACjB,MAAM,IAAI,GAAG,IAAA,sBAAiB,GAAE,CAAC;IACjC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YACnC,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ;gBAAE,OAAO,GAAG,CAAC,OAAO,CAAC;QACjE,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { Transport, ApprovalPayload } from './interface';
2
+ /**
3
+ * Remote transport — wraps existing Socket.IO client for server-relay mode.
4
+ */
5
+ export declare class RemoteTransport implements Transport {
6
+ private serverURL;
7
+ private token;
8
+ readonly mode: "server";
9
+ private socket;
10
+ private decisionCb;
11
+ constructor(serverURL: string, token: string);
12
+ get isConnected(): boolean;
13
+ start(): Promise<void>;
14
+ sendApprovalRequest(payload: ApprovalPayload): Promise<string>;
15
+ onDecision(cb: (id: string, action: 'allowed' | 'blocked' | 'timeout') => void): void;
16
+ stop(): void;
17
+ }
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RemoteTransport = void 0;
4
+ const socket_io_client_1 = require("socket.io-client");
5
+ const pending_1 = require("../relay/pending");
6
+ const logger_1 = require("../lib/logger");
7
+ /**
8
+ * Remote transport — wraps existing Socket.IO client for server-relay mode.
9
+ */
10
+ class RemoteTransport {
11
+ serverURL;
12
+ token;
13
+ mode = 'server';
14
+ socket = null;
15
+ decisionCb = null;
16
+ constructor(serverURL, token) {
17
+ this.serverURL = serverURL;
18
+ this.token = token;
19
+ }
20
+ get isConnected() {
21
+ return this.socket?.connected ?? false;
22
+ }
23
+ async start() {
24
+ // Clean up previous socket to prevent duplicate listeners
25
+ if (this.socket) {
26
+ this.socket.removeAllListeners();
27
+ this.socket.disconnect();
28
+ this.socket = null;
29
+ }
30
+ this.socket = (0, socket_io_client_1.io)(this.serverURL, {
31
+ auth: { token: this.token },
32
+ transports: ['websocket', 'polling'],
33
+ reconnection: true,
34
+ reconnectionDelay: 1000,
35
+ reconnectionDelayMax: 30000,
36
+ reconnectionAttempts: 10,
37
+ });
38
+ this.socket.on('connect', () => {
39
+ logger_1.log.success(`[remote] Connected to ${this.serverURL}`);
40
+ });
41
+ this.socket.on('disconnect', (reason) => {
42
+ logger_1.log.warn(`[remote] Disconnected: ${reason}`);
43
+ });
44
+ this.socket.on('connect_error', (err) => {
45
+ logger_1.log.error(`[remote] Connection error: ${err.message}`);
46
+ });
47
+ this.socket.on('decision', (data) => {
48
+ logger_1.log.info(`[remote] Decision: ${data.requestId} → ${data.action}`);
49
+ pending_1.pending.resolve(data.requestId, data.action);
50
+ this.decisionCb?.(data.requestId, data.action);
51
+ });
52
+ this.socket.on('heartbeat', () => {
53
+ this.socket?.emit('heartbeat');
54
+ });
55
+ // Wait for initial connection
56
+ await new Promise((resolve) => {
57
+ const timeout = setTimeout(() => resolve(), 5000);
58
+ this.socket.once('connect', () => { clearTimeout(timeout); resolve(); });
59
+ });
60
+ }
61
+ async sendApprovalRequest(payload) {
62
+ return new Promise((resolve, reject) => {
63
+ if (!this.socket?.connected)
64
+ return reject(new Error('Not connected'));
65
+ this.socket.emit('approval_request', payload, (res) => {
66
+ if (res.success && res.requestId)
67
+ resolve(res.requestId);
68
+ else
69
+ reject(new Error(res.error ?? 'Failed'));
70
+ });
71
+ });
72
+ }
73
+ onDecision(cb) {
74
+ this.decisionCb = cb;
75
+ }
76
+ stop() {
77
+ this.socket?.removeAllListeners();
78
+ this.socket?.disconnect();
79
+ this.socket = null;
80
+ }
81
+ }
82
+ exports.RemoteTransport = RemoteTransport;
83
+ //# sourceMappingURL=remote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/transport/remote.ts"],"names":[],"mappings":";;;AAAA,uDAA8C;AAG9C,8CAA2C;AAC3C,0CAAoC;AAEpC;;GAEG;AACH,MAAa,eAAe;IAOhB;IACA;IAPD,IAAI,GAAG,QAAiB,CAAC;IAE1B,MAAM,GAAkB,IAAI,CAAC;IAC7B,UAAU,GAA6E,IAAI,CAAC;IAEpG,YACU,SAAiB,EACjB,KAAa;QADb,cAAS,GAAT,SAAS,CAAQ;QACjB,UAAK,GAAL,KAAK,CAAQ;IACpB,CAAC;IAEJ,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,MAAM,EAAE,SAAS,IAAI,KAAK,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,KAAK;QACT,0DAA0D;QAC1D,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,CAAC;YACjC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;YACzB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACrB,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,IAAA,qBAAE,EAAC,IAAI,CAAC,SAAS,EAAE;YAC/B,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE;YAC3B,UAAU,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC;YACpC,YAAY,EAAE,IAAI;YAClB,iBAAiB,EAAE,IAAI;YACvB,oBAAoB,EAAE,KAAK;YAC3B,oBAAoB,EAAE,EAAE;SACzB,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;YAC7B,YAAG,CAAC,OAAO,CAAC,yBAAyB,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE;YACtC,YAAG,CAAC,IAAI,CAAC,0BAA0B,MAAM,EAAE,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,GAAG,EAAE,EAAE;YACtC,YAAG,CAAC,KAAK,CAAC,8BAA8B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,IAA2C,EAAE,EAAE;YACzE,YAAG,CAAC,IAAI,CAAC,sBAAsB,IAAI,CAAC,SAAS,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YAClE,iBAAO,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAA2C,CAAC,CAAC;YAClF,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAa,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE;YAC/B,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,8BAA8B;QAC9B,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAClC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,CAAC;YAClD,IAAI,CAAC,MAAO,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5E,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,OAAwB;QAChD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS;gBAAE,OAAO,MAAM,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;YACvE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,OAAO,EAAE,CAAC,GAA6D,EAAE,EAAE;gBAC9G,IAAI,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,SAAS;oBAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;;oBACpD,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,QAAQ,CAAC,CAAC,CAAC;YAChD,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,UAAU,CAAC,EAAmE;QAC5E,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;IACvB,CAAC;IAED,IAAI;QACF,IAAI,CAAC,MAAM,EAAE,kBAAkB,EAAE,CAAC;QAClC,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC;QAC1B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IACrB,CAAC;CACF;AAhFD,0CAgFC"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@two7722/sentinel-guard",
3
+ "version": "1.1.0",
4
+ "description": "Sentinel CLI — Claude Code 本地 Hook 服务 + 移动端审批",
5
+ "main": "dist/cli/index.js",
6
+ "bin": {
7
+ "sentinel": "dist/cli/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "dev": "tsx src/cli/index.ts",
15
+ "start": "node dist/cli/index.js",
16
+ "clean": "rm -rf dist node_modules",
17
+ "test": "npx tsx --test src/__tests__/*.test.ts",
18
+ "lint": "tsc --noEmit",
19
+ "prepublish": "npm run build"
20
+ },
21
+ "dependencies": {
22
+ "bonjour-service": "^1.2.1",
23
+ "chalk": "^5.3.0",
24
+ "commander": "^12.0.0",
25
+ "express": "^4.18.2",
26
+ "qrcode-terminal": "^0.12.0",
27
+ "socket.io-client": "^4.7.4",
28
+ "strip-ansi": "^6.0.1",
29
+ "tweetnacl": "^1.0.3",
30
+ "tweetnacl-util": "^0.15.1",
31
+ "unicode-animations": "^1.0.3",
32
+ "zod": "^3.22.4"
33
+ },
34
+ "devDependencies": {
35
+ "@types/express": "^4.17.21",
36
+ "@types/node": "^20.11.0",
37
+ "@types/qrcode-terminal": "^0.12.2",
38
+ "tsx": "^4.7.0",
39
+ "typescript": "^5.3.3"
40
+ },
41
+ "engines": {
42
+ "node": ">=20.0.0"
43
+ }
44
+ }