pi-courier 0.1.35 → 0.1.37
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 +14 -6
- package/README.zh-CN.md +8 -5
- package/dist/auth/admin-commands.d.ts +18 -0
- package/dist/auth/admin-commands.d.ts.map +1 -1
- package/dist/auth/admin-commands.js +15 -1
- package/dist/auth/admin-commands.js.map +1 -1
- package/dist/cli.js +54 -24
- package/dist/cli.js.map +1 -1
- package/dist/log-filter.d.ts +37 -0
- package/dist/log-filter.d.ts.map +1 -0
- package/dist/log-filter.js +63 -0
- package/dist/log-filter.js.map +1 -0
- package/dist/logger.d.ts +9 -3
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +27 -7
- package/dist/logger.js.map +1 -1
- package/dist/project-labels.d.ts +28 -0
- package/dist/project-labels.d.ts.map +1 -0
- package/dist/project-labels.js +44 -0
- package/dist/project-labels.js.map +1 -0
- package/dist/rpc/message-router.d.ts.map +1 -1
- package/dist/rpc/message-router.js +47 -25
- package/dist/rpc/message-router.js.map +1 -1
- package/dist/rpc/pi-rpc.d.ts +5 -0
- package/dist/rpc/pi-rpc.d.ts.map +1 -1
- package/dist/rpc/pi-rpc.js +4 -0
- package/dist/rpc/pi-rpc.js.map +1 -1
- package/dist/rpc/pmctl-controller.d.ts +5 -0
- package/dist/rpc/pmctl-controller.d.ts.map +1 -1
- package/dist/rpc/pmctl-controller.js +40 -12
- package/dist/rpc/pmctl-controller.js.map +1 -1
- package/dist/rpc/project-manager.d.ts +7 -0
- package/dist/rpc/project-manager.d.ts.map +1 -1
- package/dist/rpc/project-manager.js +32 -6
- package/dist/rpc/project-manager.js.map +1 -1
- package/dist/space.d.ts +72 -7
- package/dist/space.d.ts.map +1 -1
- package/dist/space.js +185 -9
- package/dist/space.js.map +1 -1
- package/dist/standalone.d.ts.map +1 -1
- package/dist/standalone.js +24 -15
- package/dist/standalone.js.map +1 -1
- package/dist/transports/interface.d.ts +11 -3
- package/dist/transports/interface.d.ts.map +1 -1
- package/dist/transports/matrix-rooms.d.ts +6 -2
- package/dist/transports/matrix-rooms.d.ts.map +1 -1
- package/dist/transports/matrix-rooms.js +18 -1
- package/dist/transports/matrix-rooms.js.map +1 -1
- package/dist/types.d.ts +14 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -151,7 +151,7 @@ You can chat normally right away:
|
|
|
151
151
|
[2026-08-06T02:38:57.884Z] [INFO] [agent] 回复 @barry: 你好!收到,我在线。...
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
-
You are now a trusted user (the first trusted user also becomes admin). Any user not in `auth.trustedUsers` goes through this flow once; pre-listed users skip it entirely.
|
|
154
|
+
You are now a trusted user (the first trusted user also becomes admin). In multi-project mode trusted users are also invited into the management room automatically and hold admin power in every room the bot manages — see [Multi-project rooms](#multi-project-rooms-project-isolation). Any user not in `auth.trustedUsers` goes through this flow once; pre-listed users skip it entirely.
|
|
155
155
|
|
|
156
156
|
**Then** chat normally, or send commands:
|
|
157
157
|
|
|
@@ -191,8 +191,9 @@ You are now a trusted user (the first trusted user also becomes admin). Any user
|
|
|
191
191
|
|
|
192
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.
|
|
193
193
|
|
|
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.
|
|
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; trusted users who join via the challenge later are invited into the management room automatically (one invite per person, failures retried by the next-start self-heal). 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. The space itself takes no part in authorization — who may send commands and who holds which room permissions is decided by the permission model below. `/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).
|
|
196
|
+
- **Permission model (trusted = admin)**: trusted users automatically hold **admin power** (PL 100) in every room the bot manages — the space, the management room and all project rooms — regardless of whether trust came from setup or the challenge, and regardless of membership (late joiners arrive with the level already in place). `/revoke <userId>` strips that admin power in every managed room at the same time (back to plain member); a failed demotion is retried by the next-start self-heal. Zero configuration — the first start after upgrading heals existing rooms too. Admins promoted by the pre-0.1.37 special case (project-room creator) are not in the demotion ledger: `/revoke` still demotes them on the spot, and only if that on-the-spot demotion fails do you need to lower them manually once in your client.
|
|
196
197
|
- **Create a project** (in the management room):
|
|
197
198
|
```
|
|
198
199
|
/pmctl new <name> [path]
|
|
@@ -218,8 +219,10 @@ One bot account can serve multiple projects — each project gets its own privat
|
|
|
218
219
|
### Managing the service
|
|
219
220
|
|
|
220
221
|
```bash
|
|
221
|
-
pi-courier status # status + recent logs
|
|
222
|
+
pi-courier status # status + recent logs (optionally: pi-courier status <project>)
|
|
222
223
|
pi-courier logs # tail logs (INFO and above)
|
|
224
|
+
pi-courier logs ai-api # multi-project: only this project's tagged lines
|
|
225
|
+
pi-courier logs ai-api www --level debug # several projects, full detail
|
|
223
226
|
pi-courier logs --level debug # tail ALL logs (incl. thinking, stream deltas)
|
|
224
227
|
pi-courier logs --level error # errors only
|
|
225
228
|
pi-courier run --level debug # foreground with full detail
|
|
@@ -233,8 +236,13 @@ pi-courier -v # show the installed version
|
|
|
233
236
|
|
|
234
237
|
Log levels: `debug < info < warn < error`. The service writes everything;
|
|
235
238
|
`logs` shows INFO+ by default, `--level debug` shows the full session replay
|
|
236
|
-
(user messages, thinking, tool calls, replies).
|
|
237
|
-
|
|
239
|
+
(user messages, thinking, tool calls, replies). In multi-project mode every
|
|
240
|
+
project-related line carries a `[project]` tag, and `logs <project>` filters
|
|
241
|
+
by it (case-insensitive; project = the `/pmctl` name, or the working
|
|
242
|
+
directory's name when the project is unnamed). Filtering runs through
|
|
243
|
+
`journalctl --grep` — it requires journald with PCRE2 support (standard on
|
|
244
|
+
Debian/Ubuntu). The complete conversation is always stored in pi's session
|
|
245
|
+
files (`~/.pi/agent/sessions/`).
|
|
238
246
|
|
|
239
247
|
Upgrading **pi** is independent — pi-courier always uses the system pi via `which pi`:
|
|
240
248
|
|
package/README.zh-CN.md
CHANGED
|
@@ -125,8 +125,9 @@ pi 工作目录 [默认 /home/你/Projects]: ← 回车或输
|
|
|
125
125
|
|
|
126
126
|
同一个 bot 账号可以服务多个项目 —— 每个项目一个私有房间(房间名=项目名),有独立的 pi 进程、工作目录和会话历史。
|
|
127
127
|
|
|
128
|
-
- **管理房间**:开启**空间组织**时(全新多工程配置默认开启),bot 在启动时**自行创建**管理房间 —— 位于私有空间 `pi-courier · <实例名>` 内,并邀请全部信任用户,无需先给 bot 发 DM。空间关闭(或创建失败)时沿用经典行为:bot **第一次成功受理(授权通过)的、非项目的私有/2 人房间**固化为管理房间(自动改名 `项目管理(<实例名>)` 并发送使用说明,房间 ID 写入 `config.managementRooms`)。两种路径下管理房间都是"管理台"(`/pmctl` 仅在此可用),且房间 ID 之后保持稳定。
|
|
129
|
-
- **空间组织(Element)**:纯展示层收纳 —— 私有空间 `pi-courier · <实例名>` 收集 bot 创建的所有房间(管理房间 + `/pmctl new` 的项目房间)
|
|
128
|
+
- **管理房间**:开启**空间组织**时(全新多工程配置默认开启),bot 在启动时**自行创建**管理房间 —— 位于私有空间 `pi-courier · <实例名>` 内,并邀请全部信任用户,无需先给 bot 发 DM;后续经验证码加入的信任用户也会被自动邀请进管理房间(每人只邀一次,失败由下次启动自愈重试)。空间关闭(或创建失败)时沿用经典行为:bot **第一次成功受理(授权通过)的、非项目的私有/2 人房间**固化为管理房间(自动改名 `项目管理(<实例名>)` 并发送使用说明,房间 ID 写入 `config.managementRooms`)。两种路径下管理房间都是"管理台"(`/pmctl` 仅在此可用),且房间 ID 之后保持稳定。
|
|
129
|
+
- **空间组织(Element)**:纯展示层收纳 —— 私有空间 `pi-courier · <实例名>` 收集 bot 创建的所有房间(管理房间 + `/pmctl new` 的项目房间),不再散落在房间列表里;空间本身不参与授权判定——谁能发命令、谁有什么房间权限,由下面的权限模型决定。`/pmctl rm` 删除项目时同步把房间移出空间。开关在 `setup`(`启用空间组织?`,全新配置默认开、已有配置保持现状);空间在下次启动时懒创建,失败仅警告并回退无空间行为、下次启动自动重试。后续通过验证码成为信任用户的用户会被自动邀请进空间(每人只邀请一次)。
|
|
130
|
+
- **权限模型(信任即管理员)**:信任用户在 bot 托管的所有房间——空间、管理房间、全部项目房间——自动拥有**管理员权限**(PL 100):无论信任来自 setup 还是验证码、是否已加入该房间(后加入者进房时权限已就位)。`/revoke <userId>` 撤销信任时,该用户在全部托管房间的管理员权限**同步收回**(降回普通级别),降权失败由下次启动自愈兜底。零配置,升级后的首次启动自动补齐存量房间;旧版本(≤0.1.36)由旧特例(项目房间创建者提权)成为管理员的用户不在降权簿记内——`/revoke` 仍会即时对其降权,仅当那次即时降权也失败时才需在客户端手动降一次。
|
|
130
131
|
- **创建项目**(在管理房间发):
|
|
131
132
|
```
|
|
132
133
|
/pmctl new <项目名> [路径]
|
|
@@ -191,7 +192,7 @@ pi-courier enable # 安装 systemd 服务:开机自启 + 立即启动
|
|
|
191
192
|
[2026-08-06T02:38:57.884Z] [INFO] [agent] 回复 @barry: 你好!收到,我在线。...
|
|
192
193
|
```
|
|
193
194
|
|
|
194
|
-
你就成为 trusted user(第一个 trusted 用户自动成为管理员)。不在 `auth.trustedUsers` 里的用户都会走一次这个流程;预信任用户完全跳过。
|
|
195
|
+
你就成为 trusted user(第一个 trusted 用户自动成为管理员)。多工程模式下,信任用户还会被自动邀请进管理房间,并在 bot 托管的所有房间自动获得管理员权限——见[多项目房间](#多项目房间项目隔离)。不在 `auth.trustedUsers` 里的用户都会走一次这个流程;预信任用户完全跳过。
|
|
195
196
|
|
|
196
197
|
**之后**正常对话,或发命令:
|
|
197
198
|
|
|
@@ -218,8 +219,10 @@ pi-courier enable # 安装 systemd 服务:开机自启 + 立即启动
|
|
|
218
219
|
### 服务管理
|
|
219
220
|
|
|
220
221
|
```bash
|
|
221
|
-
pi-courier status # 状态 + 最近日志
|
|
222
|
+
pi-courier status # 状态 + 最近日志(可加项目名:pi-courier status <项目>)
|
|
222
223
|
pi-courier logs # 跟踪日志(INFO 及以上)
|
|
224
|
+
pi-courier logs ai-api # 多工程:只看该项目的打标日志
|
|
225
|
+
pi-courier logs ai-api www --level debug # 多项目 + 全量细节
|
|
223
226
|
pi-courier logs --level debug # 跟踪全部日志(含思考、流式增量)
|
|
224
227
|
pi-courier logs --level error # 只看错误
|
|
225
228
|
pi-courier run --level debug # 前台运行,全量显示
|
|
@@ -231,7 +234,7 @@ pi-courier update # 更新 pi-courier 自身
|
|
|
231
234
|
pi-courier -v # 显示当前版本(--version/version 亦可)
|
|
232
235
|
```
|
|
233
236
|
|
|
234
|
-
日志级别:`debug < info < warn < error`。服务会把全部内容写入日志;`logs` 默认显示 INFO 及以上,`--level debug` 显示完整会话回放(用户消息、思考、工具调用、回复)。完整对话始终保存在 pi 的会话文件(`~/.pi/agent/sessions/`)。
|
|
237
|
+
日志级别:`debug < info < warn < error`。服务会把全部内容写入日志;`logs` 默认显示 INFO 及以上,`--level debug` 显示完整会话回放(用户消息、思考、工具调用、回复)。多工程模式下,项目相关日志行带有 `[项目名]` 标签,`logs <项目名>` 即可只看该工程(大小写不敏感;项目名 = `/pmctl` 的名称,未命名时为工作目录的目录名)。过滤经 `journalctl --grep` 实现,要求 journald 支持 PCRE2(Debian/Ubuntu 标准支持)。完整对话始终保存在 pi 的会话文件(`~/.pi/agent/sessions/`)。
|
|
235
238
|
|
|
236
239
|
**升级 pi** 是独立的事 —— pi-courier 始终通过 `which pi` 连接系统 pi:
|
|
237
240
|
|
|
@@ -21,6 +21,24 @@ export type AdminEffect = {
|
|
|
21
21
|
kind: "spaceInvite";
|
|
22
22
|
userId: string;
|
|
23
23
|
transport?: string;
|
|
24
|
+
}
|
|
25
|
+
/** Trust was just granted to this user via a passed challenge — the caller
|
|
26
|
+
* also invites them into the management room (where /pmctl lives;
|
|
27
|
+
* fire-once, best-effort, space mode only). */
|
|
28
|
+
| {
|
|
29
|
+
kind: "managementRoomInvite";
|
|
30
|
+
userId: string;
|
|
31
|
+
transport?: string;
|
|
32
|
+
}
|
|
33
|
+
/** Trust was just revoked from this user — the caller strips the admin
|
|
34
|
+
* power this instance once granted (every managed room, PL 0; best-effort,
|
|
35
|
+
* see demoteTrustedUserEverywhere). The userId arrives in the stored
|
|
36
|
+
* namespaced form ("matrix:@user:server") so the demotion hits the right
|
|
37
|
+
* MXID however the admin spelled the command argument. */
|
|
38
|
+
| {
|
|
39
|
+
kind: "powerDemote";
|
|
40
|
+
userId: string;
|
|
41
|
+
transport?: string;
|
|
24
42
|
};
|
|
25
43
|
export interface AdminNotification {
|
|
26
44
|
message: string;
|
|
@@ -1 +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,
|
|
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;AAC7D;;gDAEgD;GAC9C;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;AACtE;;;;2DAI2D;GACzD;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,CAsJpG"}
|
|
@@ -40,6 +40,7 @@ export function handleAdminCommand(auth, input) {
|
|
|
40
40
|
effects: [
|
|
41
41
|
{ kind: "persistAuth" },
|
|
42
42
|
{ kind: "spaceInvite", userId: input.userId, transport: input.transport },
|
|
43
|
+
{ kind: "managementRoomInvite", userId: input.userId, transport: input.transport },
|
|
43
44
|
],
|
|
44
45
|
});
|
|
45
46
|
case "expired":
|
|
@@ -134,12 +135,25 @@ export function handleAdminCommand(auth, input) {
|
|
|
134
135
|
});
|
|
135
136
|
}
|
|
136
137
|
const revokeId = parts[1];
|
|
138
|
+
// Capture the stored entry the revoke removes so the demotion effect can
|
|
139
|
+
// carry it in its canonical namespaced form — the command argument may be
|
|
140
|
+
// a bare display id (revokeUser also matches ":<id>" suffixes).
|
|
141
|
+
const trustedBefore = auth.exportConfig().trustedUsers;
|
|
137
142
|
const revoked = auth.revokeUser(revokeId);
|
|
138
143
|
if (revoked) {
|
|
144
|
+
const removed = trustedBefore.find((id) => !auth.exportConfig().trustedUsers.includes(id));
|
|
145
|
+
const effects = [{ kind: "persistAuth" }];
|
|
146
|
+
if (removed) {
|
|
147
|
+
// Symmetric closed loop (ticket 3, issue #44): whoever was elevated
|
|
148
|
+
// on trust gets demoted everywhere on revoke. Best-effort, same
|
|
149
|
+
// failure semantics as the invite effects — a failed demotion never
|
|
150
|
+
// un-revokes and never changes the reply.
|
|
151
|
+
effects.push({ kind: "powerDemote", userId: removed });
|
|
152
|
+
}
|
|
139
153
|
return handled({
|
|
140
154
|
replies: [`🔓 Revoked trust for ${revokeId}`],
|
|
141
155
|
notifications: [{ message: `Revoked: ${revokeId}`, level: "warning" }],
|
|
142
|
-
effects
|
|
156
|
+
effects,
|
|
143
157
|
});
|
|
144
158
|
}
|
|
145
159
|
return handled({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-commands.js","sourceRoot":"","sources":["../../src/auth/admin-commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAsB,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"admin-commands.js","sourceRoot":"","sources":["../../src/auth/admin-commands.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* pi-courier enable install a user-level systemd service (auto-start) and start it
|
|
9
9
|
* pi-courier start start the systemd service
|
|
10
10
|
* pi-courier stop stop the systemd service
|
|
11
|
-
* pi-courier status show service status + recent logs
|
|
12
|
-
* pi-courier logs tail the service logs
|
|
11
|
+
* pi-courier status show service status + recent logs (optional project filter)
|
|
12
|
+
* pi-courier logs tail the service logs (optional: <project...> [--level])
|
|
13
13
|
* pi-courier update update this project (git pull + npm install + build)
|
|
14
14
|
* pi-courier -v show the installed version (--version / version)
|
|
15
15
|
*
|
|
@@ -22,6 +22,8 @@ import * as os from "node:os";
|
|
|
22
22
|
import * as path from "node:path";
|
|
23
23
|
import { fileURLToPath } from "node:url";
|
|
24
24
|
import { loadConfig } from "./config.js";
|
|
25
|
+
import { buildLogFilterArgs } from "./log-filter.js";
|
|
26
|
+
import { projectLabelOf } from "./project-labels.js";
|
|
25
27
|
import { suppressKnownWarnings } from "./warnings.js";
|
|
26
28
|
suppressKnownWarnings();
|
|
27
29
|
const SERVICE_NAME = "pi-courier";
|
|
@@ -68,8 +70,9 @@ function usage() {
|
|
|
68
70
|
pi-courier start 启动服务
|
|
69
71
|
pi-courier stop 停止服务
|
|
70
72
|
pi-courier restart 重启服务
|
|
71
|
-
pi-courier status 查看服务状态与最近日志
|
|
72
|
-
pi-courier logs 跟踪服务日志(Ctrl+C 退出)
|
|
73
|
+
pi-courier status 查看服务状态与最近日志(可带项目名过滤)
|
|
74
|
+
pi-courier logs 跟踪服务日志(Ctrl+C 退出);多工程下可加项目名过滤:
|
|
75
|
+
pi-courier logs <项目> [项目...] [--level debug|info|warn|error]
|
|
73
76
|
pi-courier disable 卸载服务(停止 + 取消自启 + 删除 unit 文件)
|
|
74
77
|
pi-courier update 更新本项目(git pull + 安装依赖 + 重新构建)
|
|
75
78
|
pi-courier -v 显示版本号(--version / version 亦可)
|
|
@@ -151,38 +154,65 @@ function runSystemctl(args) {
|
|
|
151
154
|
process.exit(res.status ?? 1);
|
|
152
155
|
}
|
|
153
156
|
}
|
|
157
|
+
/** Project labels from the config (the single source `log-filter` matches against). */
|
|
158
|
+
function projectLabels() {
|
|
159
|
+
const config = loadConfig();
|
|
160
|
+
const projects = config.projects ?? {};
|
|
161
|
+
return { labels: Object.values(projects).map((p) => projectLabelOf(p)), multiProject: config.multiProject === true };
|
|
162
|
+
}
|
|
154
163
|
function cmdService(action, args = []) {
|
|
155
164
|
const unitPath = userUnitPath();
|
|
156
165
|
if (!fs.existsSync(unitPath)) {
|
|
157
166
|
console.error(`❌ 服务未安装。先运行 \`pi-courier enable\` 安装。`);
|
|
158
167
|
process.exit(1);
|
|
159
168
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
169
|
+
if (action === "logs" || action === "status") {
|
|
170
|
+
// status first shows the unit itself (systemctl), then the log window.
|
|
171
|
+
if (action === "status") {
|
|
172
|
+
spawnSync("systemctl", ["--user", "status", SERVICE_NAME], { stdio: "inherit" });
|
|
173
|
+
}
|
|
174
|
+
// Split args: `--level <lvl>` option vs positional project labels.
|
|
163
175
|
let level = "info";
|
|
176
|
+
const positional = [];
|
|
164
177
|
for (let i = 0; i < args.length; i++) {
|
|
165
178
|
if (args[i] === "--level")
|
|
166
|
-
level = args[++i] ??
|
|
179
|
+
level = args[++i] ?? "";
|
|
180
|
+
else
|
|
181
|
+
positional.push(args[i]);
|
|
167
182
|
}
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
183
|
+
const { labels, multiProject } = projectLabels();
|
|
184
|
+
// Single-project mode tags nothing, so a project filter can never match —
|
|
185
|
+
// say so instead of silently presenting an empty view (spec #34).
|
|
186
|
+
if (positional.length > 0 && !multiProject) {
|
|
187
|
+
console.error("❌ 当前为单工程模式,日志不区分项目(多工程模式才打项目标签)。");
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
const filter = buildLogFilterArgs({
|
|
191
|
+
unit: SERVICE_NAME,
|
|
192
|
+
availableLabels: labels,
|
|
193
|
+
requestedProjects: positional,
|
|
194
|
+
level,
|
|
195
|
+
follow: action === "logs",
|
|
196
|
+
lineCount: action === "status" ? 15 : undefined,
|
|
197
|
+
});
|
|
198
|
+
if (!filter.ok) {
|
|
199
|
+
console.error(`❌ ${filter.message}`);
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
202
|
+
const journalArgs = action === "status" ? ["--no-pager", ...filter.args] : filter.args;
|
|
203
|
+
const res = spawnSync("journalctl", journalArgs, { stdio: "inherit" });
|
|
204
|
+
// logs runs in follow mode: Ctrl+C can surface a non-zero exit — ignore it
|
|
205
|
+
// (same tolerance as before); status's window exit is meaningful.
|
|
206
|
+
if (res.status !== 0 && action === "status") {
|
|
207
|
+
process.exit(res.status ?? 1);
|
|
208
|
+
}
|
|
209
|
+
return;
|
|
173
210
|
}
|
|
211
|
+
const cmd = ["systemctl", "--user", action, SERVICE_NAME];
|
|
174
212
|
const res = spawnSync(cmd[0], cmd.slice(1), { stdio: "inherit" });
|
|
175
|
-
if (res.status !== 0
|
|
213
|
+
if (res.status !== 0) {
|
|
176
214
|
process.exit(res.status ?? 1);
|
|
177
215
|
}
|
|
178
|
-
if (action === "status") {
|
|
179
|
-
// Append recent logs for convenience
|
|
180
|
-
const logs = spawnSync("journalctl", ["--user", "-u", SERVICE_NAME, "-n", "15", "--no-pager"], {
|
|
181
|
-
encoding: "utf-8",
|
|
182
|
-
});
|
|
183
|
-
if (logs.stdout)
|
|
184
|
-
console.log(logs.stdout);
|
|
185
|
-
}
|
|
186
216
|
}
|
|
187
217
|
function cmdDisable() {
|
|
188
218
|
const unitPath = userUnitPath();
|
|
@@ -283,11 +313,11 @@ async function main() {
|
|
|
283
313
|
case "start":
|
|
284
314
|
case "stop":
|
|
285
315
|
case "restart":
|
|
286
|
-
case "status":
|
|
287
316
|
cmdService(cmd);
|
|
288
317
|
break;
|
|
318
|
+
case "status":
|
|
289
319
|
case "logs":
|
|
290
|
-
cmdService(
|
|
320
|
+
cmdService(cmd, rest);
|
|
291
321
|
break;
|
|
292
322
|
case "disable":
|
|
293
323
|
cmdDisable();
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEtD,qBAAqB,EAAE,CAAC;AAExB,MAAM,YAAY,GAAG,YAAY,CAAC;AAClC,MAAM,YAAY,GAAG,GAAG,YAAY,UAAU,CAAC;AAE/C,+DAA+D;AAC/D,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAyB,CAAC;QAClH,OAAO,GAAG,CAAC,OAAO,IAAI,SAAS,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,SAAS,UAAU;IACjB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AAC1E,CAAC;AAED;;;;;GAKG;AACH,SAAS,qBAAqB;IAC5B,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC;IACjG,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,aAAa,EAAE,0BAA0B,CAAC,CAAC;IAC7F,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/C,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,KAAK;IACZ,OAAO,CAAC,GAAG,CAAC
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* log-filter — the pure argv builder behind `pi-courier logs/status` (spec #34).
|
|
3
|
+
*
|
|
4
|
+
* Journal filtering works on the LINE, not on journald fields: custom stdout
|
|
5
|
+
* field assignments (PROJECT=…) are not parsed by journald (measured on
|
|
6
|
+
* systemd 257), and the `PRIORITY` field is useless under the default
|
|
7
|
+
* `StandardOutput=inherit` (every line lands at 6) — which is why the old
|
|
8
|
+
* `-p <priority>` --level filter never matched anything real. Instead the
|
|
9
|
+
* bridge writes `[LEVEL] [label]` into each line and this module compiles
|
|
10
|
+
* user requests into an anchored `journalctl --grep` pattern.
|
|
11
|
+
*
|
|
12
|
+
* Requirements: journalctl with PCRE2 (`--grep`, `--case`). Absent → the CLI
|
|
13
|
+
* errors via journalctl itself; no silent fallback (spec #34 decision).
|
|
14
|
+
*/
|
|
15
|
+
export interface LogFilterRequest {
|
|
16
|
+
/** Labels of all registered projects (case-sensitively stored; matched with `--case=0`). */
|
|
17
|
+
availableLabels: string[];
|
|
18
|
+
/** Positional args after the subcommand — each is a project label. */
|
|
19
|
+
requestedProjects: string[];
|
|
20
|
+
/** Already-parsed level option; kept a string so the CLI can report unknown values. */
|
|
21
|
+
level: string;
|
|
22
|
+
/** follow mode (`logs` true, `status` false). */
|
|
23
|
+
follow: boolean;
|
|
24
|
+
/** For status: -n <lineCount> after the filters. */
|
|
25
|
+
lineCount?: number;
|
|
26
|
+
/** Service unit name (cli passes its SERVICE_NAME constant — one owner). */
|
|
27
|
+
unit: string;
|
|
28
|
+
}
|
|
29
|
+
export type LogFilterResult = {
|
|
30
|
+
ok: true;
|
|
31
|
+
args: string[];
|
|
32
|
+
} | {
|
|
33
|
+
ok: false;
|
|
34
|
+
message: string;
|
|
35
|
+
};
|
|
36
|
+
export declare function buildLogFilterArgs(req: LogFilterRequest): LogFilterResult;
|
|
37
|
+
//# sourceMappingURL=log-filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-filter.d.ts","sourceRoot":"","sources":["../src/log-filter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAaH,MAAM,WAAW,gBAAgB;IAC/B,4FAA4F;IAC5F,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,sEAAsE;IACtE,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,uFAAuF;IACvF,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,MAAM,EAAE,OAAO,CAAC;IAChB,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,eAAe,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAS5F,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,gBAAgB,GAAG,eAAe,CAmCzE"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* log-filter — the pure argv builder behind `pi-courier logs/status` (spec #34).
|
|
3
|
+
*
|
|
4
|
+
* Journal filtering works on the LINE, not on journald fields: custom stdout
|
|
5
|
+
* field assignments (PROJECT=…) are not parsed by journald (measured on
|
|
6
|
+
* systemd 257), and the `PRIORITY` field is useless under the default
|
|
7
|
+
* `StandardOutput=inherit` (every line lands at 6) — which is why the old
|
|
8
|
+
* `-p <priority>` --level filter never matched anything real. Instead the
|
|
9
|
+
* bridge writes `[LEVEL] [label]` into each line and this module compiles
|
|
10
|
+
* user requests into an anchored `journalctl --grep` pattern.
|
|
11
|
+
*
|
|
12
|
+
* Requirements: journalctl with PCRE2 (`--grep`, `--case`). Absent → the CLI
|
|
13
|
+
* errors via journalctl itself; no silent fallback (spec #34 decision).
|
|
14
|
+
*/
|
|
15
|
+
import { parseLogLevel } from "./logger.js";
|
|
16
|
+
/** Lower-bound thresholds: `--level X` shows X and everything louder. */
|
|
17
|
+
const LEVEL_ALTERNATIONS = {
|
|
18
|
+
debug: "DEBUG|INFO|WARN|ERROR",
|
|
19
|
+
info: "INFO|WARN|ERROR",
|
|
20
|
+
warn: "WARN|ERROR",
|
|
21
|
+
error: "ERROR",
|
|
22
|
+
};
|
|
23
|
+
/** Escape a literal for the PCRE pattern (labels are user-visible names that
|
|
24
|
+
* validation keeps free of brackets/whitespace, but metacharacters like .
|
|
25
|
+
* remain possible). */
|
|
26
|
+
function escapeRe(s) {
|
|
27
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
28
|
+
}
|
|
29
|
+
export function buildLogFilterArgs(req) {
|
|
30
|
+
const args = ["--user", "-u", req.unit];
|
|
31
|
+
if (req.follow)
|
|
32
|
+
args.push("-f");
|
|
33
|
+
const level = parseLogLevel(req.level);
|
|
34
|
+
if (!level) {
|
|
35
|
+
return { ok: false, message: `未知日志级别: ${req.level}(可选: debug / info / warn / error)` };
|
|
36
|
+
}
|
|
37
|
+
if (req.requestedProjects.length > 0) {
|
|
38
|
+
const unknown = req.requestedProjects.filter((p) => !req.availableLabels.some((l) => l.toLowerCase() === p.toLowerCase()));
|
|
39
|
+
if (unknown.length > 0) {
|
|
40
|
+
const list = req.availableLabels.length > 0 ? req.availableLabels.join(", ") : "(当前无项目)";
|
|
41
|
+
return {
|
|
42
|
+
ok: false,
|
|
43
|
+
message: `未找到项目: ${unknown.join(", ")}\n可用项目: ${list}`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
// Case-insensitive exact matching is delegated to `--case=0`: the pattern
|
|
47
|
+
// keeps the user's spelling, journalctl does the folding. The LEVEL group
|
|
48
|
+
// is part of every pattern (debug lists all four names) so the match is
|
|
49
|
+
// always anchored to the level-delimiter boundary — a message body that
|
|
50
|
+
// happens to mention `] [name]` cannot produce a false positive.
|
|
51
|
+
const projects = req.requestedProjects.map(escapeRe).join("|");
|
|
52
|
+
args.push("--grep", `\\[(${LEVEL_ALTERNATIONS[level]})\\] \\[(${projects})\\]`, "--case=0");
|
|
53
|
+
}
|
|
54
|
+
else if (level !== "debug") {
|
|
55
|
+
args.push("--grep", `\\[(${LEVEL_ALTERNATIONS[level]})\\] `, "--case=0");
|
|
56
|
+
}
|
|
57
|
+
// level=debug without projects: no grep — everything passes (matches the
|
|
58
|
+
// pre-spec intent of `--level debug`, which was silently broken via -p).
|
|
59
|
+
if (req.lineCount !== undefined)
|
|
60
|
+
args.push("-n", String(req.lineCount));
|
|
61
|
+
return { ok: true, args };
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=log-filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-filter.js","sourceRoot":"","sources":["../src/log-filter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,yEAAyE;AACzE,MAAM,kBAAkB,GAA6B;IACnD,KAAK,EAAE,uBAAuB;IAC9B,IAAI,EAAE,iBAAiB;IACvB,IAAI,EAAE,YAAY;IAClB,KAAK,EAAE,OAAO;CACf,CAAC;AAmBF;;wBAEwB;AACxB,SAAS,QAAQ,CAAC,CAAS;IACzB,OAAO,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAqB;IACtD,MAAM,IAAI,GAAa,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IAClD,IAAI,GAAG,CAAC,MAAM;QAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEhC,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACvC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,GAAG,CAAC,KAAK,mCAAmC,EAAE,CAAC;IACzF,CAAC;IAED,IAAI,GAAG,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,GAAG,CAAC,iBAAiB,CAAC,MAAM,CAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAC7E,CAAC;QACF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,GAAG,GAAG,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACzF,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,OAAO,EAAE,UAAU,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE;aACvD,CAAC;QACJ,CAAC;QACD,0EAA0E;QAC1E,0EAA0E;QAC1E,wEAAwE;QACxE,wEAAwE;QACxE,iEAAiE;QACjE,MAAM,QAAQ,GAAG,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/D,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,kBAAkB,CAAC,KAAK,CAAC,YAAY,QAAQ,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9F,CAAC;SAAM,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,kBAAkB,CAAC,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAC3E,CAAC;IACD,yEAAyE;IACzE,yEAAyE;IAEzE,IAAI,GAAG,CAAC,SAAS,KAAK,SAAS;QAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;IACxE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAC5B,CAAC"}
|
package/dist/logger.d.ts
CHANGED
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
* via `--level debug` (run / logs), and config `logLevel` can lower/raise
|
|
7
7
|
* the write threshold for the service.
|
|
8
8
|
*
|
|
9
|
-
* Output format: `[ISO timestamp] [LEVEL] message` — one line per
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* Output format: `[ISO timestamp] [LEVEL] [label] message` — one line per
|
|
10
|
+
* call; the `[label]` segment appears only on `withLabel()` views (project
|
|
11
|
+
* tagging). Objects are JSON-serialized; string args are newline-flattened
|
|
12
|
+
* (⏎) so one call always yields one physical line (journald-friendly, and a
|
|
13
|
+
* tagged line can never be split into unlabeled continuations).
|
|
12
14
|
*/
|
|
13
15
|
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
14
16
|
export declare function suppressLogLines(...substrings: string[]): () => void;
|
|
@@ -16,6 +18,10 @@ export interface LeveledLogger {
|
|
|
16
18
|
setLogLevel(level: LogLevel): void;
|
|
17
19
|
getLogLevel(): LogLevel;
|
|
18
20
|
isEnabled(level: LogLevel): boolean;
|
|
21
|
+
/** Derive a view that prefixes every line with `[label]` (project tagging).
|
|
22
|
+
* Threshold and suppression are read through to the parent on every call.
|
|
23
|
+
* An empty/undefined label yields the parent itself (no-op derivation). */
|
|
24
|
+
withLabel(label: string | undefined): LeveledLogger;
|
|
19
25
|
debug(...args: unknown[]): void;
|
|
20
26
|
info(...args: unknown[]): void;
|
|
21
27
|
warn(...args: unknown[]): void;
|
package/dist/logger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAqB3D,wBAAgB,gBAAgB,CAAC,GAAG,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAKpE;AAQD,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;IACnC,WAAW,IAAI,QAAQ,CAAC;IACxB,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC;IACpC;;gFAE4E;IAC5E,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,CAAC;IACpD,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChC,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CACjC;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,QAAiB,GAAG,aAAa,CA2CtE;AAED,+DAA+D;AAC/D,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAMjE;AAoBD,eAAO,MAAM,MAAM,EAAE,aAA6B,CAAC;AACnD,eAAO,MAAM,WAAW,UA7FH,QAAQ,KAAG,IA6FoB,CAAC;AACrD,eAAO,MAAM,WAAW,QA7FP,QA6FmC,CAAC;AACrD,eAAO,MAAM,SAAS,UA7FH,QAAQ,KAAG,OA6FkB,CAAC"}
|
package/dist/logger.js
CHANGED
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
* via `--level debug` (run / logs), and config `logLevel` can lower/raise
|
|
7
7
|
* the write threshold for the service.
|
|
8
8
|
*
|
|
9
|
-
* Output format: `[ISO timestamp] [LEVEL] message` — one line per
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* Output format: `[ISO timestamp] [LEVEL] [label] message` — one line per
|
|
10
|
+
* call; the `[label]` segment appears only on `withLabel()` views (project
|
|
11
|
+
* tagging). Objects are JSON-serialized; string args are newline-flattened
|
|
12
|
+
* (⏎) so one call always yields one physical line (journald-friendly, and a
|
|
13
|
+
* tagged line can never be split into unlabeled continuations).
|
|
12
14
|
*/
|
|
13
15
|
const LEVEL_ORDER = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
14
16
|
const LEVEL_NAMES = { debug: "DEBUG", info: "INFO", warn: "WARN", error: "ERROR" };
|
|
@@ -48,12 +50,13 @@ function isSuppressed(args) {
|
|
|
48
50
|
export function createLogger(initial = "info") {
|
|
49
51
|
let threshold = initial;
|
|
50
52
|
const isEnabled = (level) => LEVEL_ORDER[level] >= LEVEL_ORDER[threshold];
|
|
51
|
-
const write = (level, args) => {
|
|
53
|
+
const write = (level, args, label) => {
|
|
52
54
|
if (!isEnabled(level))
|
|
53
55
|
return;
|
|
54
56
|
if (isSuppressed(args))
|
|
55
57
|
return;
|
|
56
|
-
const
|
|
58
|
+
const labelPart = label ? [`[${label}]`] : [];
|
|
59
|
+
const line = [`[${new Date().toISOString()}]`, `[${LEVEL_NAMES[level]}]`, ...labelPart, ...args.map(formatArg)].join(" ");
|
|
57
60
|
if (level === "error" || level === "warn") {
|
|
58
61
|
console.error(line);
|
|
59
62
|
}
|
|
@@ -61,17 +64,33 @@ export function createLogger(initial = "info") {
|
|
|
61
64
|
console.log(line);
|
|
62
65
|
}
|
|
63
66
|
};
|
|
64
|
-
|
|
67
|
+
const logger = {
|
|
65
68
|
setLogLevel: (level) => {
|
|
66
69
|
threshold = level;
|
|
67
70
|
},
|
|
68
71
|
getLogLevel: () => threshold,
|
|
69
72
|
isEnabled,
|
|
73
|
+
withLabel: (label) => {
|
|
74
|
+
const trimmed = label?.trim();
|
|
75
|
+
if (!trimmed)
|
|
76
|
+
return logger;
|
|
77
|
+
return {
|
|
78
|
+
setLogLevel: logger.setLogLevel,
|
|
79
|
+
getLogLevel: logger.getLogLevel,
|
|
80
|
+
isEnabled: logger.isEnabled,
|
|
81
|
+
withLabel: (next) => (next?.trim() ? logger.withLabel(next.trim()) : logger),
|
|
82
|
+
debug: (...args) => write("debug", args, trimmed),
|
|
83
|
+
info: (...args) => write("info", args, trimmed),
|
|
84
|
+
warn: (...args) => write("warn", args, trimmed),
|
|
85
|
+
error: (...args) => write("error", args, trimmed),
|
|
86
|
+
};
|
|
87
|
+
},
|
|
70
88
|
debug: (...args) => write("debug", args),
|
|
71
89
|
info: (...args) => write("info", args),
|
|
72
90
|
warn: (...args) => write("warn", args),
|
|
73
91
|
error: (...args) => write("error", args),
|
|
74
92
|
};
|
|
93
|
+
return logger;
|
|
75
94
|
}
|
|
76
95
|
/** Parse a CLI/config level string; undefined when invalid. */
|
|
77
96
|
export function parseLogLevel(value) {
|
|
@@ -86,7 +105,8 @@ export function parseLogLevel(value) {
|
|
|
86
105
|
}
|
|
87
106
|
function formatArg(arg) {
|
|
88
107
|
if (typeof arg === "string") {
|
|
89
|
-
|
|
108
|
+
const oneLine = arg.replace(/\r\n|\r|\n/g, "⏎");
|
|
109
|
+
return oneLine.length > MAX_STRING ? `${oneLine.slice(0, MAX_STRING)}…(+${oneLine.length - MAX_STRING} chars)` : oneLine;
|
|
90
110
|
}
|
|
91
111
|
if (typeof arg === "object" && arg !== null) {
|
|
92
112
|
try {
|