agentwake 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.
- package/.cursor/hooks.json +15 -0
- package/.env.example +19 -0
- package/README.md +137 -0
- package/dist/adapters/claude-hook-adapter.d.ts +3 -0
- package/dist/adapters/claude-hook-adapter.d.ts.map +1 -0
- package/dist/adapters/claude-hook-adapter.js +25 -0
- package/dist/adapters/claude-hook-adapter.js.map +1 -0
- package/dist/adapters/cursor-hook-adapter.d.ts +3 -0
- package/dist/adapters/cursor-hook-adapter.d.ts.map +1 -0
- package/dist/adapters/cursor-hook-adapter.js +144 -0
- package/dist/adapters/cursor-hook-adapter.js.map +1 -0
- package/dist/adapters/cursor-terminal-hook.d.ts +20 -0
- package/dist/adapters/cursor-terminal-hook.d.ts.map +1 -0
- package/dist/adapters/cursor-terminal-hook.js +120 -0
- package/dist/adapters/cursor-terminal-hook.js.map +1 -0
- package/dist/adapters/hook-common.d.ts +6 -0
- package/dist/adapters/hook-common.d.ts.map +1 -0
- package/dist/adapters/hook-common.js +69 -0
- package/dist/adapters/hook-common.js.map +1 -0
- package/dist/adapters/qoder-log-adapter.d.ts +19 -0
- package/dist/adapters/qoder-log-adapter.d.ts.map +1 -0
- package/dist/adapters/qoder-log-adapter.js +320 -0
- package/dist/adapters/qoder-log-adapter.js.map +1 -0
- package/dist/bootstrap.d.ts +19 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +106 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +187 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +21 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +63 -0
- package/dist/config.js.map +1 -0
- package/dist/domain/notify-event.d.ts +17 -0
- package/dist/domain/notify-event.d.ts.map +1 -0
- package/dist/domain/notify-event.js +10 -0
- package/dist/domain/notify-event.js.map +1 -0
- package/dist/gateway/adapter-registry.d.ts +9 -0
- package/dist/gateway/adapter-registry.d.ts.map +1 -0
- package/dist/gateway/adapter-registry.js +26 -0
- package/dist/gateway/adapter-registry.js.map +1 -0
- package/dist/gateway/adapter.d.ts +14 -0
- package/dist/gateway/adapter.d.ts.map +1 -0
- package/dist/gateway/adapter.js +3 -0
- package/dist/gateway/adapter.js.map +1 -0
- package/dist/gateway/event-router.d.ts +20 -0
- package/dist/gateway/event-router.d.ts.map +1 -0
- package/dist/gateway/event-router.js +72 -0
- package/dist/gateway/event-router.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +9 -0
- package/dist/main.js.map +1 -0
- package/dist/notifiers/desktop-notifier.d.ts +11 -0
- package/dist/notifiers/desktop-notifier.d.ts.map +1 -0
- package/dist/notifiers/desktop-notifier.js +78 -0
- package/dist/notifiers/desktop-notifier.js.map +1 -0
- package/dist/notifiers/mobile-ws-notifier.d.ts +13 -0
- package/dist/notifiers/mobile-ws-notifier.d.ts.map +1 -0
- package/dist/notifiers/mobile-ws-notifier.js +65 -0
- package/dist/notifiers/mobile-ws-notifier.js.map +1 -0
- package/dist/notifiers/notifier.d.ts +6 -0
- package/dist/notifiers/notifier.d.ts.map +1 -0
- package/dist/notifiers/notifier.js +3 -0
- package/dist/notifiers/notifier.js.map +1 -0
- package/dist/notifiers/pwa-push-notifier.d.ts +12 -0
- package/dist/notifiers/pwa-push-notifier.d.ts.map +1 -0
- package/dist/notifiers/pwa-push-notifier.js +69 -0
- package/dist/notifiers/pwa-push-notifier.js.map +1 -0
- package/dist/run-gateway.d.ts +3 -0
- package/dist/run-gateway.d.ts.map +1 -0
- package/dist/run-gateway.js +66 -0
- package/dist/run-gateway.js.map +1 -0
- package/dist/utils/approval-match.d.ts +2 -0
- package/dist/utils/approval-match.d.ts.map +1 -0
- package/dist/utils/approval-match.js +32 -0
- package/dist/utils/approval-match.js.map +1 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +19 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +60 -0
- package/scripts/cursor-hook-forwarder.mjs +269 -0
- package/web/app.js +350 -0
- package/web/icons/icon-192.svg +6 -0
- package/web/icons/icon-512.svg +6 -0
- package/web/index.html +117 -0
- package/web/manifest.webmanifest +25 -0
- package/web/sw.js +32 -0
|
@@ -0,0 +1,69 @@
|
|
|
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.PwaPushNotifier = void 0;
|
|
7
|
+
const web_push_1 = __importDefault(require("web-push"));
|
|
8
|
+
class PwaPushNotifier {
|
|
9
|
+
vapidPublicKey;
|
|
10
|
+
id = "pwa-push-notifier";
|
|
11
|
+
subscriptions = new Map();
|
|
12
|
+
constructor(vapidPublicKey) {
|
|
13
|
+
this.vapidPublicKey = vapidPublicKey;
|
|
14
|
+
}
|
|
15
|
+
mountRoutes(app) {
|
|
16
|
+
app.get("/api/push/public-key", (_req, res) => {
|
|
17
|
+
if (!this.vapidPublicKey) {
|
|
18
|
+
res.status(404).json({ ok: false, error: "vapid key not configured" });
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
res.json({ ok: true, publicKey: this.vapidPublicKey });
|
|
22
|
+
});
|
|
23
|
+
app.post("/api/push/subscribe", (req, res) => {
|
|
24
|
+
const subscription = req.body?.subscription;
|
|
25
|
+
if (!subscription?.endpoint || !subscription.keys?.auth || !subscription.keys?.p256dh) {
|
|
26
|
+
res.status(400).json({ ok: false, error: "invalid subscription" });
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
this.subscriptions.set(subscription.endpoint, subscription);
|
|
30
|
+
res.json({ ok: true });
|
|
31
|
+
});
|
|
32
|
+
app.post("/api/push/unsubscribe", (req, res) => {
|
|
33
|
+
const endpoint = typeof req.body?.endpoint === "string" ? req.body.endpoint : "";
|
|
34
|
+
if (!endpoint) {
|
|
35
|
+
res.status(400).json({ ok: false, error: "endpoint required" });
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
this.subscriptions.delete(endpoint);
|
|
39
|
+
res.json({ ok: true });
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
async notify(event) {
|
|
43
|
+
if (this.subscriptions.size === 0 || !this.vapidPublicKey) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const payload = JSON.stringify({
|
|
47
|
+
title: event.title,
|
|
48
|
+
body: event.body,
|
|
49
|
+
event,
|
|
50
|
+
});
|
|
51
|
+
const expired = [];
|
|
52
|
+
await Promise.all([...this.subscriptions.values()].map(async (subscription) => {
|
|
53
|
+
try {
|
|
54
|
+
await web_push_1.default.sendNotification(subscription, payload);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
const code = Number(error?.statusCode ?? 0);
|
|
58
|
+
if (code === 404 || code === 410) {
|
|
59
|
+
expired.push(subscription.endpoint);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}));
|
|
63
|
+
for (const endpoint of expired) {
|
|
64
|
+
this.subscriptions.delete(endpoint);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.PwaPushNotifier = PwaPushNotifier;
|
|
69
|
+
//# sourceMappingURL=pwa-push-notifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pwa-push-notifier.js","sourceRoot":"","sources":["../../src/notifiers/pwa-push-notifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-gateway.d.ts","sourceRoot":"","sources":["../src/run-gateway.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AAkCvB,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAgChD"}
|
|
@@ -0,0 +1,66 @@
|
|
|
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.runGateway = runGateway;
|
|
7
|
+
require("dotenv/config");
|
|
8
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
9
|
+
const qrcode_terminal_1 = __importDefault(require("qrcode-terminal"));
|
|
10
|
+
const bootstrap_1 = require("./bootstrap");
|
|
11
|
+
const config_1 = require("./config");
|
|
12
|
+
const logger_1 = require("./utils/logger");
|
|
13
|
+
function resolveLanHost() {
|
|
14
|
+
const interfaces = node_os_1.default.networkInterfaces();
|
|
15
|
+
for (const entries of Object.values(interfaces)) {
|
|
16
|
+
if (!entries) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
for (const entry of entries) {
|
|
20
|
+
if (entry.family === "IPv4" && !entry.internal) {
|
|
21
|
+
return entry.address;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
function printAccessQr(host, port, httpsEnabled) {
|
|
28
|
+
const lanHost = host === "0.0.0.0" ? resolveLanHost() : host;
|
|
29
|
+
if (!lanHost) {
|
|
30
|
+
logger_1.logger.warn("unable to resolve LAN host for QR");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const protocol = httpsEnabled ? "https" : "http";
|
|
34
|
+
const url = `${protocol}://${lanHost}:${port}`;
|
|
35
|
+
logger_1.logger.info("mobile access url", { url });
|
|
36
|
+
qrcode_terminal_1.default.generate(url, { small: true });
|
|
37
|
+
}
|
|
38
|
+
async function runGateway() {
|
|
39
|
+
const config = (0, config_1.loadConfig)();
|
|
40
|
+
const gateway = (0, bootstrap_1.createGateway)(config);
|
|
41
|
+
await gateway.start();
|
|
42
|
+
await new Promise((resolve, reject) => {
|
|
43
|
+
gateway.server.listen(config.port, config.host, () => {
|
|
44
|
+
logger_1.logger.info("agentwake started", {
|
|
45
|
+
host: config.host,
|
|
46
|
+
port: config.port,
|
|
47
|
+
httpsEnabled: config.httpsEnabled,
|
|
48
|
+
cursorHookPath: config.cursorHookPath,
|
|
49
|
+
claudeHookPath: config.claudeHookPath,
|
|
50
|
+
wsPath: config.wsPath,
|
|
51
|
+
});
|
|
52
|
+
printAccessQr(config.host, config.port, config.httpsEnabled);
|
|
53
|
+
resolve();
|
|
54
|
+
});
|
|
55
|
+
gateway.server.on("error", reject);
|
|
56
|
+
});
|
|
57
|
+
const shutdown = async () => {
|
|
58
|
+
logger_1.logger.info("shutting down");
|
|
59
|
+
await gateway.stop();
|
|
60
|
+
await new Promise((resolve, reject) => gateway.server.close((err) => (err ? reject(err) : resolve())));
|
|
61
|
+
process.exit(0);
|
|
62
|
+
};
|
|
63
|
+
process.on("SIGINT", () => void shutdown());
|
|
64
|
+
process.on("SIGTERM", () => void shutdown());
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=run-gateway.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-gateway.js","sourceRoot":"","sources":["../src/run-gateway.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval-match.d.ts","sourceRoot":"","sources":["../../src/utils/approval-match.ts"],"names":[],"mappings":"AAsBA,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAM5D"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isApprovalWaitingText = isApprovalWaitingText;
|
|
4
|
+
const APPROVAL_PATTERNS = [
|
|
5
|
+
/waiting for user (approval|confirmation|allow)/i,
|
|
6
|
+
/awaiting user (approval|confirmation)/i,
|
|
7
|
+
/requires user (approval|confirmation)/i,
|
|
8
|
+
/permission required/i,
|
|
9
|
+
/waiting for (your )?approval/i,
|
|
10
|
+
/pending (user )?approval/i,
|
|
11
|
+
/user (action|input|response) required/i,
|
|
12
|
+
/approve or reject/i,
|
|
13
|
+
/waiting for (user )?(to )?(confirm|approve|allow|accept)/i,
|
|
14
|
+
/tool (call |execution )?(requires|needs) (user )?(approval|confirmation)/i,
|
|
15
|
+
/paused.{0,20}(approval|confirmation|user)/i,
|
|
16
|
+
/blocked.{0,20}waiting.{0,20}user/i,
|
|
17
|
+
/ask_user_question/i,
|
|
18
|
+
/等待用户允许/,
|
|
19
|
+
/等待用户确认/,
|
|
20
|
+
/需要用户授权/,
|
|
21
|
+
/等待.*审批/,
|
|
22
|
+
/等待.*批准/,
|
|
23
|
+
/需要.*确认/,
|
|
24
|
+
];
|
|
25
|
+
function isApprovalWaitingText(input) {
|
|
26
|
+
const value = input.trim();
|
|
27
|
+
if (!value) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
return APPROVAL_PATTERNS.some((pattern) => pattern.test(value));
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=approval-match.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval-match.js","sourceRoot":"","sources":["../../src/utils/approval-match.ts"],"names":[],"mappings":";;AAsBA,sDAMC;AA5BD,MAAM,iBAAiB,GAAG;IACxB,iDAAiD;IACjD,wCAAwC;IACxC,wCAAwC;IACxC,sBAAsB;IACtB,+BAA+B;IAC/B,2BAA2B;IAC3B,wCAAwC;IACxC,oBAAoB;IACpB,2DAA2D;IAC3D,2EAA2E;IAC3E,4CAA4C;IAC5C,mCAAmC;IACnC,oBAAoB;IACpB,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;CACT,CAAC;AAEF,SAAgB,qBAAqB,CAAC,KAAa;IACjD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const logger: {
|
|
2
|
+
info: (msg: string, meta?: Record<string, unknown>) => void;
|
|
3
|
+
warn: (msg: string, meta?: Record<string, unknown>) => void;
|
|
4
|
+
error: (msg: string, meta?: Record<string, unknown>) => void;
|
|
5
|
+
debug: (msg: string, meta?: Record<string, unknown>) => void;
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,MAAM;gBACL,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBACtC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;iBACrC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;iBACtC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CACpD,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.logger = void 0;
|
|
4
|
+
function log(level, msg, meta) {
|
|
5
|
+
const ts = new Date().toISOString();
|
|
6
|
+
const prefix = `[${ts}] [${level.toUpperCase()}]`;
|
|
7
|
+
if (meta && Object.keys(meta).length > 0) {
|
|
8
|
+
console.log(prefix, msg, JSON.stringify(meta));
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
console.log(prefix, msg);
|
|
12
|
+
}
|
|
13
|
+
exports.logger = {
|
|
14
|
+
info: (msg, meta) => log("info", msg, meta),
|
|
15
|
+
warn: (msg, meta) => log("warn", msg, meta),
|
|
16
|
+
error: (msg, meta) => log("error", msg, meta),
|
|
17
|
+
debug: (msg, meta) => log("debug", msg, meta),
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":";;;AAEA,SAAS,GAAG,CAAC,KAAe,EAAE,GAAW,EAAE,IAA8B;IACvE,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC;IAClD,IAAI,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/C,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAC3B,CAAC;AAEY,QAAA,MAAM,GAAG;IACpB,IAAI,EAAE,CAAC,GAAW,EAAE,IAA8B,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC;IAC7E,IAAI,EAAE,CAAC,GAAW,EAAE,IAA8B,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC;IAC7E,KAAK,EAAE,CAAC,GAAW,EAAE,IAA8B,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC;IAC/E,KAAK,EAAE,CAAC,GAAW,EAAE,IAA8B,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC;CAChF,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agentwake",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Cross-editor notification gateway for approval waiting events.",
|
|
5
|
+
"main": "dist/main.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist/**",
|
|
8
|
+
"web/**",
|
|
9
|
+
"scripts/cursor-hook-forwarder.mjs",
|
|
10
|
+
".env.example",
|
|
11
|
+
".cursor/hooks.json",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"bin": {
|
|
15
|
+
"agentwake": "dist/cli.js"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"dev": "tsx src/main.ts",
|
|
19
|
+
"cli": "tsx src/cli.ts",
|
|
20
|
+
"build": "tsc -p tsconfig.json",
|
|
21
|
+
"start": "node dist/cli.js start",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest",
|
|
24
|
+
"init": "tsx src/cli.ts init"
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/tjdxwwj/agentwake.git"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [],
|
|
31
|
+
"author": "",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"type": "commonjs",
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/tjdxwwj/agentwake/issues"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/tjdxwwj/agentwake#readme",
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@types/qrcode-terminal": "^0.12.2",
|
|
40
|
+
"dotenv": "^17.4.1",
|
|
41
|
+
"express": "^5.2.1",
|
|
42
|
+
"node-notifier": "^10.0.1",
|
|
43
|
+
"qrcode-terminal": "^0.12.0",
|
|
44
|
+
"web-push": "^3.6.7",
|
|
45
|
+
"ws": "^8.20.0",
|
|
46
|
+
"zod": "^4.3.6"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/express": "^5.0.6",
|
|
50
|
+
"@types/node": "^25.5.2",
|
|
51
|
+
"@types/node-notifier": "^8.0.5",
|
|
52
|
+
"@types/supertest": "^7.2.0",
|
|
53
|
+
"@types/web-push": "^3.6.4",
|
|
54
|
+
"@types/ws": "^8.18.1",
|
|
55
|
+
"supertest": "^7.2.2",
|
|
56
|
+
"tsx": "^4.21.0",
|
|
57
|
+
"typescript": "^6.0.2",
|
|
58
|
+
"vitest": "^4.1.3"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { mkdir, appendFile } from "node:fs/promises";
|
|
5
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { execFile } from "node:child_process";
|
|
7
|
+
import { promisify } from "node:util";
|
|
8
|
+
|
|
9
|
+
const execFileAsync = promisify(execFile);
|
|
10
|
+
|
|
11
|
+
const gatewayUrl = process.env.AGENTWAKE_GATEWAY_URL || "http://127.0.0.1:3199/hooks/cursor";
|
|
12
|
+
const enforceDangerousAsk = (process.env.AGENTWAKE_CURSOR_ENFORCE_ASK || "1") !== "0";
|
|
13
|
+
const approvalMode = (process.env.AGENTWAKE_CURSOR_APPROVAL_MODE || "cursor-ask").trim().toLowerCase();
|
|
14
|
+
const debugLogEnabled = (process.env.AGENTWAKE_CURSOR_DEBUG_LOG || "1") !== "0";
|
|
15
|
+
const debugLogFile =
|
|
16
|
+
process.env.AGENTWAKE_CURSOR_DEBUG_LOG_FILE ||
|
|
17
|
+
path.join(process.cwd(), ".qoder", "cursor-hook-debug.jsonl");
|
|
18
|
+
const approvalCacheFile =
|
|
19
|
+
process.env.AGENTWAKE_CURSOR_APPROVAL_CACHE_FILE ||
|
|
20
|
+
path.join(process.cwd(), ".qoder", "cursor-approval-cache.json");
|
|
21
|
+
const approvalCacheTtlMs = 30_000;
|
|
22
|
+
|
|
23
|
+
const DANGEROUS_COMMAND_PATTERNS = [
|
|
24
|
+
/\brm\s+-rf\s+\/(?!tmp\b)/i,
|
|
25
|
+
/\brm\s+-rf\s+~\//i,
|
|
26
|
+
/\bsudo\b/i,
|
|
27
|
+
/\bchmod\s+-R\s+777\b/i,
|
|
28
|
+
/\bdd\s+if=/i,
|
|
29
|
+
/\bmkfs(\.\w+)?\b/i,
|
|
30
|
+
/\bcurl\b.*\|\s*(sh|bash|zsh)\b/i,
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
function shouldAskForDangerousCommand(command) {
|
|
34
|
+
const text = String(command || "").trim();
|
|
35
|
+
if (!text) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
return DANGEROUS_COMMAND_PATTERNS.some((pattern) => pattern.test(text));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function writeDebugLog(record) {
|
|
42
|
+
if (!debugLogEnabled) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const dir = path.dirname(debugLogFile);
|
|
46
|
+
await mkdir(dir, { recursive: true });
|
|
47
|
+
await appendFile(debugLogFile, `${JSON.stringify(record)}\n`, "utf8");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function readStdin() {
|
|
51
|
+
const chunks = [];
|
|
52
|
+
for await (const chunk of process.stdin) {
|
|
53
|
+
chunks.push(typeof chunk === "string" ? chunk : chunk.toString("utf8"));
|
|
54
|
+
}
|
|
55
|
+
return chunks.join("");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function resolveApprovalCacheKey(payload) {
|
|
59
|
+
const generation = String(payload?.generation_id || "");
|
|
60
|
+
const session = String(payload?.session_id || payload?.conversation_id || "");
|
|
61
|
+
const command = String(payload?.command || "");
|
|
62
|
+
if (!command) {
|
|
63
|
+
return "";
|
|
64
|
+
}
|
|
65
|
+
return `${session}:${generation}:${command}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function loadApprovalCache() {
|
|
69
|
+
try {
|
|
70
|
+
if (!existsSync(approvalCacheFile)) {
|
|
71
|
+
return {};
|
|
72
|
+
}
|
|
73
|
+
const raw = readFileSync(approvalCacheFile, "utf8");
|
|
74
|
+
const parsed = JSON.parse(raw);
|
|
75
|
+
if (!parsed || typeof parsed !== "object") {
|
|
76
|
+
return {};
|
|
77
|
+
}
|
|
78
|
+
return parsed;
|
|
79
|
+
} catch {
|
|
80
|
+
return {};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function saveApprovalCache(cache) {
|
|
85
|
+
try {
|
|
86
|
+
const dir = path.dirname(approvalCacheFile);
|
|
87
|
+
if (!existsSync(dir)) {
|
|
88
|
+
mkdirSync(dir, { recursive: true });
|
|
89
|
+
}
|
|
90
|
+
writeFileSync(approvalCacheFile, JSON.stringify(cache), "utf8");
|
|
91
|
+
} catch {
|
|
92
|
+
// ignore cache write errors
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function readCachedDecision(cacheKey) {
|
|
97
|
+
if (!cacheKey) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
const cache = loadApprovalCache();
|
|
101
|
+
const now = Date.now();
|
|
102
|
+
for (const [key, value] of Object.entries(cache)) {
|
|
103
|
+
const ts = Number(value?.ts || 0);
|
|
104
|
+
if (!ts || now - ts > approvalCacheTtlMs) {
|
|
105
|
+
delete cache[key];
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const record = cache[cacheKey];
|
|
109
|
+
saveApprovalCache(cache);
|
|
110
|
+
if (!record) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const decision = String(record.decision || "");
|
|
114
|
+
if (decision !== "allow" && decision !== "deny") {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
return decision;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function writeCachedDecision(cacheKey, decision) {
|
|
121
|
+
if (!cacheKey) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const cache = loadApprovalCache();
|
|
125
|
+
cache[cacheKey] = { decision, ts: Date.now() };
|
|
126
|
+
saveApprovalCache(cache);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function escapeAppleScriptText(input) {
|
|
130
|
+
return String(input || "").replaceAll("\\", "\\\\").replaceAll("\"", "\\\"");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async function resolveOsaDecision(command) {
|
|
134
|
+
const title = "AgentWake Approval";
|
|
135
|
+
const body = `检测到高风险命令:\\n${command}\\n\\n是否允许执行?`;
|
|
136
|
+
const script = `display dialog "${escapeAppleScriptText(body)}" with title "${escapeAppleScriptText(title)}" buttons {"Reject","Allow"} default button "Reject" giving up after 20`;
|
|
137
|
+
try {
|
|
138
|
+
const { stdout } = await execFileAsync("osascript", ["-e", script]);
|
|
139
|
+
const text = String(stdout || "");
|
|
140
|
+
if (/Allow/i.test(text)) {
|
|
141
|
+
return "allow";
|
|
142
|
+
}
|
|
143
|
+
return "deny";
|
|
144
|
+
} catch {
|
|
145
|
+
return "deny";
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function forwardToGateway(params) {
|
|
150
|
+
const { payload, eventName, headers } = params;
|
|
151
|
+
const controller = new AbortController();
|
|
152
|
+
const timer = setTimeout(() => controller.abort(), 500);
|
|
153
|
+
try {
|
|
154
|
+
const response = await fetch(gatewayUrl, {
|
|
155
|
+
method: "POST",
|
|
156
|
+
headers,
|
|
157
|
+
body: JSON.stringify(payload),
|
|
158
|
+
signal: controller.signal,
|
|
159
|
+
});
|
|
160
|
+
const responseText = await response.text();
|
|
161
|
+
await writeDebugLog({
|
|
162
|
+
ts: new Date().toISOString(),
|
|
163
|
+
phase: "gateway-forwarded",
|
|
164
|
+
status: response.status,
|
|
165
|
+
responseText,
|
|
166
|
+
eventName,
|
|
167
|
+
});
|
|
168
|
+
} catch (error) {
|
|
169
|
+
await writeDebugLog({
|
|
170
|
+
ts: new Date().toISOString(),
|
|
171
|
+
phase: "forward-error",
|
|
172
|
+
eventName,
|
|
173
|
+
error: String(error),
|
|
174
|
+
});
|
|
175
|
+
} finally {
|
|
176
|
+
clearTimeout(timer);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async function main() {
|
|
181
|
+
try {
|
|
182
|
+
const raw = await readStdin();
|
|
183
|
+
if (!raw.trim()) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const payload = JSON.parse(raw);
|
|
187
|
+
await writeDebugLog({
|
|
188
|
+
ts: new Date().toISOString(),
|
|
189
|
+
phase: "hook-received",
|
|
190
|
+
payload,
|
|
191
|
+
});
|
|
192
|
+
const eventName = String(payload?.hook_event_name || "");
|
|
193
|
+
if (eventName !== "beforeShellExecution" && eventName !== "afterShellExecution") {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
let forwardedPayload = payload;
|
|
197
|
+
if (eventName === "beforeShellExecution" && enforceDangerousAsk) {
|
|
198
|
+
const command = String(payload?.command || "");
|
|
199
|
+
if (shouldAskForDangerousCommand(command)) {
|
|
200
|
+
const reasonText = `AgentWake risk policy matched: ${command}`;
|
|
201
|
+
let reply;
|
|
202
|
+
let approvalDecision = "ask";
|
|
203
|
+
if (approvalMode === "osascript") {
|
|
204
|
+
const cacheKey = resolveApprovalCacheKey(payload);
|
|
205
|
+
const cachedDecision = readCachedDecision(cacheKey);
|
|
206
|
+
approvalDecision = cachedDecision || (await resolveOsaDecision(command));
|
|
207
|
+
if (!cachedDecision) {
|
|
208
|
+
writeCachedDecision(cacheKey, approvalDecision);
|
|
209
|
+
}
|
|
210
|
+
if (approvalDecision === "allow") {
|
|
211
|
+
reply = {
|
|
212
|
+
continue: true,
|
|
213
|
+
userMessage: `AgentWake 已同意执行: ${command}`,
|
|
214
|
+
agentMessage: "User approved via AgentWake osascript dialog.",
|
|
215
|
+
};
|
|
216
|
+
} else {
|
|
217
|
+
reply = {
|
|
218
|
+
continue: false,
|
|
219
|
+
permission: "deny",
|
|
220
|
+
userMessage: `AgentWake 已拒绝执行: ${command}`,
|
|
221
|
+
agentMessage: "User rejected via AgentWake osascript dialog.",
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
} else {
|
|
225
|
+
reply = {
|
|
226
|
+
continue: false,
|
|
227
|
+
permission: "ask",
|
|
228
|
+
userMessage: `AgentWake 拦截到高风险命令,需手动同意后执行: ${command}`,
|
|
229
|
+
agentMessage:
|
|
230
|
+
"High-risk shell command detected by AgentWake policy. Request explicit user approval first.",
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
process.stdout.write(`${JSON.stringify(reply)}\n`);
|
|
234
|
+
forwardedPayload = {
|
|
235
|
+
...payload,
|
|
236
|
+
permission: reply.permission,
|
|
237
|
+
pendingApproval: approvalDecision === "ask",
|
|
238
|
+
reason: reasonText,
|
|
239
|
+
requiresApproval: true,
|
|
240
|
+
approvalMode,
|
|
241
|
+
approvalDecision,
|
|
242
|
+
};
|
|
243
|
+
await writeDebugLog({
|
|
244
|
+
ts: new Date().toISOString(),
|
|
245
|
+
phase: "hook-ask-returned",
|
|
246
|
+
reply,
|
|
247
|
+
command,
|
|
248
|
+
approvalMode,
|
|
249
|
+
approvalDecision,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const headers = {
|
|
255
|
+
"content-type": "application/json",
|
|
256
|
+
};
|
|
257
|
+
await forwardToGateway({ payload: forwardedPayload, eventName, headers });
|
|
258
|
+
} catch (error) {
|
|
259
|
+
// Hook should never block Cursor's main flow.
|
|
260
|
+
process.stderr.write(`[agentwake] cursor hook forward failed: ${String(error)}\n`);
|
|
261
|
+
await writeDebugLog({
|
|
262
|
+
ts: new Date().toISOString(),
|
|
263
|
+
phase: "forward-error",
|
|
264
|
+
error: String(error),
|
|
265
|
+
}).catch(() => {});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
void main();
|