pi-courier 0.1.32 → 0.1.34
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/README.md +6 -2
- package/README.zh-CN.md +6 -2
- package/dist/auth/admin-commands.d.ts +52 -0
- package/dist/auth/admin-commands.d.ts.map +1 -0
- package/dist/auth/admin-commands.js +155 -0
- package/dist/auth/admin-commands.js.map +1 -0
- package/dist/auth/challenge-auth.d.ts +38 -31
- package/dist/auth/challenge-auth.d.ts.map +1 -1
- package/dist/auth/challenge-auth.js +95 -229
- package/dist/auth/challenge-auth.js.map +1 -1
- package/dist/cli.js +6 -35
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +35 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +53 -3
- package/dist/config.js.map +1 -1
- package/dist/lock.js +3 -3
- package/dist/lock.js.map +1 -1
- package/dist/logger.d.ts +22 -9
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +62 -25
- package/dist/logger.js.map +1 -1
- package/dist/management-room.d.ts +15 -0
- package/dist/management-room.d.ts.map +1 -0
- package/dist/management-room.js +30 -0
- package/dist/management-room.js.map +1 -0
- package/dist/rpc/command-map.d.ts +10 -25
- package/dist/rpc/command-map.d.ts.map +1 -1
- package/dist/rpc/command-map.js +12 -239
- package/dist/rpc/command-map.js.map +1 -1
- package/dist/rpc/message-router.d.ts +30 -12
- package/dist/rpc/message-router.d.ts.map +1 -1
- package/dist/rpc/message-router.js +161 -154
- package/dist/rpc/message-router.js.map +1 -1
- package/dist/rpc/pmctl-controller.d.ts +54 -0
- package/dist/rpc/pmctl-controller.d.ts.map +1 -0
- package/dist/rpc/pmctl-controller.js +297 -0
- package/dist/rpc/pmctl-controller.js.map +1 -0
- package/dist/rpc/project-manager.d.ts +9 -3
- package/dist/rpc/project-manager.d.ts.map +1 -1
- package/dist/rpc/project-manager.js +25 -24
- package/dist/rpc/project-manager.js.map +1 -1
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +30 -3
- package/dist/setup.js.map +1 -1
- package/dist/space.d.ts +33 -0
- package/dist/space.d.ts.map +1 -0
- package/dist/space.js +118 -0
- package/dist/space.js.map +1 -0
- package/dist/standalone.d.ts.map +1 -1
- package/dist/standalone.js +86 -91
- package/dist/standalone.js.map +1 -1
- package/dist/transports/interface.d.ts +51 -12
- package/dist/transports/interface.d.ts.map +1 -1
- package/dist/transports/matrix-rooms.d.ts +55 -0
- package/dist/transports/matrix-rooms.d.ts.map +1 -0
- package/dist/transports/matrix-rooms.js +116 -0
- package/dist/transports/matrix-rooms.js.map +1 -0
- package/dist/transports/matrix-utils.d.ts +4 -0
- package/dist/transports/matrix-utils.d.ts.map +1 -1
- package/dist/transports/matrix-utils.js +9 -1
- package/dist/transports/matrix-utils.js.map +1 -1
- package/dist/transports/matrix-utils.test.js +29 -1
- package/dist/transports/matrix-utils.test.js.map +1 -1
- package/dist/transports/matrix.d.ts +18 -17
- package/dist/transports/matrix.d.ts.map +1 -1
- package/dist/transports/matrix.js +63 -94
- package/dist/transports/matrix.js.map +1 -1
- package/dist/types.d.ts +19 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/warnings.d.ts +10 -0
- package/dist/warnings.d.ts.map +1 -0
- package/dist/warnings.js +22 -0
- package/dist/warnings.js.map +1 -0
- package/dist/workdir.d.ts +17 -0
- package/dist/workdir.d.ts.map +1 -0
- package/dist/workdir.js +48 -0
- package/dist/workdir.js.map +1 -0
- package/package.json +2 -2
- package/dist/transports/manager.d.ts +0 -66
- package/dist/transports/manager.d.ts.map +0 -1
- package/dist/transports/manager.js +0 -137
- package/dist/transports/manager.js.map +0 -1
package/README.md
CHANGED
|
@@ -96,6 +96,7 @@ Matrix homeserver URL (如 https://matrix.example.com): ← 输入,如 https:/
|
|
|
96
96
|
pi 工作目录 [默认 /home/you/Projects]: ← Enter 或输入其他目录
|
|
97
97
|
实例名/机器名 [默认 debian]: ← distinguish multiple deployments; shown in the management room name
|
|
98
98
|
启用多工程模式? [y/N]: ← default N = single-project (one bot ↔ one pi); y = multi-project (management + project rooms)
|
|
99
|
+
启用空间组织? [Y/n]: ← only asked with multi-project; fresh configs default Y — all bot-created rooms are grouped into one Element space (see below)
|
|
99
100
|
|
|
100
101
|
✅ 配置已写入 ~/.pi/pi-courier.json
|
|
101
102
|
账号: @test3:...
|
|
@@ -190,7 +191,8 @@ You are now a trusted user (the first trusted user also becomes admin). Any user
|
|
|
190
191
|
|
|
191
192
|
One bot account can serve multiple projects — each project gets its own private room (named after the project), its own pi process, working directory and conversation history.
|
|
192
193
|
|
|
193
|
-
- **Management room
|
|
194
|
+
- **Management room**: with the **space feature enabled** (fresh multi-project setups default to it), the bot **creates the management room itself at startup**, inside a private Element space `pi-courier · <instance>`, and invites all trusted users — no first DM needed. With the space off (or if its creation fails), the classic behavior applies: the first room where the bot **successfully accepts (authorizes) a message** — a non-project, ≤2-person room — becomes the management room (renamed to `项目管理(<instance>)`, guide sent, room ID persisted to `config.managementRooms`). Either way the room is the admin console — `/pmctl` works only there — and its ID is stable afterwards.
|
|
195
|
+
- **Space organization (Element)**: a purely cosmetic grouping — a private space `pi-courier · <instanceName>` collects every room the bot creates (the management room and all `/pmctl new` project rooms) so they don't scatter across your room list. It never affects trust or permissions; `/pmctl rm` also removes the room from the space. Toggle it in `setup` (`启用空间组织?`, fresh configs default on, existing configs keep their current state); creation is lazy at the next start, and any failure just falls back to the unspace'd behavior with a warning and a retry on the next start. Users who pass the challenge later are invited into the space automatically (one invite per person, ever).
|
|
194
196
|
- **Create a project** (in the management room):
|
|
195
197
|
```
|
|
196
198
|
/pmctl new <name> [path]
|
|
@@ -205,7 +207,7 @@ One bot account can serve multiple projects — each project gets its own privat
|
|
|
205
207
|
/pmctl rename <name> <new> Rename (also renames the room)
|
|
206
208
|
```
|
|
207
209
|
Legacy aliases still work: `/newproject`, `/projects`.
|
|
208
|
-
- Manual setup is also possible: edit `pi-courier.json` and add a `projects` map:
|
|
210
|
+
- Manual setup is also possible: edit `pi-courier.json` and add a `projects` map (config is loaded once at startup — restart the service after manual edits):
|
|
209
211
|
```json
|
|
210
212
|
"projects": {
|
|
211
213
|
"!roomid:server": { "workdir": "/home/you/Projects/myapp" }
|
|
@@ -293,6 +295,8 @@ A: The wizard-generated config. Example:
|
|
|
293
295
|
"matrix": { "homeserverUrl": "https://matrix.example.com", "accessToken": "syt_...", "encryption": true },
|
|
294
296
|
"auth": { "trustedUsers": ["matrix:@you:matrix.example.com"], "adminUserId": "matrix:@you:matrix.example.com" },
|
|
295
297
|
"workdir": "/home/you/Projects",
|
|
298
|
+
"multiProject": true,
|
|
299
|
+
"space": { "enabled": true },
|
|
296
300
|
"autoConnect": true,
|
|
297
301
|
"debug": true
|
|
298
302
|
}
|
package/README.zh-CN.md
CHANGED
|
@@ -96,6 +96,7 @@ Matrix homeserver URL (如 https://matrix.example.com): ← 输入,如 https:/
|
|
|
96
96
|
pi 工作目录 [默认 /home/你/Projects]: ← 回车或输入其他目录
|
|
97
97
|
实例名/机器名 [默认 debian]: ← 多台部署用来区分;将显示在管理房间名
|
|
98
98
|
启用多工程模式? [y/N]: ← 默认 N=单工程(一个 bot 对应一个 pi);y=多工程(管理房间+项目房间)
|
|
99
|
+
启用空间组织? [Y/n]: ← 仅多工程时询问;全新配置默认 Y —— bot 创建的房间统一收纳进一个 Element 空间(见下文)
|
|
99
100
|
|
|
100
101
|
✅ 配置已写入 ~/.pi/pi-courier.json
|
|
101
102
|
账号: @test3:...
|
|
@@ -124,7 +125,8 @@ pi 工作目录 [默认 /home/你/Projects]: ← 回车或输
|
|
|
124
125
|
|
|
125
126
|
同一个 bot 账号可以服务多个项目 —— 每个项目一个私有房间(房间名=项目名),有独立的 pi 进程、工作目录和会话历史。
|
|
126
127
|
|
|
127
|
-
-
|
|
128
|
+
- **管理房间**:开启**空间组织**时(全新多工程配置默认开启),bot 在启动时**自行创建**管理房间 —— 位于私有空间 `pi-courier · <实例名>` 内,并邀请全部信任用户,无需先给 bot 发 DM。空间关闭(或创建失败)时沿用经典行为:bot **第一次成功受理(授权通过)的、非项目的私有/2 人房间**固化为管理房间(自动改名 `项目管理(<实例名>)` 并发送使用说明,房间 ID 写入 `config.managementRooms`)。两种路径下管理房间都是"管理台"(`/pmctl` 仅在此可用),且房间 ID 之后保持稳定。
|
|
129
|
+
- **空间组织(Element)**:纯展示层收纳 —— 私有空间 `pi-courier · <实例名>` 收集 bot 创建的所有房间(管理房间 + `/pmctl new` 的项目房间),不再散落在房间列表里。**不影响信任模型与房间权限**;`/pmctl rm` 删除项目时同步把房间移出空间。开关在 `setup`(`启用空间组织?`,全新配置默认开、已有配置保持现状);空间在下次启动时懒创建,失败仅警告并回退无空间行为、下次启动自动重试。后续通过验证码成为信任用户的用户会被自动邀请进空间(每人只邀请一次)。
|
|
128
130
|
- **创建项目**(在管理房间发):
|
|
129
131
|
```
|
|
130
132
|
/pmctl new <项目名> [路径]
|
|
@@ -139,7 +141,7 @@ pi 工作目录 [默认 /home/你/Projects]: ← 回车或输
|
|
|
139
141
|
/pmctl rename <名称> <新名> 重命名(同步改房间名)
|
|
140
142
|
```
|
|
141
143
|
旧命令别名仍可用:`/newproject`、`/projects`。
|
|
142
|
-
- **手动配置**也可以:直接编辑 `pi-courier.json` 加 `projects`
|
|
144
|
+
- **手动配置**也可以:直接编辑 `pi-courier.json` 加 `projects` 映射(配置在启动时装载一次 —— 手动编辑后需重启服务生效):
|
|
143
145
|
```json
|
|
144
146
|
"projects": {
|
|
145
147
|
"!房间ID:服务器": { "workdir": "/home/你/Projects/myapp" }
|
|
@@ -290,6 +292,8 @@ A: 向导生成的配置,示例:
|
|
|
290
292
|
"matrix": { "homeserverUrl": "https://matrix.example.com", "accessToken": "syt_...", "encryption": true },
|
|
291
293
|
"auth": { "trustedUsers": ["matrix:@你:matrix.example.com"], "adminUserId": "matrix:@你:matrix.example.com" },
|
|
292
294
|
"workdir": "/home/你/Projects",
|
|
295
|
+
"multiProject": true,
|
|
296
|
+
"space": { "enabled": true },
|
|
293
297
|
"autoConnect": true,
|
|
294
298
|
"debug": true
|
|
295
299
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin command handling for the auth engine (/trusted /revoke /channels
|
|
3
|
+
* /enable /disable /toggletools + challenge-code entry).
|
|
4
|
+
*
|
|
5
|
+
* Pure input → output: text + identity in, handled / replies /
|
|
6
|
+
* notifications / effects out. The engine's in-memory mutations happen
|
|
7
|
+
* through ChallengeAuth methods; persistence (auth snapshot, tool-call
|
|
8
|
+
* visibility) is returned as effects for the CALLER to apply through the
|
|
9
|
+
* injected config store — this module touches no disk and holds no state.
|
|
10
|
+
*/
|
|
11
|
+
import { type ChallengeAuth } from "./challenge-auth.js";
|
|
12
|
+
export type AdminEffect = {
|
|
13
|
+
kind: "persistAuth";
|
|
14
|
+
} | {
|
|
15
|
+
kind: "hideToolCalls";
|
|
16
|
+
value: boolean;
|
|
17
|
+
}
|
|
18
|
+
/** Trust was just granted to this user via a passed challenge — the caller
|
|
19
|
+
* invites them into the organizational space (fire-once, best-effort). */
|
|
20
|
+
| {
|
|
21
|
+
kind: "spaceInvite";
|
|
22
|
+
userId: string;
|
|
23
|
+
transport?: string;
|
|
24
|
+
};
|
|
25
|
+
export interface AdminNotification {
|
|
26
|
+
message: string;
|
|
27
|
+
level: "info" | "warning";
|
|
28
|
+
}
|
|
29
|
+
export interface AdminCommandInput {
|
|
30
|
+
text: string;
|
|
31
|
+
userId: string;
|
|
32
|
+
transport?: string;
|
|
33
|
+
/** Current tool-call visibility (read by the caller before dispatch). */
|
|
34
|
+
hideToolCalls?: boolean;
|
|
35
|
+
}
|
|
36
|
+
export interface AdminCommandResult {
|
|
37
|
+
handled: boolean;
|
|
38
|
+
replies: string[];
|
|
39
|
+
notifications: AdminNotification[];
|
|
40
|
+
effects: AdminEffect[];
|
|
41
|
+
}
|
|
42
|
+
/** Admin command help — the auth-owned section of the unified /help output
|
|
43
|
+
* (assembled by the command map; the management-room guide belongs to the
|
|
44
|
+
* router and pi-command help to the command map). */
|
|
45
|
+
export declare function adminCommandHelpText(): string;
|
|
46
|
+
/**
|
|
47
|
+
* Handle bridge admin commands and challenge-code entry in DMs.
|
|
48
|
+
* Returns handled: false when the text is not an admin command and no
|
|
49
|
+
* challenge validation applies (the caller then continues its pipeline).
|
|
50
|
+
*/
|
|
51
|
+
export declare function handleAdminCommand(auth: ChallengeAuth, input: AdminCommandInput): AdminCommandResult;
|
|
52
|
+
//# sourceMappingURL=admin-commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-commands.d.ts","sourceRoot":"","sources":["../../src/auth/admin-commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,KAAK,aAAa,EAAgB,MAAM,qBAAqB,CAAC;AAEvE,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE;AAC3C;2EAC2E;GACzE;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,iBAAiB,EAAE,CAAC;IACnC,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AAMD;;sDAEsD;AACtD,wBAAgB,oBAAoB,IAAI,MAAM,CAK7C;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,iBAAiB,GAAG,kBAAkB,CAwIpG"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin command handling for the auth engine (/trusted /revoke /channels
|
|
3
|
+
* /enable /disable /toggletools + challenge-code entry).
|
|
4
|
+
*
|
|
5
|
+
* Pure input → output: text + identity in, handled / replies /
|
|
6
|
+
* notifications / effects out. The engine's in-memory mutations happen
|
|
7
|
+
* through ChallengeAuth methods; persistence (auth snapshot, tool-call
|
|
8
|
+
* visibility) is returned as effects for the CALLER to apply through the
|
|
9
|
+
* injected config store — this module touches no disk and holds no state.
|
|
10
|
+
*/
|
|
11
|
+
import { namespacedId } from "./challenge-auth.js";
|
|
12
|
+
function handled(result) {
|
|
13
|
+
return { handled: true, ...result };
|
|
14
|
+
}
|
|
15
|
+
/** Admin command help — the auth-owned section of the unified /help output
|
|
16
|
+
* (assembled by the command map; the management-room guide belongs to the
|
|
17
|
+
* router and pi-command help to the command map). */
|
|
18
|
+
export function adminCommandHelpText() {
|
|
19
|
+
return [
|
|
20
|
+
"**Bridge 管理命令**: `/help`(本帮助)、`/trusted`、`/revoke`、`/channels`、`/enable`、`/disable`、`/toggletools`",
|
|
21
|
+
"**认证**: 首次私聊 bot → bot 终端显示 6 位验证码 → 在聊天里输入验证码即成为信任用户(第一个信任用户 = 管理员)。群聊由信任用户在群里发 `/enable <模式>` 启用。",
|
|
22
|
+
].join("\n");
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Handle bridge admin commands and challenge-code entry in DMs.
|
|
26
|
+
* Returns handled: false when the text is not an admin command and no
|
|
27
|
+
* challenge validation applies (the caller then continues its pipeline).
|
|
28
|
+
*/
|
|
29
|
+
export function handleAdminCommand(auth, input) {
|
|
30
|
+
const namespacedUserId = namespacedId(input.userId, input.transport);
|
|
31
|
+
// Non-admin users: challenge-code entry (only when a challenge is active).
|
|
32
|
+
if (!auth.isTrustedUser(input.userId, input.transport)) {
|
|
33
|
+
if (/^\d{6}$/.test(input.text.trim())) {
|
|
34
|
+
const outcome = auth.validateChallengeCode(namespacedUserId, input.text.trim());
|
|
35
|
+
switch (outcome) {
|
|
36
|
+
case "authenticated":
|
|
37
|
+
return handled({
|
|
38
|
+
replies: ["✅ Authenticated! You can now chat with the agent."],
|
|
39
|
+
notifications: [],
|
|
40
|
+
effects: [
|
|
41
|
+
{ kind: "persistAuth" },
|
|
42
|
+
{ kind: "spaceInvite", userId: input.userId, transport: input.transport },
|
|
43
|
+
],
|
|
44
|
+
});
|
|
45
|
+
case "expired":
|
|
46
|
+
return handled({
|
|
47
|
+
replies: ["⏱️ Challenge expired. Send any message to get a new code."],
|
|
48
|
+
notifications: [],
|
|
49
|
+
effects: [],
|
|
50
|
+
});
|
|
51
|
+
case "blocked":
|
|
52
|
+
return handled({
|
|
53
|
+
replies: ["🚫 Too many failed attempts. Blocked for 5 minutes."],
|
|
54
|
+
notifications: [],
|
|
55
|
+
effects: [],
|
|
56
|
+
});
|
|
57
|
+
case "wrong":
|
|
58
|
+
return handled({
|
|
59
|
+
replies: [`❌ Wrong code. ${auth.attemptsLeft(namespacedUserId)} attempts remaining.`],
|
|
60
|
+
notifications: [],
|
|
61
|
+
effects: [],
|
|
62
|
+
});
|
|
63
|
+
default:
|
|
64
|
+
return { handled: false, replies: [], notifications: [], effects: [] };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return { handled: false, replies: [], notifications: [], effects: [] };
|
|
68
|
+
}
|
|
69
|
+
// Admin commands
|
|
70
|
+
const parts = input.text.split(/\s+/);
|
|
71
|
+
const cmd = parts[0].toLowerCase();
|
|
72
|
+
switch (cmd) {
|
|
73
|
+
case "/enable": {
|
|
74
|
+
if (parts.length < 3) {
|
|
75
|
+
return handled({ replies: ["Usage: /enable <chatId> <all|mentions|trusted-only>"], notifications: [], effects: [] });
|
|
76
|
+
}
|
|
77
|
+
const mode = parts[2];
|
|
78
|
+
if (mode !== "all" && mode !== "mentions" && mode !== "trusted-only") {
|
|
79
|
+
return handled({ replies: ["Usage: /enable <chatId> <all|mentions|trusted-only>"], notifications: [], effects: [] });
|
|
80
|
+
}
|
|
81
|
+
auth.enableChannel(parts[1], mode);
|
|
82
|
+
return handled({
|
|
83
|
+
replies: [`✅ Channel ${parts[1]} enabled (mode: ${parts[2]})`],
|
|
84
|
+
notifications: [{ message: `Channel ${parts[1]} enabled (${parts[2]})`, level: "info" }],
|
|
85
|
+
effects: [{ kind: "persistAuth" }],
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
case "/disable": {
|
|
89
|
+
if (parts.length < 2) {
|
|
90
|
+
return handled({ replies: ["Usage: /disable <chatId>"], notifications: [], effects: [] });
|
|
91
|
+
}
|
|
92
|
+
auth.disableChannel(parts[1]);
|
|
93
|
+
return handled({
|
|
94
|
+
replies: [`❌ Channel ${parts[1]} disabled`],
|
|
95
|
+
notifications: [{ message: `Channel ${parts[1]} disabled`, level: "info" }],
|
|
96
|
+
effects: [{ kind: "persistAuth" }],
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
case "/channels": {
|
|
100
|
+
const channels = auth
|
|
101
|
+
.exportConfig()
|
|
102
|
+
.channels;
|
|
103
|
+
const lines = Object.entries(channels).map(([id, channel]) => `• ${id}: ${channel.enabled ? "✅" : "❌"} (${channel.mode})`);
|
|
104
|
+
return handled({ replies: [lines.join("\n") || "No channels configured"], notifications: [], effects: [] });
|
|
105
|
+
}
|
|
106
|
+
case "/trusted": {
|
|
107
|
+
const snapshot = auth.exportConfig();
|
|
108
|
+
const trusted = snapshot.trustedUsers
|
|
109
|
+
.map((id) => {
|
|
110
|
+
const [transport, uid] = id.split(":");
|
|
111
|
+
return uid ? `${uid} (${transport})` : id;
|
|
112
|
+
})
|
|
113
|
+
.join(", ");
|
|
114
|
+
return handled({
|
|
115
|
+
replies: [`Trusted users (${snapshot.trustedUsers.length}):\n${trusted || "None"}`],
|
|
116
|
+
notifications: [],
|
|
117
|
+
effects: [],
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
case "/toggletools": {
|
|
121
|
+
const next = !input.hideToolCalls;
|
|
122
|
+
return handled({
|
|
123
|
+
replies: [`🔧 Tool calls ${next ? "hidden" : "shown"} in remote messages`],
|
|
124
|
+
notifications: [],
|
|
125
|
+
effects: [{ kind: "hideToolCalls", value: next }],
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
case "/revoke": {
|
|
129
|
+
if (parts.length < 2) {
|
|
130
|
+
return handled({
|
|
131
|
+
replies: ["Usage: /revoke <userId> or /revoke <transport:userId>"],
|
|
132
|
+
notifications: [],
|
|
133
|
+
effects: [],
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
const revokeId = parts[1];
|
|
137
|
+
const revoked = auth.revokeUser(revokeId);
|
|
138
|
+
if (revoked) {
|
|
139
|
+
return handled({
|
|
140
|
+
replies: [`🔓 Revoked trust for ${revokeId}`],
|
|
141
|
+
notifications: [{ message: `Revoked: ${revokeId}`, level: "warning" }],
|
|
142
|
+
effects: [{ kind: "persistAuth" }],
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return handled({
|
|
146
|
+
replies: [`❌ User ${revokeId} not found in trusted users`],
|
|
147
|
+
notifications: [],
|
|
148
|
+
effects: [],
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
default:
|
|
152
|
+
return { handled: false, replies: [], notifications: [], effects: [] };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=admin-commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-commands.js","sourceRoot":"","sources":["../../src/auth/admin-commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,21 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Challenge-based authentication
|
|
3
|
-
* Ported from vscode-chonky-remote-pilot
|
|
2
|
+
* Challenge-based authentication strategy engine.
|
|
3
|
+
* Ported from vscode-chonky-remote-pilot.
|
|
4
|
+
*
|
|
5
|
+
* Pure strategy: authorization decisions, challenge lifecycle, channel modes
|
|
6
|
+
* and trust state — every method either reads state, mutates it in memory, or
|
|
7
|
+
* (for the challenge prompt) sends through the sender passed as a parameter.
|
|
8
|
+
* No persistence and no admin-command handling happens here: the caller
|
|
9
|
+
* applies persistence effects (see admin-commands.ts) through the injected
|
|
10
|
+
* config store.
|
|
4
11
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
12
|
+
export type ChallengeOutcome = "authenticated" | "expired" | "wrong" | "blocked";
|
|
13
|
+
/** Per-transport identity key (`transport:userId`) — the single namespacing
|
|
14
|
+
* implementation for runtime identity: trust/admin lookups, challenge
|
|
15
|
+
* storage and admin-command handling all key off it. (Config-storage
|
|
16
|
+
* boundaries — the matrix env vars and setup — write the transport-prefixed
|
|
17
|
+
* form directly; display-side splits are the inverse operation.)
|
|
7
18
|
*/
|
|
19
|
+
export declare function namespacedId(userId: string, transport?: string): string;
|
|
8
20
|
export declare class ChallengeAuth {
|
|
9
21
|
private onShowCode;
|
|
10
22
|
private onNotify;
|
|
11
|
-
private onSendMessage?;
|
|
12
|
-
private onSaveAuth?;
|
|
13
23
|
private challenges;
|
|
14
24
|
private trustedUsers;
|
|
15
25
|
private channelAuth;
|
|
16
26
|
private blockedUsers;
|
|
17
27
|
private adminUserId?;
|
|
18
|
-
constructor(onShowCode: (code: string, username: string) => void, onNotify: (message: string, level?: "info" | "warning" | "error") => void
|
|
28
|
+
constructor(onShowCode: (code: string, username: string) => void, onNotify: (message: string, level?: "info" | "warning" | "error") => void);
|
|
19
29
|
/**
|
|
20
30
|
* Initialize auth state from config
|
|
21
31
|
*/
|
|
@@ -39,44 +49,41 @@ export declare class ChallengeAuth {
|
|
|
39
49
|
}>;
|
|
40
50
|
};
|
|
41
51
|
/**
|
|
42
|
-
* Check if a user is authorized to send messages
|
|
43
|
-
*
|
|
52
|
+
* Check if a user is authorized to send messages. Unknown DM users get a
|
|
53
|
+
* challenge; the prompt goes out through the sender passed here — the
|
|
54
|
+
* engine never stores a sender on itself.
|
|
44
55
|
*/
|
|
45
56
|
checkAuthorization(userId: string, chatId: string, username: string, isGroupChat: boolean, wasMentioned: boolean, sendMessage?: (chatId: string, message: string) => Promise<void>, transport?: string): Promise<boolean>;
|
|
46
57
|
/** Whether a user is in the trusted list (per transport). */
|
|
47
58
|
isTrustedUser(userId: string, transport?: string): boolean;
|
|
59
|
+
/** Whether this user is the admin (namespaced comparison, per transport). */
|
|
60
|
+
isAdminUser(userId: string, transport?: string): boolean;
|
|
48
61
|
/** Whether a group chat has been explicitly enabled by the admin. */
|
|
49
62
|
isChannelEnabled(chatId: string): boolean;
|
|
50
|
-
/** Enable a group chat with a mode (
|
|
63
|
+
/** Enable a group chat with a mode (in-memory only; the caller persists). */
|
|
51
64
|
enableChannel(chatId: string, mode: "all" | "mentions" | "trusted-only"): void;
|
|
65
|
+
/** Disable a group chat (in-memory only; the caller persists). */
|
|
66
|
+
disableChannel(chatId: string): void;
|
|
67
|
+
/** Revoke trust. Matching rule: full namespaced IDs (or exact entries)
|
|
68
|
+
* match exactly; any other form — bare telegram IDs AND native MXIDs as
|
|
69
|
+
* displayed by /trusted — matches the `:<id>` suffix of one entry.
|
|
70
|
+
* Returns whether anything was revoked. */
|
|
71
|
+
revokeUser(revokeId: string): boolean;
|
|
52
72
|
/**
|
|
53
|
-
*
|
|
73
|
+
* Validate a challenge code. Mutates trust/blocked/challenge state and
|
|
74
|
+
* returns the outcome — the caller turns it into replies and persistence.
|
|
54
75
|
*/
|
|
55
|
-
|
|
76
|
+
validateChallengeCode(namespacedUserId: string, code: string): ChallengeOutcome | "none";
|
|
77
|
+
/** Attempts left on the active challenge (0 when none/blocked). */
|
|
78
|
+
attemptsLeft(namespacedUserId: string): number;
|
|
56
79
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
80
|
+
* Initiate or re-check a challenge for a DM user. Returns false (the user
|
|
81
|
+
* is not yet authorized); the prompt is delivered via the sender argument.
|
|
59
82
|
*/
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Validate a challenge code entered by the user
|
|
63
|
-
*/
|
|
64
|
-
private validateChallenge;
|
|
83
|
+
private initiateChallenge;
|
|
65
84
|
/**
|
|
66
85
|
* Generate a random 6-digit code
|
|
67
86
|
*/
|
|
68
87
|
private generateCode;
|
|
69
|
-
/**
|
|
70
|
-
* Get help text for admin commands
|
|
71
|
-
*/
|
|
72
|
-
private getHelpText;
|
|
73
|
-
/**
|
|
74
|
-
* Get current stats with detailed user info
|
|
75
|
-
*/
|
|
76
|
-
getStats(): {
|
|
77
|
-
trustedUsers: number;
|
|
78
|
-
channels: number;
|
|
79
|
-
usersByTransport: Record<string, string[]>;
|
|
80
|
-
};
|
|
81
88
|
}
|
|
82
89
|
//# sourceMappingURL=challenge-auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"challenge-auth.d.ts","sourceRoot":"","sources":["../../src/auth/challenge-auth.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"challenge-auth.d.ts","sourceRoot":"","sources":["../../src/auth/challenge-auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAgBH,MAAM,MAAM,gBAAgB,GAAG,eAAe,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AAEjF;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED,qBAAa,aAAa;IAQtB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,QAAQ;IARlB,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,WAAW,CAAC,CAAS;gBAGnB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,EACpD,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,KAAK,IAAI;IAGnF;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE;QACrB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,IAAI,EAAE,KAAK,GAAG,UAAU,GAAG,cAAc,CAAA;SAAE,CAAC,CAAC;KAC5F,GAAG,IAAI;IAYR;;OAEG;IACH,YAAY,IAAI;QACd,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,IAAI,EAAE,KAAK,GAAG,UAAU,GAAG,cAAc,CAAA;SAAE,CAAC,CAAC;KAC3F;IAQD;;;;OAIG;IACG,kBAAkB,CACtB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,OAAO,EACpB,YAAY,EAAE,OAAO,EACrB,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,EAChE,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC;IAgDnB,6DAA6D;IAC7D,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO;IAK1D,6EAA6E;IAC7E,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO;IAMxD,qEAAqE;IACrE,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIzC,6EAA6E;IAC7E,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,UAAU,GAAG,cAAc,GAAG,IAAI;IAI9E,kEAAkE;IAClE,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIpC;;;gDAG4C;IAC5C,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAcrC;;;OAGG;IACH,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,MAAM;IA8BxF,mEAAmE;IACnE,YAAY,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM;IAK9C;;;OAGG;YACW,iBAAiB;IAgD/B;;OAEG;IACH,OAAO,CAAC,YAAY;CAGrB"}
|