@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.
- package/dist/__tests__/rules-engine.test.d.ts +1 -0
- package/dist/__tests__/rules-engine.test.js +69 -0
- package/dist/__tests__/rules-engine.test.js.map +1 -0
- package/dist/__tests__/transport-encryption.test.d.ts +1 -0
- package/dist/__tests__/transport-encryption.test.js +95 -0
- package/dist/__tests__/transport-encryption.test.js.map +1 -0
- package/dist/api/client.d.ts +27 -0
- package/dist/api/client.js +91 -0
- package/dist/api/client.js.map +1 -0
- package/dist/cli/bootstrap.d.ts +12 -0
- package/dist/cli/bootstrap.js +132 -0
- package/dist/cli/bootstrap.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +534 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/crypto/keys.d.ts +40 -0
- package/dist/crypto/keys.js +125 -0
- package/dist/crypto/keys.js.map +1 -0
- package/dist/crypto/transport-encryption.d.ts +13 -0
- package/dist/crypto/transport-encryption.js +62 -0
- package/dist/crypto/transport-encryption.js.map +1 -0
- package/dist/install/setup.d.ts +2 -0
- package/dist/install/setup.js +80 -0
- package/dist/install/setup.js.map +1 -0
- package/dist/lib/budget.d.ts +14 -0
- package/dist/lib/budget.js +93 -0
- package/dist/lib/budget.js.map +1 -0
- package/dist/lib/claude-process.d.ts +16 -0
- package/dist/lib/claude-process.js +98 -0
- package/dist/lib/claude-process.js.map +1 -0
- package/dist/lib/daemon.d.ts +6 -0
- package/dist/lib/daemon.js +218 -0
- package/dist/lib/daemon.js.map +1 -0
- package/dist/lib/diff.d.ts +5 -0
- package/dist/lib/diff.js +85 -0
- package/dist/lib/diff.js.map +1 -0
- package/dist/lib/doctor.d.ts +1 -0
- package/dist/lib/doctor.js +108 -0
- package/dist/lib/doctor.js.map +1 -0
- package/dist/lib/history.d.ts +22 -0
- package/dist/lib/history.js +62 -0
- package/dist/lib/history.js.map +1 -0
- package/dist/lib/logger.d.ts +11 -0
- package/dist/lib/logger.js +62 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/modes.d.ts +22 -0
- package/dist/lib/modes.js +58 -0
- package/dist/lib/modes.js.map +1 -0
- package/dist/lib/overrides.d.ts +13 -0
- package/dist/lib/overrides.js +74 -0
- package/dist/lib/overrides.js.map +1 -0
- package/dist/lib/session.d.ts +32 -0
- package/dist/lib/session.js +68 -0
- package/dist/lib/session.js.map +1 -0
- package/dist/lib/summarizer.d.ts +5 -0
- package/dist/lib/summarizer.js +46 -0
- package/dist/lib/summarizer.js.map +1 -0
- package/dist/lib/tunnel.d.ts +2 -0
- package/dist/lib/tunnel.js +48 -0
- package/dist/lib/tunnel.js.map +1 -0
- package/dist/relay/pending.d.ts +27 -0
- package/dist/relay/pending.js +65 -0
- package/dist/relay/pending.js.map +1 -0
- package/dist/rules/engine.d.ts +31 -0
- package/dist/rules/engine.js +203 -0
- package/dist/rules/engine.js.map +1 -0
- package/dist/server/http.d.ts +8 -0
- package/dist/server/http.js +359 -0
- package/dist/server/http.js.map +1 -0
- package/dist/socket/client.d.ts +16 -0
- package/dist/socket/client.js +81 -0
- package/dist/socket/client.js.map +1 -0
- package/dist/transport/cloudkit.d.ts +30 -0
- package/dist/transport/cloudkit.js +162 -0
- package/dist/transport/cloudkit.js.map +1 -0
- package/dist/transport/factory.d.ts +6 -0
- package/dist/transport/factory.js +20 -0
- package/dist/transport/factory.js.map +1 -0
- package/dist/transport/interface.d.ts +25 -0
- package/dist/transport/interface.js +13 -0
- package/dist/transport/interface.js.map +1 -0
- package/dist/transport/local.d.ts +46 -0
- package/dist/transport/local.js +320 -0
- package/dist/transport/local.js.map +1 -0
- package/dist/transport/remote.d.ts +17 -0
- package/dist/transport/remote.js +83 -0
- package/dist/transport/remote.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.connectSocket = connectSocket;
|
|
4
|
+
exports.emitApprovalRequest = emitApprovalRequest;
|
|
5
|
+
exports.getSocket = getSocket;
|
|
6
|
+
exports.disconnectSocket = disconnectSocket;
|
|
7
|
+
exports.isConnected = isConnected;
|
|
8
|
+
const socket_io_client_1 = require("socket.io-client");
|
|
9
|
+
const pending_1 = require("../relay/pending");
|
|
10
|
+
const logger_1 = require("../lib/logger");
|
|
11
|
+
let socket = null;
|
|
12
|
+
let reconnectAttempts = 0;
|
|
13
|
+
const MAX_RECONNECT = 10;
|
|
14
|
+
/**
|
|
15
|
+
* 连接 Socket.IO,带 JWT auth 和指数退避重连
|
|
16
|
+
*/
|
|
17
|
+
function connectSocket(serverURL, token) {
|
|
18
|
+
if (socket?.connected)
|
|
19
|
+
return socket;
|
|
20
|
+
socket = (0, socket_io_client_1.io)(serverURL, {
|
|
21
|
+
auth: { token },
|
|
22
|
+
transports: ['websocket', 'polling'],
|
|
23
|
+
reconnection: true,
|
|
24
|
+
reconnectionDelay: 1000,
|
|
25
|
+
reconnectionDelayMax: 30000,
|
|
26
|
+
reconnectionAttempts: MAX_RECONNECT,
|
|
27
|
+
});
|
|
28
|
+
socket.on('connect', () => {
|
|
29
|
+
reconnectAttempts = 0;
|
|
30
|
+
logger_1.log.success(`Socket connected (id: ${socket.id})`);
|
|
31
|
+
});
|
|
32
|
+
socket.on('disconnect', (reason) => {
|
|
33
|
+
logger_1.log.warn(`Socket disconnected: ${reason}`);
|
|
34
|
+
});
|
|
35
|
+
socket.on('connect_error', (err) => {
|
|
36
|
+
reconnectAttempts++;
|
|
37
|
+
const delay = Math.min(Math.pow(2, reconnectAttempts - 1) * 1000, 30000);
|
|
38
|
+
logger_1.log.error(`Connection error: ${err.message} (retry in ${delay / 1000}s)`);
|
|
39
|
+
});
|
|
40
|
+
// ==================== 收到决策 ====================
|
|
41
|
+
socket.on('decision', (data) => {
|
|
42
|
+
logger_1.log.info(`Decision received: ${data.requestId} → ${data.action}`);
|
|
43
|
+
pending_1.pending.resolve(data.requestId, data.action);
|
|
44
|
+
});
|
|
45
|
+
socket.on('heartbeat', () => {
|
|
46
|
+
socket?.emit('heartbeat');
|
|
47
|
+
});
|
|
48
|
+
socket.on('heartbeat_ack', () => {
|
|
49
|
+
logger_1.log.debug('Heartbeat ack');
|
|
50
|
+
});
|
|
51
|
+
return socket;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 发送审批请求到 server,返回 requestId
|
|
55
|
+
*/
|
|
56
|
+
async function emitApprovalRequest(data) {
|
|
57
|
+
return new Promise((resolve, reject) => {
|
|
58
|
+
if (!socket?.connected) {
|
|
59
|
+
return reject(new Error('Socket not connected'));
|
|
60
|
+
}
|
|
61
|
+
socket.emit('approval_request', data, (res) => {
|
|
62
|
+
if (res.success && res.requestId) {
|
|
63
|
+
resolve(res.requestId);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
reject(new Error(res.error ?? 'Failed to send approval request'));
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function getSocket() {
|
|
72
|
+
return socket;
|
|
73
|
+
}
|
|
74
|
+
function disconnectSocket() {
|
|
75
|
+
socket?.disconnect();
|
|
76
|
+
socket = null;
|
|
77
|
+
}
|
|
78
|
+
function isConnected() {
|
|
79
|
+
return socket?.connected ?? false;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/socket/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Transport, ApprovalPayload } from './interface';
|
|
2
|
+
/**
|
|
3
|
+
* CloudKit transport — uses CloudKit Web Services REST API.
|
|
4
|
+
*
|
|
5
|
+
* Mac writes ApprovalRequest records, polls for Decision records.
|
|
6
|
+
* iOS writes Decision records via CKDatabase on-device.
|
|
7
|
+
*
|
|
8
|
+
* Env vars: CLOUDKIT_CONTAINER, CLOUDKIT_API_TOKEN, CLOUDKIT_ENVIRONMENT
|
|
9
|
+
*/
|
|
10
|
+
export declare class CloudKitTransport implements Transport {
|
|
11
|
+
readonly mode: "cloudkit";
|
|
12
|
+
private container;
|
|
13
|
+
private apiToken;
|
|
14
|
+
private environment;
|
|
15
|
+
private baseURL;
|
|
16
|
+
private pollTimer;
|
|
17
|
+
private decisionCb;
|
|
18
|
+
private knownDecisions;
|
|
19
|
+
private _connected;
|
|
20
|
+
constructor();
|
|
21
|
+
get isConnected(): boolean;
|
|
22
|
+
start(): Promise<void>;
|
|
23
|
+
sendApprovalRequest(payload: ApprovalPayload): Promise<string>;
|
|
24
|
+
onDecision(cb: (id: string, action: 'allowed' | 'blocked' | 'timeout') => void): void;
|
|
25
|
+
stop(): void;
|
|
26
|
+
private pollDecisions;
|
|
27
|
+
private query;
|
|
28
|
+
private saveRecord;
|
|
29
|
+
private updateRecordField;
|
|
30
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CloudKitTransport = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const pending_1 = require("../relay/pending");
|
|
6
|
+
const logger_1 = require("../lib/logger");
|
|
7
|
+
const POLL_INTERVAL = 2000;
|
|
8
|
+
/**
|
|
9
|
+
* CloudKit transport — uses CloudKit Web Services REST API.
|
|
10
|
+
*
|
|
11
|
+
* Mac writes ApprovalRequest records, polls for Decision records.
|
|
12
|
+
* iOS writes Decision records via CKDatabase on-device.
|
|
13
|
+
*
|
|
14
|
+
* Env vars: CLOUDKIT_CONTAINER, CLOUDKIT_API_TOKEN, CLOUDKIT_ENVIRONMENT
|
|
15
|
+
*/
|
|
16
|
+
class CloudKitTransport {
|
|
17
|
+
mode = 'cloudkit';
|
|
18
|
+
container;
|
|
19
|
+
apiToken;
|
|
20
|
+
environment;
|
|
21
|
+
baseURL;
|
|
22
|
+
pollTimer = null;
|
|
23
|
+
decisionCb = null;
|
|
24
|
+
knownDecisions = new Set();
|
|
25
|
+
_connected = false;
|
|
26
|
+
constructor() {
|
|
27
|
+
this.container = process.env.CLOUDKIT_CONTAINER ?? '';
|
|
28
|
+
this.apiToken = process.env.CLOUDKIT_API_TOKEN ?? '';
|
|
29
|
+
this.environment = process.env.CLOUDKIT_ENVIRONMENT ?? 'development';
|
|
30
|
+
this.baseURL = `https://api.apple-cloudkit.com/database/1/${this.container}/${this.environment}/private`;
|
|
31
|
+
}
|
|
32
|
+
get isConnected() {
|
|
33
|
+
return this._connected;
|
|
34
|
+
}
|
|
35
|
+
async start() {
|
|
36
|
+
if (!this.container || !this.apiToken) {
|
|
37
|
+
throw new Error('CloudKit requires CLOUDKIT_CONTAINER and CLOUDKIT_API_TOKEN env vars');
|
|
38
|
+
}
|
|
39
|
+
// Verify connectivity
|
|
40
|
+
try {
|
|
41
|
+
await this.query('Decisions', [], 1);
|
|
42
|
+
this._connected = true;
|
|
43
|
+
logger_1.log.success('[cloudkit] Connected to CloudKit');
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
logger_1.log.warn(`[cloudkit] Initial query failed, will retry: ${err.message}`);
|
|
47
|
+
this._connected = true; // optimistic — polling will catch errors
|
|
48
|
+
}
|
|
49
|
+
// Start polling for decisions
|
|
50
|
+
this.pollTimer = setInterval(() => this.pollDecisions(), POLL_INTERVAL);
|
|
51
|
+
logger_1.log.info(`[cloudkit] Polling every ${POLL_INTERVAL / 1000}s for decisions`);
|
|
52
|
+
}
|
|
53
|
+
async sendApprovalRequest(payload) {
|
|
54
|
+
const requestId = (0, crypto_1.randomBytes)(12).toString('hex');
|
|
55
|
+
const record = {
|
|
56
|
+
recordType: 'ApprovalRequest',
|
|
57
|
+
fields: {
|
|
58
|
+
requestId: { value: requestId },
|
|
59
|
+
toolName: { value: payload.toolName },
|
|
60
|
+
toolInput: { value: JSON.stringify(payload.toolInput) },
|
|
61
|
+
riskLevel: { value: payload.riskLevel },
|
|
62
|
+
timestamp: { value: Date.now() },
|
|
63
|
+
timeoutAt: { value: Date.now() + 120_000 },
|
|
64
|
+
status: { value: 'pending' },
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
await this.saveRecord(record);
|
|
68
|
+
logger_1.log.info(`[cloudkit] Approval request saved: ${requestId}`);
|
|
69
|
+
return requestId;
|
|
70
|
+
}
|
|
71
|
+
onDecision(cb) {
|
|
72
|
+
this.decisionCb = cb;
|
|
73
|
+
}
|
|
74
|
+
stop() {
|
|
75
|
+
if (this.pollTimer) {
|
|
76
|
+
clearInterval(this.pollTimer);
|
|
77
|
+
this.pollTimer = null;
|
|
78
|
+
}
|
|
79
|
+
this._connected = false;
|
|
80
|
+
}
|
|
81
|
+
// ==================== CloudKit REST ====================
|
|
82
|
+
async pollDecisions() {
|
|
83
|
+
try {
|
|
84
|
+
const results = await this.query('Decision', [
|
|
85
|
+
{ fieldName: 'status', comparator: 'EQUALS', fieldValue: { value: 'new' } },
|
|
86
|
+
], 20);
|
|
87
|
+
for (const record of results) {
|
|
88
|
+
const requestId = record.fields?.requestId?.value;
|
|
89
|
+
const action = record.fields?.action?.value;
|
|
90
|
+
if (!requestId || !action)
|
|
91
|
+
continue;
|
|
92
|
+
if (this.knownDecisions.has(record.recordName))
|
|
93
|
+
continue;
|
|
94
|
+
this.knownDecisions.add(record.recordName);
|
|
95
|
+
const mapped = action === 'allow' ? 'allowed' : action === 'block' ? 'blocked' : action;
|
|
96
|
+
logger_1.log.info(`[cloudkit] Decision: ${requestId} → ${mapped}`);
|
|
97
|
+
pending_1.pending.resolve(requestId, mapped);
|
|
98
|
+
this.decisionCb?.(requestId, mapped);
|
|
99
|
+
// Mark as processed
|
|
100
|
+
await this.updateRecordField(record.recordName, 'Decision', 'status', 'processed');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
logger_1.log.debug(`[cloudkit] Poll error: ${err.message}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async query(recordType, filters, limit) {
|
|
108
|
+
const body = {
|
|
109
|
+
query: { recordType, filterBy: filters },
|
|
110
|
+
resultsLimit: limit,
|
|
111
|
+
};
|
|
112
|
+
const res = await fetch(`${this.baseURL}/records/query`, {
|
|
113
|
+
method: 'POST',
|
|
114
|
+
headers: {
|
|
115
|
+
'Content-Type': 'application/json',
|
|
116
|
+
'X-Apple-CloudKit-Request-KeyID': this.apiToken,
|
|
117
|
+
},
|
|
118
|
+
body: JSON.stringify(body),
|
|
119
|
+
});
|
|
120
|
+
if (!res.ok)
|
|
121
|
+
throw new Error(`CloudKit query failed: ${res.status}`);
|
|
122
|
+
const json = (await res.json());
|
|
123
|
+
return json.records ?? [];
|
|
124
|
+
}
|
|
125
|
+
async saveRecord(record) {
|
|
126
|
+
const body = {
|
|
127
|
+
operations: [{ operationType: 'create', record }],
|
|
128
|
+
};
|
|
129
|
+
const res = await fetch(`${this.baseURL}/records/modify`, {
|
|
130
|
+
method: 'POST',
|
|
131
|
+
headers: {
|
|
132
|
+
'Content-Type': 'application/json',
|
|
133
|
+
'X-Apple-CloudKit-Request-KeyID': this.apiToken,
|
|
134
|
+
},
|
|
135
|
+
body: JSON.stringify(body),
|
|
136
|
+
});
|
|
137
|
+
if (!res.ok)
|
|
138
|
+
throw new Error(`CloudKit save failed: ${res.status}`);
|
|
139
|
+
}
|
|
140
|
+
async updateRecordField(recordName, recordType, field, value) {
|
|
141
|
+
const body = {
|
|
142
|
+
operations: [{
|
|
143
|
+
operationType: 'update',
|
|
144
|
+
record: {
|
|
145
|
+
recordName,
|
|
146
|
+
recordType,
|
|
147
|
+
fields: { [field]: { value } },
|
|
148
|
+
},
|
|
149
|
+
}],
|
|
150
|
+
};
|
|
151
|
+
await fetch(`${this.baseURL}/records/modify`, {
|
|
152
|
+
method: 'POST',
|
|
153
|
+
headers: {
|
|
154
|
+
'Content-Type': 'application/json',
|
|
155
|
+
'X-Apple-CloudKit-Request-KeyID': this.apiToken,
|
|
156
|
+
},
|
|
157
|
+
body: JSON.stringify(body),
|
|
158
|
+
}).catch(() => { }); // best-effort
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
exports.CloudKitTransport = CloudKitTransport;
|
|
162
|
+
//# sourceMappingURL=cloudkit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudkit.js","sourceRoot":"","sources":["../../src/transport/cloudkit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createTransport = createTransport;
|
|
4
|
+
const local_1 = require("./local");
|
|
5
|
+
const remote_1 = require("./remote");
|
|
6
|
+
const cloudkit_1 = require("./cloudkit");
|
|
7
|
+
function createTransport(mode, opts) {
|
|
8
|
+
switch (mode) {
|
|
9
|
+
case 'local':
|
|
10
|
+
return new local_1.LocalTransport();
|
|
11
|
+
case 'cloudkit':
|
|
12
|
+
return new cloudkit_1.CloudKitTransport();
|
|
13
|
+
case 'server':
|
|
14
|
+
if (!opts?.serverUrl || !opts?.token) {
|
|
15
|
+
throw new Error('Server mode requires serverUrl and token');
|
|
16
|
+
}
|
|
17
|
+
return new remote_1.RemoteTransport(opts.serverUrl, opts.token);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/transport/factory.ts"],"names":[],"mappings":";;AAUA,0CAYC;AArBD,mCAAyC;AACzC,qCAA2C;AAC3C,yCAA+C;AAO/C,SAAgB,eAAe,CAAC,IAAmB,EAAE,IAAuB;IAC1E,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,OAAO;YACV,OAAO,IAAI,sBAAc,EAAE,CAAC;QAC9B,KAAK,UAAU;YACb,OAAO,IAAI,4BAAiB,EAAE,CAAC;QACjC,KAAK,QAAQ;YACX,IAAI,CAAC,IAAI,EAAE,SAAS,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;gBACrC,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;YAC9D,CAAC;YACD,OAAO,IAAI,wBAAe,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport interface — abstracts local (TCP) vs remote (Socket.IO) communication.
|
|
3
|
+
* Both modes use the same message format for approval_request / decision.
|
|
4
|
+
*/
|
|
5
|
+
export type TransportMode = 'local' | 'cloudkit' | 'server';
|
|
6
|
+
export interface ApprovalPayload {
|
|
7
|
+
toolName: string;
|
|
8
|
+
toolInput: Record<string, unknown>;
|
|
9
|
+
riskLevel: string;
|
|
10
|
+
diff?: string;
|
|
11
|
+
contextSummary?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface Transport {
|
|
14
|
+
readonly mode: TransportMode;
|
|
15
|
+
readonly isConnected: boolean;
|
|
16
|
+
start(): Promise<void>;
|
|
17
|
+
sendApprovalRequest(payload: ApprovalPayload): Promise<string>;
|
|
18
|
+
onDecision(cb: (requestId: string, action: 'allowed' | 'blocked' | 'timeout') => void): void;
|
|
19
|
+
stop(): void;
|
|
20
|
+
/** Send fire-and-forget event to iOS (terminal, activity, notification) */
|
|
21
|
+
sendEvent?(data: Record<string, unknown>): void;
|
|
22
|
+
sendNotification?(title: string, message: string): void;
|
|
23
|
+
}
|
|
24
|
+
export declare function setTransport(t: Transport): void;
|
|
25
|
+
export declare function getTransport(): Transport | null;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Transport interface — abstracts local (TCP) vs remote (Socket.IO) communication.
|
|
4
|
+
* Both modes use the same message format for approval_request / decision.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.setTransport = setTransport;
|
|
8
|
+
exports.getTransport = getTransport;
|
|
9
|
+
/** Global transport instance — set by start command */
|
|
10
|
+
let _transport = null;
|
|
11
|
+
function setTransport(t) { _transport = t; }
|
|
12
|
+
function getTransport() { return _transport; }
|
|
13
|
+
//# sourceMappingURL=interface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/transport/interface.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AA6BH,oCAAoE;AACpE,oCAAuE;AAJvE,uDAAuD;AACvD,IAAI,UAAU,GAAqB,IAAI,CAAC;AAExC,SAAgB,YAAY,CAAC,CAAY,IAAU,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC;AACpE,SAAgB,YAAY,KAAuB,OAAO,UAAU,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Transport, ApprovalPayload } from './interface';
|
|
2
|
+
import type { Rule } from '../rules/engine';
|
|
3
|
+
/**
|
|
4
|
+
* Local transport — TCP server + Bonjour (mDNS) for LAN-direct mode.
|
|
5
|
+
*
|
|
6
|
+
* - Opens a TCP server on port 7750
|
|
7
|
+
* - Publishes _sentinel._tcp via Bonjour so iOS can auto-discover
|
|
8
|
+
* - iOS connects directly, same JSON message format as remote mode
|
|
9
|
+
* - Messages are newline-delimited JSON over raw TCP
|
|
10
|
+
*/
|
|
11
|
+
export declare class LocalTransport implements Transport {
|
|
12
|
+
readonly mode: "local";
|
|
13
|
+
private server;
|
|
14
|
+
private bonjour;
|
|
15
|
+
private iosSocket;
|
|
16
|
+
private buffer;
|
|
17
|
+
private static readonly MAX_BUFFER_SIZE;
|
|
18
|
+
private decisionCb;
|
|
19
|
+
private rulesUpdateCb;
|
|
20
|
+
private userMessageCb;
|
|
21
|
+
private activeClaudeProcess;
|
|
22
|
+
get isConnected(): boolean;
|
|
23
|
+
start(): Promise<void>;
|
|
24
|
+
private publishBonjour;
|
|
25
|
+
/** Process newline-delimited messages from buffer (encrypted or plain) */
|
|
26
|
+
private processBuffer;
|
|
27
|
+
private handleMessage;
|
|
28
|
+
/** Send a notification to iOS */
|
|
29
|
+
sendNotification(title: string, message: string): void;
|
|
30
|
+
sendEvent(data: Record<string, unknown>): void;
|
|
31
|
+
private runClaude;
|
|
32
|
+
/** Send a JSON message to connected iOS */
|
|
33
|
+
private send;
|
|
34
|
+
sendApprovalRequest(payload: ApprovalPayload): Promise<string>;
|
|
35
|
+
onDecision(cb: (id: string, action: 'allowed' | 'blocked' | 'timeout') => void): void;
|
|
36
|
+
/** Register callback for rules updates from iOS */
|
|
37
|
+
onRulesUpdate(cb: (rules: Rule[]) => void): void;
|
|
38
|
+
/** Register callback for user messages from iOS */
|
|
39
|
+
onUserMessage(cb: (text: string) => void): void;
|
|
40
|
+
stop(): void;
|
|
41
|
+
/** Get info for pairing display */
|
|
42
|
+
getConnectionInfo(): {
|
|
43
|
+
ip: string;
|
|
44
|
+
port: number;
|
|
45
|
+
};
|
|
46
|
+
}
|