claude-pager 0.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/LICENSE +21 -0
- package/README.md +207 -0
- package/dist/channels/channel.d.ts +27 -0
- package/dist/channels/channel.d.ts.map +1 -0
- package/dist/channels/channel.js +3 -0
- package/dist/channels/channel.js.map +1 -0
- package/dist/channels/factory.d.ts +4 -0
- package/dist/channels/factory.d.ts.map +1 -0
- package/dist/channels/factory.js +22 -0
- package/dist/channels/factory.js.map +1 -0
- package/dist/channels/ntfy/__tests__/provider.test.d.ts +2 -0
- package/dist/channels/ntfy/__tests__/provider.test.d.ts.map +1 -0
- package/dist/channels/ntfy/__tests__/provider.test.js +29 -0
- package/dist/channels/ntfy/__tests__/provider.test.js.map +1 -0
- package/dist/channels/ntfy/provider.d.ts +17 -0
- package/dist/channels/ntfy/provider.d.ts.map +1 -0
- package/dist/channels/ntfy/provider.js +142 -0
- package/dist/channels/ntfy/provider.js.map +1 -0
- package/dist/channels/telegram/provider.d.ts +27 -0
- package/dist/channels/telegram/provider.d.ts.map +1 -0
- package/dist/channels/telegram/provider.js +312 -0
- package/dist/channels/telegram/provider.js.map +1 -0
- package/dist/channels/telegram/voice-handler.d.ts +22 -0
- package/dist/channels/telegram/voice-handler.d.ts.map +1 -0
- package/dist/channels/telegram/voice-handler.js +68 -0
- package/dist/channels/telegram/voice-handler.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +99 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/recover.d.ts +2 -0
- package/dist/cli/recover.d.ts.map +1 -0
- package/dist/cli/recover.js +45 -0
- package/dist/cli/recover.js.map +1 -0
- package/dist/cli/run.d.ts +2 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +32 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/setup.d.ts +8 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +238 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/config/index.d.ts +6 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +40 -0
- package/dist/config/index.js.map +1 -0
- package/dist/daemon/__tests__/handlers.test.d.ts +2 -0
- package/dist/daemon/__tests__/handlers.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/handlers.test.js +99 -0
- package/dist/daemon/__tests__/handlers.test.js.map +1 -0
- package/dist/daemon/__tests__/server.test.d.ts +2 -0
- package/dist/daemon/__tests__/server.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/server.test.js +118 -0
- package/dist/daemon/__tests__/server.test.js.map +1 -0
- package/dist/daemon/handlers.d.ts +4 -0
- package/dist/daemon/handlers.d.ts.map +1 -0
- package/dist/daemon/handlers.js +153 -0
- package/dist/daemon/handlers.js.map +1 -0
- package/dist/daemon/index.d.ts +7 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +83 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/server.d.ts +11 -0
- package/dist/daemon/server.d.ts.map +1 -0
- package/dist/daemon/server.js +115 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +172 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/injectors/__tests__/tmux.test.d.ts +2 -0
- package/dist/injectors/__tests__/tmux.test.d.ts.map +1 -0
- package/dist/injectors/__tests__/tmux.test.js +38 -0
- package/dist/injectors/__tests__/tmux.test.js.map +1 -0
- package/dist/injectors/factory.d.ts +3 -0
- package/dist/injectors/factory.d.ts.map +1 -0
- package/dist/injectors/factory.js +22 -0
- package/dist/injectors/factory.js.map +1 -0
- package/dist/injectors/injector.d.ts +7 -0
- package/dist/injectors/injector.d.ts.map +1 -0
- package/dist/injectors/injector.js +3 -0
- package/dist/injectors/injector.js.map +1 -0
- package/dist/injectors/tmux/injector.d.ts +9 -0
- package/dist/injectors/tmux/injector.d.ts.map +1 -0
- package/dist/injectors/tmux/injector.js +55 -0
- package/dist/injectors/tmux/injector.js.map +1 -0
- package/dist/injectors/xdotool/injector.d.ts +9 -0
- package/dist/injectors/xdotool/injector.d.ts.map +1 -0
- package/dist/injectors/xdotool/injector.js +59 -0
- package/dist/injectors/xdotool/injector.js.map +1 -0
- package/dist/sessions/__tests__/events.test.d.ts +2 -0
- package/dist/sessions/__tests__/events.test.d.ts.map +1 -0
- package/dist/sessions/__tests__/events.test.js +103 -0
- package/dist/sessions/__tests__/events.test.js.map +1 -0
- package/dist/sessions/__tests__/tracker.test.d.ts +2 -0
- package/dist/sessions/__tests__/tracker.test.d.ts.map +1 -0
- package/dist/sessions/__tests__/tracker.test.js +24 -0
- package/dist/sessions/__tests__/tracker.test.js.map +1 -0
- package/dist/sessions/events.d.ts +11 -0
- package/dist/sessions/events.d.ts.map +1 -0
- package/dist/sessions/events.js +73 -0
- package/dist/sessions/events.js.map +1 -0
- package/dist/sessions/tracker.d.ts +7 -0
- package/dist/sessions/tracker.d.ts.map +1 -0
- package/dist/sessions/tracker.js +83 -0
- package/dist/sessions/tracker.js.map +1 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/__tests__/html.test.d.ts +2 -0
- package/dist/utils/__tests__/html.test.d.ts.map +1 -0
- package/dist/utils/__tests__/html.test.js +42 -0
- package/dist/utils/__tests__/html.test.js.map +1 -0
- package/dist/utils/__tests__/json.test.d.ts +2 -0
- package/dist/utils/__tests__/json.test.d.ts.map +1 -0
- package/dist/utils/__tests__/json.test.js +27 -0
- package/dist/utils/__tests__/json.test.js.map +1 -0
- package/dist/utils/__tests__/validation.test.d.ts +2 -0
- package/dist/utils/__tests__/validation.test.d.ts.map +1 -0
- package/dist/utils/__tests__/validation.test.js +38 -0
- package/dist/utils/__tests__/validation.test.js.map +1 -0
- package/dist/utils/html.d.ts +3 -0
- package/dist/utils/html.d.ts.map +1 -0
- package/dist/utils/html.js +43 -0
- package/dist/utils/html.js.map +1 -0
- package/dist/utils/json.d.ts +2 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +13 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/validation.d.ts +4 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +16 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/voice/transcribe.d.ts +7 -0
- package/dist/voice/transcribe.d.ts.map +1 -0
- package/dist/voice/transcribe.js +66 -0
- package/dist/voice/transcribe.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
const node_test_1 = require("node:test");
|
|
7
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
8
|
+
const injector_js_1 = require("../tmux/injector.js");
|
|
9
|
+
const SESSION = {
|
|
10
|
+
sessionId: 'test-1',
|
|
11
|
+
pid: 1234,
|
|
12
|
+
tty: '',
|
|
13
|
+
cwd: '/tmp',
|
|
14
|
+
tmuxPane: '%99',
|
|
15
|
+
timestamp: Date.now(),
|
|
16
|
+
};
|
|
17
|
+
(0, node_test_1.describe)('TmuxInjector', () => {
|
|
18
|
+
(0, node_test_1.it)('should have name "tmux"', () => {
|
|
19
|
+
const injector = new injector_js_1.TmuxInjector();
|
|
20
|
+
strict_1.default.equal(injector.name, 'tmux');
|
|
21
|
+
});
|
|
22
|
+
(0, node_test_1.it)('should return false for resolve when no tmuxPane', async () => {
|
|
23
|
+
const injector = new injector_js_1.TmuxInjector();
|
|
24
|
+
const noPane = { ...SESSION, tmuxPane: undefined };
|
|
25
|
+
strict_1.default.equal(await injector.resolve(noPane), false);
|
|
26
|
+
});
|
|
27
|
+
(0, node_test_1.it)('should return false for sendResponse when no tmuxPane', async () => {
|
|
28
|
+
const injector = new injector_js_1.TmuxInjector();
|
|
29
|
+
const noPane = { ...SESSION, tmuxPane: undefined };
|
|
30
|
+
strict_1.default.equal(await injector.sendResponse(noPane, 'allow', 'permission_prompt'), false);
|
|
31
|
+
});
|
|
32
|
+
(0, node_test_1.it)('should return false for resolve on non-existent pane', async () => {
|
|
33
|
+
const injector = new injector_js_1.TmuxInjector();
|
|
34
|
+
const fakePaneSession = { ...SESSION, tmuxPane: '%99999' };
|
|
35
|
+
strict_1.default.equal(await injector.resolve(fakePaneSession), false);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=tmux.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmux.test.js","sourceRoot":"","sources":["../../../src/injectors/__tests__/tmux.test.ts"],"names":[],"mappings":";;;;;AAAA,yCAAyC;AACzC,gEAAwC;AACxC,qDAAmD;AAGnD,MAAM,OAAO,GAAgB;IAC3B,SAAS,EAAE,QAAQ;IACnB,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,EAAE;IACP,GAAG,EAAE,MAAM;IACX,QAAQ,EAAE,KAAK;IACf,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;CACtB,CAAC;AAEF,IAAA,oBAAQ,EAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,IAAA,cAAE,EAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,MAAM,QAAQ,GAAG,IAAI,0BAAY,EAAE,CAAC;QACpC,gBAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,QAAQ,GAAG,IAAI,0BAAY,EAAE,CAAC;QACpC,MAAM,MAAM,GAAgB,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;QAChE,gBAAM,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,QAAQ,GAAG,IAAI,0BAAY,EAAE,CAAC;QACpC,MAAM,MAAM,GAAgB,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;QAChE,gBAAM,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,mBAAmB,CAAC,EAAE,KAAK,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,QAAQ,GAAG,IAAI,0BAAY,EAAE,CAAC;QACpC,MAAM,eAAe,GAAgB,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;QACxE,gBAAM,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,KAAK,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/injectors/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAInD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,aAAa,GAAG,aAAa,CAe/F"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createInjector = createInjector;
|
|
4
|
+
const injector_js_1 = require("./tmux/injector.js");
|
|
5
|
+
const injector_js_2 = require("./xdotool/injector.js");
|
|
6
|
+
function createInjector(type) {
|
|
7
|
+
switch (type) {
|
|
8
|
+
case 'tmux':
|
|
9
|
+
return new injector_js_1.TmuxInjector();
|
|
10
|
+
case 'xdotool':
|
|
11
|
+
return new injector_js_2.XdotoolInjector();
|
|
12
|
+
case 'auto':
|
|
13
|
+
// Prefer tmux if available, fallback to xdotool
|
|
14
|
+
if (process.platform === 'linux') {
|
|
15
|
+
return new injector_js_1.TmuxInjector();
|
|
16
|
+
}
|
|
17
|
+
throw new Error(`No injector available for platform: ${process.platform}`);
|
|
18
|
+
default:
|
|
19
|
+
throw new Error(`Unknown injector type: ${type}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/injectors/factory.ts"],"names":[],"mappings":";;AAIA,wCAeC;AAlBD,oDAAkD;AAClD,uDAAwD;AAExD,SAAgB,cAAc,CAAC,IAAiD;IAC9E,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,MAAM;YACT,OAAO,IAAI,0BAAY,EAAE,CAAC;QAC5B,KAAK,SAAS;YACZ,OAAO,IAAI,6BAAe,EAAE,CAAC;QAC/B,KAAK,MAAM;YACT,gDAAgD;YAChD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;gBACjC,OAAO,IAAI,0BAAY,EAAE,CAAC;YAC5B,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,uCAAuC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC7E;YACE,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { EventType, SessionInfo } from '../types.js';
|
|
2
|
+
export interface InputInjector {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
resolve(session: SessionInfo): Promise<boolean>;
|
|
5
|
+
sendResponse(session: SessionInfo, text: string, eventType: EventType): Promise<boolean>;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=injector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injector.d.ts","sourceRoot":"","sources":["../../src/injectors/injector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEhD,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1F"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injector.js","sourceRoot":"","sources":["../../src/injectors/injector.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { InputInjector } from '../injector.js';
|
|
2
|
+
import type { EventType, SessionInfo } from '../../types.js';
|
|
3
|
+
export declare class TmuxInjector implements InputInjector {
|
|
4
|
+
readonly name = "tmux";
|
|
5
|
+
resolve(session: SessionInfo): Promise<boolean>;
|
|
6
|
+
sendResponse(session: SessionInfo, text: string, eventType: EventType): Promise<boolean>;
|
|
7
|
+
private handlePermissionPrompt;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=injector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injector.d.ts","sourceRoot":"","sources":["../../../src/injectors/tmux/injector.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAI7D,qBAAa,YAAa,YAAW,aAAa;IAChD,QAAQ,CAAC,IAAI,UAAU;IAEjB,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAU/C,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;YAiBhF,sBAAsB;CAerC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TmuxInjector = void 0;
|
|
4
|
+
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
const node_util_1 = require("node:util");
|
|
6
|
+
const exec = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
7
|
+
class TmuxInjector {
|
|
8
|
+
name = 'tmux';
|
|
9
|
+
async resolve(session) {
|
|
10
|
+
if (!session.tmuxPane)
|
|
11
|
+
return false;
|
|
12
|
+
try {
|
|
13
|
+
await exec('tmux', ['has-session', '-t', session.tmuxPane]);
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async sendResponse(session, text, eventType) {
|
|
21
|
+
if (!session.tmuxPane)
|
|
22
|
+
return false;
|
|
23
|
+
const pane = session.tmuxPane;
|
|
24
|
+
try {
|
|
25
|
+
if (eventType === 'permission_prompt') {
|
|
26
|
+
return await this.handlePermissionPrompt(pane, text);
|
|
27
|
+
}
|
|
28
|
+
// For other prompts (idle_prompt, etc.), type the text + Enter
|
|
29
|
+
await exec('tmux', ['send-keys', '-t', pane, text, 'Enter']);
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
console.error('[tmux] sendResponse error:', err);
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async handlePermissionPrompt(pane, text) {
|
|
38
|
+
const lower = text.toLowerCase().trim();
|
|
39
|
+
if (['allow', 'yes', 'y'].includes(lower)) {
|
|
40
|
+
// Option 1 "Yes" is always first and already selected — just press Enter
|
|
41
|
+
await exec('tmux', ['send-keys', '-t', pane, 'Enter']);
|
|
42
|
+
}
|
|
43
|
+
else if (['deny', 'no', 'n'].includes(lower)) {
|
|
44
|
+
// "No" is always the last option — End jumps to it
|
|
45
|
+
await exec('tmux', ['send-keys', '-t', pane, 'End', 'Enter']);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// Free text — type it and press Enter
|
|
49
|
+
await exec('tmux', ['send-keys', '-t', pane, text, 'Enter']);
|
|
50
|
+
}
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.TmuxInjector = TmuxInjector;
|
|
55
|
+
//# sourceMappingURL=injector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injector.js","sourceRoot":"","sources":["../../../src/injectors/tmux/injector.ts"],"names":[],"mappings":";;;AAAA,2DAA8C;AAC9C,yCAAsC;AAItC,MAAM,IAAI,GAAG,IAAA,qBAAS,EAAC,6BAAQ,CAAC,CAAC;AAEjC,MAAa,YAAY;IACd,IAAI,GAAG,MAAM,CAAC;IAEvB,KAAK,CAAC,OAAO,CAAC,OAAoB;QAChC,IAAI,CAAC,OAAO,CAAC,QAAQ;YAAE,OAAO,KAAK,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,aAAa,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC5D,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAAoB,EAAE,IAAY,EAAE,SAAoB;QACzE,IAAI,CAAC,OAAO,CAAC,QAAQ;YAAE,OAAO,KAAK,CAAC;QACpC,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC;QAE9B,IAAI,CAAC;YACH,IAAI,SAAS,KAAK,mBAAmB,EAAE,CAAC;gBACtC,OAAO,MAAM,IAAI,CAAC,sBAAsB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACvD,CAAC;YACD,+DAA+D;YAC/D,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;YAC7D,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,GAAG,CAAC,CAAC;YACjD,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,sBAAsB,CAAC,IAAY,EAAE,IAAY;QAC7D,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QAExC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1C,yEAAyE;YACzE,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QACzD,CAAC;aAAM,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/C,mDAAmD;YACnD,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;QAChE,CAAC;aAAM,CAAC;YACN,sCAAsC;YACtC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AA7CD,oCA6CC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { InputInjector } from '../injector.js';
|
|
2
|
+
import type { EventType, SessionInfo } from '../../types.js';
|
|
3
|
+
export declare class XdotoolInjector implements InputInjector {
|
|
4
|
+
readonly name = "xdotool";
|
|
5
|
+
resolve(session: SessionInfo): Promise<boolean>;
|
|
6
|
+
sendResponse(session: SessionInfo, text: string, eventType: EventType): Promise<boolean>;
|
|
7
|
+
private findWindow;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=injector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injector.d.ts","sourceRoot":"","sources":["../../../src/injectors/xdotool/injector.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAI7D,qBAAa,eAAgB,YAAW,aAAa;IACnD,QAAQ,CAAC,IAAI,aAAa;IAEpB,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAI/C,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;YA6BhF,UAAU;CAWzB"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.XdotoolInjector = void 0;
|
|
4
|
+
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
const node_util_1 = require("node:util");
|
|
6
|
+
const exec = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
7
|
+
class XdotoolInjector {
|
|
8
|
+
name = 'xdotool';
|
|
9
|
+
async resolve(session) {
|
|
10
|
+
return (await this.findWindow(session)) !== null;
|
|
11
|
+
}
|
|
12
|
+
async sendResponse(session, text, eventType) {
|
|
13
|
+
const windowId = await this.findWindow(session);
|
|
14
|
+
if (!windowId)
|
|
15
|
+
return false;
|
|
16
|
+
try {
|
|
17
|
+
await exec('xdotool', ['windowactivate', '--sync', String(windowId)]);
|
|
18
|
+
await new Promise(r => setTimeout(r, 100));
|
|
19
|
+
if (eventType === 'permission_prompt') {
|
|
20
|
+
const lower = text.toLowerCase().trim();
|
|
21
|
+
if (['allow', 'yes', 'y'].includes(lower)) {
|
|
22
|
+
await exec('xdotool', ['key', '--window', String(windowId), 'Return']);
|
|
23
|
+
}
|
|
24
|
+
else if (['deny', 'no', 'n'].includes(lower)) {
|
|
25
|
+
await exec('xdotool', ['key', '--window', String(windowId), 'End', 'Return']);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
await exec('xdotool', ['type', '--window', String(windowId), '--clearmodifiers', text]);
|
|
29
|
+
await exec('xdotool', ['key', '--window', String(windowId), 'Return']);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
await exec('xdotool', ['type', '--window', String(windowId), '--clearmodifiers', text]);
|
|
34
|
+
await exec('xdotool', ['key', '--window', String(windowId), 'Return']);
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
console.error('[xdotool] sendResponse error:', err);
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async findWindow(session) {
|
|
44
|
+
if (session.windowId)
|
|
45
|
+
return session.windowId;
|
|
46
|
+
try {
|
|
47
|
+
const { stdout } = await exec('xdotool', ['search', '--pid', String(session.pid)]);
|
|
48
|
+
const ids = stdout.trim().split('\n').filter(Boolean);
|
|
49
|
+
if (ids.length === 0)
|
|
50
|
+
return null;
|
|
51
|
+
return parseInt(ids[ids.length - 1], 10);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.XdotoolInjector = XdotoolInjector;
|
|
59
|
+
//# sourceMappingURL=injector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injector.js","sourceRoot":"","sources":["../../../src/injectors/xdotool/injector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.test.d.ts","sourceRoot":"","sources":["../../../src/sessions/__tests__/events.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,103 @@
|
|
|
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
|
+
const node_test_1 = require("node:test");
|
|
7
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
8
|
+
const events_js_1 = require("../events.js");
|
|
9
|
+
function makeEvent(id, overrides) {
|
|
10
|
+
return {
|
|
11
|
+
id,
|
|
12
|
+
sessionId: 'session-1',
|
|
13
|
+
type: 'permission_prompt',
|
|
14
|
+
message: 'Allow Bash(git status)?',
|
|
15
|
+
project: '/home/user/dev/myproject',
|
|
16
|
+
timestamp: Date.now(),
|
|
17
|
+
...overrides,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
(0, node_test_1.describe)('event store', () => {
|
|
21
|
+
(0, node_test_1.beforeEach)(() => {
|
|
22
|
+
for (const q of (0, events_js_1.listPending)()) {
|
|
23
|
+
(0, events_js_1.removePending)(q.event.id);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
(0, node_test_1.it)('should add and retrieve a pending question', () => {
|
|
27
|
+
const event = makeEvent('evt-1');
|
|
28
|
+
const shortId = (0, events_js_1.addPending)(event, 'msg-123');
|
|
29
|
+
const q = (0, events_js_1.getPending)('evt-1');
|
|
30
|
+
strict_1.default.ok(q);
|
|
31
|
+
strict_1.default.equal(q.event.id, 'evt-1');
|
|
32
|
+
strict_1.default.equal(q.channelMessageId, 'msg-123');
|
|
33
|
+
strict_1.default.ok(q.shortId);
|
|
34
|
+
strict_1.default.ok(shortId);
|
|
35
|
+
});
|
|
36
|
+
(0, node_test_1.it)('should return undefined for unknown event', () => {
|
|
37
|
+
strict_1.default.equal((0, events_js_1.getPending)('nonexistent'), undefined);
|
|
38
|
+
});
|
|
39
|
+
(0, node_test_1.it)('should list all pending questions', () => {
|
|
40
|
+
(0, events_js_1.addPending)(makeEvent('evt-1'));
|
|
41
|
+
(0, events_js_1.addPending)(makeEvent('evt-2'));
|
|
42
|
+
(0, events_js_1.addPending)(makeEvent('evt-3'));
|
|
43
|
+
strict_1.default.equal((0, events_js_1.listPending)().length, 3);
|
|
44
|
+
});
|
|
45
|
+
(0, node_test_1.it)('should remove a pending question', () => {
|
|
46
|
+
(0, events_js_1.addPending)(makeEvent('evt-1'));
|
|
47
|
+
strict_1.default.ok((0, events_js_1.getPending)('evt-1'));
|
|
48
|
+
(0, events_js_1.removePending)('evt-1');
|
|
49
|
+
strict_1.default.equal((0, events_js_1.getPending)('evt-1'), undefined);
|
|
50
|
+
});
|
|
51
|
+
(0, node_test_1.describe)('resolveResponse', () => {
|
|
52
|
+
(0, node_test_1.it)('should return null when no pending questions', () => {
|
|
53
|
+
strict_1.default.equal((0, events_js_1.resolveResponse)('allow'), null);
|
|
54
|
+
});
|
|
55
|
+
(0, node_test_1.it)('should route any text to the single pending question', () => {
|
|
56
|
+
(0, events_js_1.addPending)(makeEvent('evt-1'));
|
|
57
|
+
const result = (0, events_js_1.resolveResponse)('allow');
|
|
58
|
+
strict_1.default.ok(result);
|
|
59
|
+
strict_1.default.equal(result.question.event.id, 'evt-1');
|
|
60
|
+
strict_1.default.equal(result.response, 'allow');
|
|
61
|
+
});
|
|
62
|
+
(0, node_test_1.it)('should route free text to single pending question', () => {
|
|
63
|
+
(0, events_js_1.addPending)(makeEvent('evt-1', { type: 'idle_prompt' }));
|
|
64
|
+
const result = (0, events_js_1.resolveResponse)('yes go ahead and fix the tests');
|
|
65
|
+
strict_1.default.ok(result);
|
|
66
|
+
strict_1.default.equal(result.question.event.id, 'evt-1');
|
|
67
|
+
strict_1.default.equal(result.response, 'yes go ahead and fix the tests');
|
|
68
|
+
});
|
|
69
|
+
(0, node_test_1.it)('should route allow/deny to most recent permission_prompt when multiple pending', () => {
|
|
70
|
+
(0, events_js_1.addPending)(makeEvent('evt-1', { type: 'idle_prompt' }));
|
|
71
|
+
(0, events_js_1.addPending)(makeEvent('evt-2', { type: 'permission_prompt' }));
|
|
72
|
+
(0, events_js_1.addPending)(makeEvent('evt-3', { type: 'permission_prompt' }));
|
|
73
|
+
const result = (0, events_js_1.resolveResponse)('allow');
|
|
74
|
+
strict_1.default.ok(result);
|
|
75
|
+
strict_1.default.equal(result.question.event.id, 'evt-3');
|
|
76
|
+
strict_1.default.equal(result.response, 'allow');
|
|
77
|
+
});
|
|
78
|
+
(0, node_test_1.it)('should route numbered response to the correct question', () => {
|
|
79
|
+
const shortId1 = (0, events_js_1.addPending)(makeEvent('evt-1'));
|
|
80
|
+
(0, events_js_1.addPending)(makeEvent('evt-2'));
|
|
81
|
+
const result = (0, events_js_1.resolveResponse)(`#${shortId1} deny`);
|
|
82
|
+
strict_1.default.ok(result);
|
|
83
|
+
strict_1.default.equal(result.question.event.id, 'evt-1');
|
|
84
|
+
strict_1.default.equal(result.response, 'deny');
|
|
85
|
+
});
|
|
86
|
+
(0, node_test_1.it)('should route numbered response without # prefix', () => {
|
|
87
|
+
const shortId1 = (0, events_js_1.addPending)(makeEvent('evt-1'));
|
|
88
|
+
(0, events_js_1.addPending)(makeEvent('evt-2'));
|
|
89
|
+
const result = (0, events_js_1.resolveResponse)(`${shortId1} deny`);
|
|
90
|
+
strict_1.default.ok(result);
|
|
91
|
+
strict_1.default.equal(result.question.event.id, 'evt-1');
|
|
92
|
+
strict_1.default.equal(result.response, 'deny');
|
|
93
|
+
});
|
|
94
|
+
(0, node_test_1.it)('should fallback to most recent for ambiguous free text', () => {
|
|
95
|
+
(0, events_js_1.addPending)(makeEvent('evt-1', { type: 'idle_prompt' }));
|
|
96
|
+
(0, events_js_1.addPending)(makeEvent('evt-2', { type: 'idle_prompt' }));
|
|
97
|
+
const result = (0, events_js_1.resolveResponse)('do the thing');
|
|
98
|
+
strict_1.default.ok(result);
|
|
99
|
+
strict_1.default.equal(result.question.event.id, 'evt-2');
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
//# sourceMappingURL=events.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.test.js","sourceRoot":"","sources":["../../../src/sessions/__tests__/events.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracker.test.d.ts","sourceRoot":"","sources":["../../../src/sessions/__tests__/tracker.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
const node_test_1 = require("node:test");
|
|
7
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
8
|
+
async function loadTracker() {
|
|
9
|
+
const { isProcessAlive } = await import('../tracker.js');
|
|
10
|
+
return { isProcessAlive };
|
|
11
|
+
}
|
|
12
|
+
(0, node_test_1.describe)('session tracker', () => {
|
|
13
|
+
(0, node_test_1.describe)('isProcessAlive', () => {
|
|
14
|
+
(0, node_test_1.it)('should return true for current process', async () => {
|
|
15
|
+
const { isProcessAlive } = await loadTracker();
|
|
16
|
+
strict_1.default.equal(isProcessAlive(process.pid), true);
|
|
17
|
+
});
|
|
18
|
+
(0, node_test_1.it)('should return false for non-existent PID', async () => {
|
|
19
|
+
const { isProcessAlive } = await loadTracker();
|
|
20
|
+
strict_1.default.equal(isProcessAlive(99999999), false);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
//# sourceMappingURL=tracker.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracker.test.js","sourceRoot":"","sources":["../../../src/sessions/__tests__/tracker.test.ts"],"names":[],"mappings":";;;;;AAAA,yCAAyC;AACzC,gEAAwC;AAExC,KAAK,UAAU,WAAW;IACxB,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;IACzD,OAAO,EAAE,cAAc,EAAE,CAAC;AAC5B,CAAC;AAED,IAAA,oBAAQ,EAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,IAAA,oBAAQ,EAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,IAAA,cAAE,EAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;YACtD,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;YAC/C,gBAAM,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QAEH,IAAA,cAAE,EAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;YACxD,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;YAC/C,gBAAM,CAAC,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PendingQuestion, RelayEvent } from '../types.js';
|
|
2
|
+
export declare function addPending(event: RelayEvent, channelMessageId?: string): string;
|
|
3
|
+
export declare function getPending(eventId: string): PendingQuestion | undefined;
|
|
4
|
+
export declare function removePending(eventId: string): void;
|
|
5
|
+
export declare function listPending(): PendingQuestion[];
|
|
6
|
+
export interface ResolvedResponse {
|
|
7
|
+
question: PendingQuestion;
|
|
8
|
+
response: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function resolveResponse(rawText: string): ResolvedResponse | null;
|
|
11
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/sessions/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAM/D,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,CAU/E;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAEvE;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEnD;AAID,wBAAgB,WAAW,IAAI,eAAe,EAAE,CAS/C;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAsCxE"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addPending = addPending;
|
|
4
|
+
exports.getPending = getPending;
|
|
5
|
+
exports.removePending = removePending;
|
|
6
|
+
exports.listPending = listPending;
|
|
7
|
+
exports.resolveResponse = resolveResponse;
|
|
8
|
+
const pending = new Map();
|
|
9
|
+
let nextShortId = (Date.now() % 10000) + 1;
|
|
10
|
+
let insertionOrder = 0;
|
|
11
|
+
function addPending(event, channelMessageId) {
|
|
12
|
+
const shortId = String(nextShortId++);
|
|
13
|
+
pending.set(event.id, {
|
|
14
|
+
event,
|
|
15
|
+
notifiedAt: Date.now(),
|
|
16
|
+
channelMessageId,
|
|
17
|
+
shortId,
|
|
18
|
+
order: insertionOrder++,
|
|
19
|
+
});
|
|
20
|
+
return shortId;
|
|
21
|
+
}
|
|
22
|
+
function getPending(eventId) {
|
|
23
|
+
return pending.get(eventId);
|
|
24
|
+
}
|
|
25
|
+
function removePending(eventId) {
|
|
26
|
+
pending.delete(eventId);
|
|
27
|
+
}
|
|
28
|
+
const PENDING_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
29
|
+
function listPending() {
|
|
30
|
+
// Expire old questions
|
|
31
|
+
const now = Date.now();
|
|
32
|
+
for (const [id, q] of pending) {
|
|
33
|
+
if (now - q.notifiedAt > PENDING_TTL_MS) {
|
|
34
|
+
pending.delete(id);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return Array.from(pending.values());
|
|
38
|
+
}
|
|
39
|
+
function resolveResponse(rawText) {
|
|
40
|
+
const all = listPending();
|
|
41
|
+
if (all.length === 0)
|
|
42
|
+
return null;
|
|
43
|
+
const text = rawText.trim();
|
|
44
|
+
// Try "#<id> response" format — id can be a shortId (number) or event UUID
|
|
45
|
+
const prefixed = text.match(/^#?([\w-]+)\s+(.+)$/s);
|
|
46
|
+
if (prefixed) {
|
|
47
|
+
const id = prefixed[1];
|
|
48
|
+
const response = prefixed[2].trim();
|
|
49
|
+
// Match by shortId (ntfy) or event ID (telegram)
|
|
50
|
+
const match = all.find(q => q.shortId === id || q.event.id === id);
|
|
51
|
+
if (match) {
|
|
52
|
+
return { question: match, response };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Single pending → any text goes to it
|
|
56
|
+
if (all.length === 1) {
|
|
57
|
+
return { question: all[0], response: text };
|
|
58
|
+
}
|
|
59
|
+
// Multiple pending: route "allow"/"deny"/"yes"/"no" to most recent permission_prompt
|
|
60
|
+
const lower = text.toLowerCase();
|
|
61
|
+
if (['allow', 'deny', 'yes', 'no', 'y', 'n'].includes(lower)) {
|
|
62
|
+
const permissionQuestions = all
|
|
63
|
+
.filter(q => q.event.type === 'permission_prompt')
|
|
64
|
+
.sort((a, b) => b.order - a.order);
|
|
65
|
+
if (permissionQuestions.length > 0) {
|
|
66
|
+
return { question: permissionQuestions[0], response: text };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Fallback: route to most recent pending
|
|
70
|
+
const mostRecent = all.sort((a, b) => b.order - a.order)[0];
|
|
71
|
+
return { question: mostRecent, response: text };
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/sessions/events.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SessionInfo } from '../types.js';
|
|
2
|
+
export declare function registerSession(info: SessionInfo): void;
|
|
3
|
+
export declare function getSession(sessionId: string): SessionInfo | null;
|
|
4
|
+
export declare function listSessions(): SessionInfo[];
|
|
5
|
+
export declare function isProcessAlive(pid: number): boolean;
|
|
6
|
+
export declare function cleanDeadSessions(): number;
|
|
7
|
+
//# sourceMappingURL=tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/sessions/tracker.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM/C,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAQvD;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAKhE;AAED,wBAAgB,YAAY,IAAI,WAAW,EAAE,CAO5C;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOnD;AAmBD,wBAAgB,iBAAiB,IAAI,MAAM,CAc1C"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerSession = registerSession;
|
|
4
|
+
exports.getSession = getSession;
|
|
5
|
+
exports.listSessions = listSessions;
|
|
6
|
+
exports.isProcessAlive = isProcessAlive;
|
|
7
|
+
exports.cleanDeadSessions = cleanDeadSessions;
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const node_path_1 = require("node:path");
|
|
10
|
+
const node_child_process_1 = require("node:child_process");
|
|
11
|
+
const index_js_1 = require("../config/index.js");
|
|
12
|
+
const json_js_1 = require("../utils/json.js");
|
|
13
|
+
const validation_js_1 = require("../utils/validation.js");
|
|
14
|
+
function sessionsDir() {
|
|
15
|
+
return (0, node_path_1.join)((0, index_js_1.getDataDir)(), 'sessions');
|
|
16
|
+
}
|
|
17
|
+
function registerSession(info) {
|
|
18
|
+
if (!(0, validation_js_1.isValidSessionId)(info.sessionId)) {
|
|
19
|
+
console.debug('[tracker] Rejected invalid sessionId:', info.sessionId);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
(0, index_js_1.ensureDataDir)();
|
|
23
|
+
const file = (0, node_path_1.join)(sessionsDir(), `${info.sessionId}.json`);
|
|
24
|
+
(0, node_fs_1.writeFileSync)(file, JSON.stringify(info, null, 2) + '\n');
|
|
25
|
+
}
|
|
26
|
+
function getSession(sessionId) {
|
|
27
|
+
if (!(0, validation_js_1.isValidSessionId)(sessionId))
|
|
28
|
+
return null;
|
|
29
|
+
const file = (0, node_path_1.join)(sessionsDir(), `${sessionId}.json`);
|
|
30
|
+
if (!(0, node_fs_1.existsSync)(file))
|
|
31
|
+
return null;
|
|
32
|
+
return (0, json_js_1.safeJsonParse)((0, node_fs_1.readFileSync)(file, 'utf-8'), null);
|
|
33
|
+
}
|
|
34
|
+
function listSessions() {
|
|
35
|
+
const dir = sessionsDir();
|
|
36
|
+
if (!(0, node_fs_1.existsSync)(dir))
|
|
37
|
+
return [];
|
|
38
|
+
return (0, node_fs_1.readdirSync)(dir)
|
|
39
|
+
.filter(f => f.endsWith('.json'))
|
|
40
|
+
.map(f => (0, json_js_1.safeJsonParse)((0, node_fs_1.readFileSync)((0, node_path_1.join)(dir, f), 'utf-8'), null))
|
|
41
|
+
.filter((s) => s !== null);
|
|
42
|
+
}
|
|
43
|
+
function isProcessAlive(pid) {
|
|
44
|
+
try {
|
|
45
|
+
process.kill(pid, 0);
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function isTmuxPaneAlive(pane) {
|
|
53
|
+
try {
|
|
54
|
+
(0, node_child_process_1.execFileSync)('tmux', ['has-session', '-t', pane], { timeout: 2000 });
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function isSessionAlive(info) {
|
|
62
|
+
// If we have a tmux pane, check that instead of the PID
|
|
63
|
+
if (info.tmuxPane) {
|
|
64
|
+
return isTmuxPaneAlive(info.tmuxPane);
|
|
65
|
+
}
|
|
66
|
+
return isProcessAlive(info.pid);
|
|
67
|
+
}
|
|
68
|
+
function cleanDeadSessions() {
|
|
69
|
+
let cleaned = 0;
|
|
70
|
+
const dir = sessionsDir();
|
|
71
|
+
if (!(0, node_fs_1.existsSync)(dir))
|
|
72
|
+
return 0;
|
|
73
|
+
for (const file of (0, node_fs_1.readdirSync)(dir).filter(f => f.endsWith('.json'))) {
|
|
74
|
+
const path = (0, node_path_1.join)(dir, file);
|
|
75
|
+
const info = (0, json_js_1.safeJsonParse)((0, node_fs_1.readFileSync)(path, 'utf-8'), null);
|
|
76
|
+
if (!info || !isSessionAlive(info)) {
|
|
77
|
+
(0, node_fs_1.unlinkSync)(path);
|
|
78
|
+
cleaned++;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return cleaned;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../src/sessions/tracker.ts"],"names":[],"mappings":"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"}
|