@ketaisoft/agentmem 0.1.3
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.en.md +68 -0
- package/README.md +164 -0
- package/dist/cli.js +130 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 agentmem
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.en.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# agentmem collector (agentmem-capture)
|
|
2
|
+
|
|
3
|
+
[中文](./README.md) · **English**
|
|
4
|
+
|
|
5
|
+
A session collector for coding agents. **Read-only**: it captures your local coding-agent sessions → redacts on the client → HMAC-signs → uploads to the server's `/ingest` endpoint.
|
|
6
|
+
|
|
7
|
+
Supports **Claude Code** (`~/.claude/projects/**/*.jsonl`) and **Codex** (`~/.codex/sessions/**/rollout-*.jsonl`).
|
|
8
|
+
|
|
9
|
+
## Highlights
|
|
10
|
+
- **Read-only, non-intrusive** — never modifies agent files or workflows.
|
|
11
|
+
- **Normalization** — each transcript line becomes a unified event. Only `type=user/assistant` lines that carry a `message` are captured; noise lines are skipped. `seq` = the file line number (append-only, stable, idempotency-friendly).
|
|
12
|
+
- **Reasoning (thinking)** — content is not exposed in the preview by default; only its occurrence and tokens are recorded (the full text goes to the original-text store).
|
|
13
|
+
- **Client-side redaction** — masks secrets / tokens / connection passwords / JWTs / emails before upload, and writes a redaction report (rules hit + counts) into `meta.redaction`. Best-effort, not a guarantee; the server can re-check.
|
|
14
|
+
- **Machine auth** — HMAC-SHA256 signature; the tenant/user identity is bound server-side by the credential (`SysOpenAccess`), so the client never carries a tenant.
|
|
15
|
+
- **Idempotent** — `(client_id, session_id, seq)` is unique; duplicate uploads return `accepted=0`.
|
|
16
|
+
- **End-to-end durable** — a local WAL plus watermark reconcile: entries are dropped only after the server confirms they are persisted.
|
|
17
|
+
- **Zero runtime dependencies** — run the compiled `dist` on Node ≥ 18.18, or the `.ts` source directly on Node ≥ 23.6 (native type-stripping).
|
|
18
|
+
- **Bilingual output** — the CLI and logs switch automatically by OS language (Chinese locale → Chinese, otherwise English). Override with `AGENTMEM_LANG=en|zh`.
|
|
19
|
+
|
|
20
|
+
## Install & run
|
|
21
|
+
No installation step is required — it is a zero-dependency Node program.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# 1) Configure credentials with the device-authorization flow (no key pasting)
|
|
25
|
+
agentmem login --endpoint https://api.huihuayun.cn
|
|
26
|
+
|
|
27
|
+
# 2a) Run as a daemon (continuous background capture) — the production path
|
|
28
|
+
agentmem daemon
|
|
29
|
+
|
|
30
|
+
# 2b) ...or inject a one-line hook into ~/.claude/settings.json (near-zero footprint)
|
|
31
|
+
agentmem install
|
|
32
|
+
|
|
33
|
+
# Inspect / diagnose
|
|
34
|
+
agentmem status
|
|
35
|
+
agentmem doctor
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
During development you can also run `node dist/cli.js <command>`, or run the source directly with `node src/cli.ts <command>` on Node ≥ 23.6.
|
|
39
|
+
|
|
40
|
+
## Commands
|
|
41
|
+
| Command | Description |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `daemon` | Continuous capture (watch + poll → local WAL → upload) — the production path |
|
|
44
|
+
| `flush [--transcript F \| --latest \| --session S \| --stdin]` | One-shot incremental capture + drain (hooks use `--stdin`) |
|
|
45
|
+
| `login --endpoint <url>` | Device-authorization login (no key pasting) |
|
|
46
|
+
| `install [--local]` | Idempotently inject the `~/.claude/settings.json` hook |
|
|
47
|
+
| `uninstall` | Remove our hook |
|
|
48
|
+
| `service <install\|uninstall\|status>` | Service / auto-start: launch the daemon at login (needed for daemon-based sources). Windows: `schtasks` logon task; macOS: LaunchAgent; Linux: systemd `--user` unit. All user-level, no admin/sudo. |
|
|
49
|
+
| `status` | Local queue / cursor / credentials |
|
|
50
|
+
| `doctor` | One-shot health check |
|
|
51
|
+
| `upload --file <jsonl> [--dry-run]` | Manual full upload (debugging) |
|
|
52
|
+
|
|
53
|
+
## Environment variables
|
|
54
|
+
| Variable | Description |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `AGENTMEM_LANG` | `en` / `zh` to force the CLI & log language (default: OS locale, non-Chinese ⇒ English) |
|
|
57
|
+
| `AGENTMEM_ENDPOINT` / `AGENTMEM_ACCESS_KEY` / `AGENTMEM_ACCESS_SECRET` | Credentials via environment (for CI / headless). Otherwise they are stored in `~/.agentmem/credentials.json` after `login`. |
|
|
58
|
+
|
|
59
|
+
## What it captures
|
|
60
|
+
- **Claude Code** — `~/.claude/projects/**/*.jsonl`
|
|
61
|
+
- **Codex** — `~/.codex/sessions/**/rollout-*.jsonl`
|
|
62
|
+
|
|
63
|
+
Each event carries: role, model, tokens, project, a redacted preview/summary, and — when the content is larger than the preview — the full redacted original text, which the server stores in object storage.
|
|
64
|
+
|
|
65
|
+
## Notes
|
|
66
|
+
- **Cross-platform** — pure Node; runs on Windows / macOS / Linux under any system locale.
|
|
67
|
+
- **Network** — read-only on disk; only the HTTPS endpoint you configure is contacted, over a signed request.
|
|
68
|
+
- **Storage** — local state lives under `~/.agentmem/` (client id, credentials, WAL, cursors).
|
package/README.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# agentmem · 编码 Agent 会话采集端 / Coding-Agent Session Collector
|
|
2
|
+
|
|
3
|
+
`@ketaisoft/agentmem` — 只读采集本机编码 Agent 会话,客户端脱敏后 HMAC 签名上报到你的会话云;**零运行时依赖**。
|
|
4
|
+
Read-only collector for local coding-agent sessions: redact on-device, HMAC-sign, upload to your session cloud. **Zero runtime dependencies.**
|
|
5
|
+
|
|
6
|
+
**支持 / Supports:** Claude Code · Codex · Cursor · Gemini · OpenCode
|
|
7
|
+
|
|
8
|
+
### 🌐 官网 / Website:**https://www.huihuayun.cn**
|
|
9
|
+
|
|
10
|
+
[中文](#中文) · [English](#english)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<a id="中文"></a>
|
|
15
|
+
|
|
16
|
+
## 中文
|
|
17
|
+
|
|
18
|
+
### 这是什么
|
|
19
|
+
`agentmem` 采集端**只读**采集你本机的编码 Agent 会话(消息 / 推理发生 / 工具调用 / 工具结果 / token / 成本)→ **客户端脱敏**(密钥、令牌、连接串口令、JWT、邮箱等打码)→ **HMAC-SHA256 签名** → 上报服务端 `/ingest`。本地 WAL + 后端落库水位对账,**端到端不丢**。
|
|
20
|
+
|
|
21
|
+
### 安装
|
|
22
|
+
```bash
|
|
23
|
+
# 免安装(先试试)
|
|
24
|
+
npx -y @ketaisoft/agentmem doctor
|
|
25
|
+
# 或全局安装(命令即 agentmem)
|
|
26
|
+
npm i -g @ketaisoft/agentmem
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 快速开始
|
|
30
|
+
```bash
|
|
31
|
+
agentmem login # 设备授权登录(默认连 https://api.huihuayun.cn)
|
|
32
|
+
# 私有化部署指向自己的服务端:agentmem login --endpoint https://你的服务端
|
|
33
|
+
agentmem install # 注入 Claude Code hook(检测到 Codex 时一并装 notify)
|
|
34
|
+
# 若使用 Cursor / Gemini / OpenCode(无 hook 的源):
|
|
35
|
+
agentmem daemon # 常驻采集
|
|
36
|
+
agentmem service install # 开机自启(免得每次手动起 daemon)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 各 Agent 的采集通道
|
|
40
|
+
| Agent | 通道 | 说明 |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| Claude Code | hook(事件驱动) | `install` 注入 `~/.claude/settings.json` 的 Stop/SessionEnd hook;会话结束即采,无需常驻、重启不受影响 |
|
|
43
|
+
| Codex | notify hook | `install` 幂等注入 `~/.codex/config.toml` 的 `notify`;回合结束即采,无需常驻 |
|
|
44
|
+
| Cursor / Gemini / OpenCode | daemon(文件监听) | 需常驻 `agentmem daemon`;`service install` 可开机自启 |
|
|
45
|
+
|
|
46
|
+
### 命令
|
|
47
|
+
| 命令 | 说明 |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `daemon` | 常驻采集(多源 watch+轮询 → 本地 WAL → 上报) |
|
|
50
|
+
| `flush [--transcript F\|--latest\|--session S\|--stdin]` | 一次性增量采集+排空(hook 用 `--stdin`) |
|
|
51
|
+
| `login --endpoint <url>` | 设备授权登录 |
|
|
52
|
+
| `install [--local]` | 注入 Claude hook(+ 检测到 Codex 时装 notify) |
|
|
53
|
+
| `uninstall` | 移除我方 hook(含 Codex notify) |
|
|
54
|
+
| `service <install\|uninstall\|status>` | 服务化 / 开机自启 |
|
|
55
|
+
| `status` | 本地队列 / 游标 / 凭证 |
|
|
56
|
+
| `doctor` | 一键体检 |
|
|
57
|
+
| `upload --file <jsonl> [--dry-run]` | 手工全量上报(调试) |
|
|
58
|
+
| `mcp [--print-config]` | 团队记忆 MCP server(供 Claude Code/Codex 回喂) |
|
|
59
|
+
| `replay-dead` | 重投本地死信回待发队列 |
|
|
60
|
+
| `codex-notify [<json>]` | Codex notify 钩子入口(一般由 Codex 自动调用) |
|
|
61
|
+
| `update` | 升级到最新版 |
|
|
62
|
+
| `-v` / `--version` / `version` | 查看版本 |
|
|
63
|
+
| `-h` / `-help` / `--help` | 查看帮助 |
|
|
64
|
+
|
|
65
|
+
### 服务化 / 开机自启(用 daemon 源时需要)
|
|
66
|
+
均为**用户级、免管理员/sudo**:
|
|
67
|
+
- **Windows**:`schtasks` 登录自启任务 `agentmem-daemon`
|
|
68
|
+
- **macOS**:`launchd` LaunchAgent(`RunAtLoad`+`KeepAlive`)
|
|
69
|
+
- **Linux**:`systemd --user` 单元;开机未登录也常驻需一次性 `loginctl enable-linger $USER`
|
|
70
|
+
|
|
71
|
+
### 设计要点
|
|
72
|
+
- **只读、不干扰**:绝不修改 agent 文件或工作流。
|
|
73
|
+
- **脱敏(信任差异点)**:上传前本机打码密钥/令牌/连接串口令/JWT/邮箱等,并产出脱敏报告(命中规则+计数,入 `meta.redaction`);尽力而非保证,服务端可二次复核。
|
|
74
|
+
- **推理内容默认不外露**:仅记 reasoning 的发生与 token。
|
|
75
|
+
- **机器鉴权**:HMAC-SHA256 签名;租户/用户身份由服务端开放凭证绑定,客户端不自带 tenant。
|
|
76
|
+
- **幂等**:`(client_id, session_id, seq)` 唯一,重复上报 `accepted=0`。
|
|
77
|
+
- **端到端不丢**:本地 WAL + 后端落库水位对账,后端确认落库才删本地;失败可 `replay-dead` 重投。
|
|
78
|
+
- **零运行时依赖**:`dist` 在 Node ≥ 20 跑;源码 `.ts` 在 Node ≥ 23.6 原生 strip-types 免构建直跑。
|
|
79
|
+
|
|
80
|
+
### 环境变量
|
|
81
|
+
| 变量 | 说明 |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `AGENTMEM_LANG` | `en`/`zh` 强制 CLI/日志语言(默认随系统语言,非中文 ⇒ 英文) |
|
|
84
|
+
| `AGENTMEM_ENDPOINT` / `AGENTMEM_ACCESS_KEY` / `AGENTMEM_ACCESS_SECRET` | 用环境变量提供凭证(CI/无人值守);否则 `login` 后存 `~/.agentmem/credentials.json` |
|
|
85
|
+
| `AGENTMEM_CLAUDE_DIR` / `AGENTMEM_CODEX_DIR` / `AGENTMEM_CURSOR_DIR` / `AGENTMEM_GEMINI_DIR` / `AGENTMEM_OPENCODE_DIR` / `AGENTMEM_EXTRA_DIRS` | 覆盖各源会话目录 |
|
|
86
|
+
|
|
87
|
+
本地状态存于 `~/.agentmem/`(client id、凭证、WAL、游标)。
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
<a id="english"></a>
|
|
92
|
+
|
|
93
|
+
## English
|
|
94
|
+
|
|
95
|
+
### What it is
|
|
96
|
+
`agentmem` is a **read-only** collector for your local coding-agent sessions (messages / reasoning occurrences / tool calls / tool results / tokens / cost). It **redacts on-device** (secrets, tokens, connection passwords, JWTs, emails…), **HMAC-SHA256 signs**, and uploads to your server's `/ingest`. A local WAL plus a persistence-watermark reconcile make it **end-to-end lossless**.
|
|
97
|
+
|
|
98
|
+
### Install
|
|
99
|
+
```bash
|
|
100
|
+
# no install
|
|
101
|
+
npx -y @ketaisoft/agentmem doctor
|
|
102
|
+
# or global (command: agentmem)
|
|
103
|
+
npm i -g @ketaisoft/agentmem
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Quick start
|
|
107
|
+
```bash
|
|
108
|
+
agentmem login # device-authorization login (defaults to https://api.huihuayun.cn)
|
|
109
|
+
# self-hosted: point to your own server → agentmem login --endpoint https://your-server
|
|
110
|
+
agentmem install # inject Claude Code hook (+ Codex notify if detected)
|
|
111
|
+
# For Cursor / Gemini / OpenCode (no-hook sources):
|
|
112
|
+
agentmem daemon # continuous capture
|
|
113
|
+
agentmem service install # auto-start at login
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Capture channel per agent
|
|
117
|
+
| Agent | Channel | Notes |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| Claude Code | hook (event-driven) | `install` injects a Stop/SessionEnd hook into `~/.claude/settings.json`; no daemon, survives reboot |
|
|
120
|
+
| Codex | notify hook | `install` idempotently adds `notify` to `~/.codex/config.toml`; captures at turn end, no daemon |
|
|
121
|
+
| Cursor / Gemini / OpenCode | daemon (file watch) | needs a running `agentmem daemon`; use `service install` for auto-start |
|
|
122
|
+
|
|
123
|
+
### Commands
|
|
124
|
+
| Command | Description |
|
|
125
|
+
|---|---|
|
|
126
|
+
| `daemon` | Continuous capture (watch + poll → local WAL → upload) |
|
|
127
|
+
| `flush [--transcript F\|--latest\|--session S\|--stdin]` | One-shot incremental capture + drain (hooks use `--stdin`) |
|
|
128
|
+
| `login --endpoint <url>` | Device-authorization login |
|
|
129
|
+
| `install [--local]` | Inject the Claude hook (+ Codex notify when detected) |
|
|
130
|
+
| `uninstall` | Remove our hook (incl. Codex notify) |
|
|
131
|
+
| `service <install\|uninstall\|status>` | Service / auto-start (launch daemon at login) |
|
|
132
|
+
| `status` | Local queue / cursor / credentials |
|
|
133
|
+
| `doctor` | One-shot health check |
|
|
134
|
+
| `upload --file <jsonl> [--dry-run]` | Manual full upload (debugging) |
|
|
135
|
+
| `mcp [--print-config]` | Team-memory MCP server (recall for Claude Code/Codex) |
|
|
136
|
+
| `replay-dead` | Requeue local dead-letter events |
|
|
137
|
+
| `codex-notify [<json>]` | Codex notify hook entry (usually invoked by Codex) |
|
|
138
|
+
| `update` | Upgrade to the latest version |
|
|
139
|
+
| `-v` / `--version` / `version` | Print version |
|
|
140
|
+
| `-h` / `-help` / `--help` | Show help |
|
|
141
|
+
|
|
142
|
+
### Service / auto-start (needed for daemon-based sources)
|
|
143
|
+
All user-level, no admin/sudo:
|
|
144
|
+
- **Windows** — `schtasks` logon task `agentmem-daemon`
|
|
145
|
+
- **macOS** — `launchd` LaunchAgent (`RunAtLoad` + `KeepAlive`)
|
|
146
|
+
- **Linux** — `systemd --user` unit; to persist without an active login run `loginctl enable-linger $USER` once
|
|
147
|
+
|
|
148
|
+
### Design
|
|
149
|
+
- **Read-only & non-intrusive** — never modifies agent files or workflows.
|
|
150
|
+
- **Client-side redaction** — masks secrets / tokens / connection passwords / JWTs / emails before upload, with a report (rules hit + counts) in `meta.redaction`. Best-effort, not a guarantee; the server can re-check.
|
|
151
|
+
- **Reasoning content not exposed** — only its occurrence and tokens are recorded.
|
|
152
|
+
- **Machine auth** — HMAC-SHA256; tenant/user identity is bound server-side by the credential, so the client never carries a tenant.
|
|
153
|
+
- **Idempotent** — `(client_id, session_id, seq)` is unique; duplicate uploads return `accepted=0`.
|
|
154
|
+
- **End-to-end lossless** — local WAL + server persistence watermark; entries drop only after the server confirms they are stored. Failed items can be re-queued via `replay-dead`.
|
|
155
|
+
- **Zero runtime dependencies** — run the compiled `dist` on Node ≥ 20, or the `.ts` source directly on Node ≥ 23.6 (native type-stripping).
|
|
156
|
+
|
|
157
|
+
### Environment variables
|
|
158
|
+
| Variable | Description |
|
|
159
|
+
|---|---|
|
|
160
|
+
| `AGENTMEM_LANG` | `en` / `zh` to force the CLI & log language (default: OS locale, non-Chinese ⇒ English) |
|
|
161
|
+
| `AGENTMEM_ENDPOINT` / `AGENTMEM_ACCESS_KEY` / `AGENTMEM_ACCESS_SECRET` | Credentials via environment (CI / headless); otherwise stored in `~/.agentmem/credentials.json` after `login` |
|
|
162
|
+
| `AGENTMEM_CLAUDE_DIR` / `AGENTMEM_CODEX_DIR` / `AGENTMEM_CURSOR_DIR` / `AGENTMEM_GEMINI_DIR` / `AGENTMEM_OPENCODE_DIR` / `AGENTMEM_EXTRA_DIRS` | Override each source's session directory |
|
|
163
|
+
|
|
164
|
+
Local state lives under `~/.agentmem/` (client id, credentials, WAL, cursors).
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{fileURLToPath as kr}from"node:url";import{existsSync as N}from"node:fs";import{spawnSync as Sr}from"node:child_process";import{readFileSync as so,statSync as $t,openSync as ro,readSync as io,closeSync as ao}from"node:fs";import{basename as co}from"node:path";var _t=4e3,lo=16*1024*1024;function Ct(e){return e.customTitle??e.aiTitle??null}function It(e){let t=co(e);return t.endsWith(".jsonl")?t.slice(0,-6):t}function uo(e){if(!e||typeof e!="object")return"";let t=e,n=t.file_path??t.notebook_path??t.filePath??t.path;if(typeof n=="string"&&n)return n.slice(0,300);let o=t.command??t.cmd??t.script;if(typeof o=="string"&&o)return o.slice(0,200);let s=t.pattern??t.query;return typeof s=="string"&&s?s.slice(0,120):""}function fo(e){if(typeof e=="string")return e.slice(0,300);if(Array.isArray(e)){let t=[];for(let n of e)n&&typeof n=="object"&&n.type==="text"&&t.push(String(n.text??""));return t.join(`
|
|
3
|
+
`).slice(0,300)}return""}function po(e){if(typeof e=="string")return e;if(Array.isArray(e)){let t=[];for(let n of e)n&&typeof n=="object"&&n.type==="text"&&t.push(String(n.text??""));return t.join(`
|
|
4
|
+
`)}return""}function mo(e,t){if(typeof e=="string")return{preview:e.slice(0,_t),raw:e};if(!Array.isArray(e))return{preview:"",raw:""};let n=[],o=[];for(let s of e){if(!s||typeof s!="object")continue;let r=s.type;if(r==="text"){let a=String(s.text??"");n.push(a),o.push(a)}else if(r==="thinking"||r==="redacted_thinking"){t.kind="reasoning";let a=String(s.thinking??"");a&&o.push(a)}else if(r==="tool_use"){t.kind="tool_call";let a=s.name??"unknown",i=s.input,c=uo(i);n.push(c?`[tool_call:${a}] ${c}`:`[tool_call:${a}]`);let l="";try{l=JSON.stringify(i??"")}catch{}o.push(`[tool_call:${a}] ${l}`)}else if(r==="tool_result"){t.kind="tool_result";let a=s.content;n.push(`[tool_result] ${fo(a)}`),o.push(`[tool_result] ${po(a)}`)}}return{preview:n.join(`
|
|
5
|
+
`).slice(0,_t).trim(),raw:o.join(`
|
|
6
|
+
`).trim()}}function Rt(e,t,n){let o=e.trim();if(!o)return null;let s;try{s=JSON.parse(o)}catch{return null}let r=s.type;if(r==="custom-title")return typeof s.customTitle=="string"&&(n.customTitle=s.customTitle),null;if(r==="ai-title")return typeof s.aiTitle=="string"&&(n.aiTitle=s.aiTitle),null;if(r!=="user"&&r!=="assistant")return null;let a=s.message;if(!a||typeof a!="object")return null;let i=a;typeof s.sessionId=="string"&&(n.sessionId=s.sessionId),typeof s.cwd=="string"&&(n.project=s.cwd);let c=r==="assistant"?"assistant":"user",l={kind:"message"},d=mo(i.content,l),p=i.usage&&typeof i.usage=="object"?i.usage:{},m=typeof i.model=="string"?i.model:null;return m&&(n.lastModel=m),{sessionId:n.sessionId,seq:t,role:c,eventKind:l.kind,model:c==="assistant"?m??n.lastModel:null,project:n.project,ts:typeof s.timestamp=="string"?s.timestamp:null,text:d.preview,rawText:d.raw,tokenIn:Number(p.input_tokens??0)||0,tokenOut:Number(p.output_tokens??0)||0,meta:{uuid:s.uuid??null,parentUuid:s.parentUuid??null,isSidechain:!!s.isSidechain,isMeta:!!s.isMeta,gitBranch:s.gitBranch??null,version:s.version??null,stopReason:i.stop_reason??null,cacheRead:Number(p.cache_read_input_tokens??0)||0,cacheCreation:Number(p.cache_creation_input_tokens??0)||0}}}function At(e){let t=so(e,"utf8").split(/\r?\n/),n={sessionId:It(e),project:null,lastModel:null,customTitle:null,aiTitle:null},o=[];for(let r=0;r<t.length;r++){let a=Rt(t[r],r,n);a&&o.push(a)}let s=Ct(n);if(s)for(let r of o)r.title=s;return{sessionId:n.sessionId,project:n.project,events:o}}function ye(e){let t=$t(e);return`${t.dev}-${t.ino}`}function Nt(e,t,n,o){let s=$t(e),r=s.size,a=`${s.dev}-${s.ino}`,i=t,c=n;i>r&&(i=0,c=0);let l={sessionId:o||It(e),project:null,lastModel:null,customTitle:null,aiTitle:null},d=[];if(r<=i)return{events:d,sessionId:l.sessionId,project:l.project,inode:a,byteOffset:i,lineNo:c,fileSize:r,hasMore:!1};let p=r-i,m=Math.min(p,lo),y=Buffer.alloc(m),g=ro(e,"r");try{io(g,y,0,m,i)}finally{ao(g)}let k=y.lastIndexOf(10);if(k<0){if(m<p){let x=i+m;return{events:d,sessionId:l.sessionId,project:l.project,inode:a,byteOffset:x,lineNo:c,fileSize:r,hasMore:x<r}}return{events:d,sessionId:l.sessionId,project:l.project,inode:a,byteOffset:i,lineNo:c,fileSize:r,hasMore:!1}}let b=y.subarray(0,k+1),S=b.toString("utf8").split(/\r?\n/);S.length&&S[S.length-1]===""&&S.pop();for(let x=0;x<S.length;x++){let B=Rt(S[x],c+x,l);B&&d.push(B)}let w=Ct(l);if(w)for(let x of d)x.title=w;let f=i+b.length;return{events:d,sessionId:l.sessionId,project:l.project,inode:a,byteOffset:f,lineNo:c+S.length,fileSize:r,hasMore:f<r}}import{readFileSync as go,statSync as ho,openSync as yo,readSync as wo,closeSync as ko}from"node:fs";import{basename as So}from"node:path";var bo=4e3,vo=16*1024*1024,xo=/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i;function Eo(e){let t=xo.exec(e);if(t)return t[1];let n=So(e);return n.endsWith(".jsonl")?n.slice(0,-6):n}var _o=(e,t=bo)=>String(e??"").slice(0,t);function oe(e,t,n,o,s,r){let a=String(s??"");return{sessionId:e.sessionId,seq:t,role:n,eventKind:o,model:n==="assistant"&&o==="message"?e.lastModel:null,project:e.project,ts:e.ts,text:_o(a),rawText:a,tokenIn:0,tokenOut:0,meta:{role:n,eventKind:o,agent:"codex",...r}}}function Tt(e,t,n,o){let s=e.trim();if(!s)return;let r;try{r=JSON.parse(s)}catch{return}let a=r.type,i=r.payload&&typeof r.payload=="object"?r.payload:{};if(n.ts=typeof r.timestamp=="string"?r.timestamp:n.ts,a==="session_meta"){typeof i.id=="string"&&(n.sessionId=i.id),typeof i.cwd=="string"&&(n.project=i.cwd);return}if(a==="turn_context"){typeof i.model=="string"&&(n.lastModel=i.model),typeof i.cwd=="string"&&(n.project=i.cwd);return}if(a==="event_msg"){let c=i.type;if(c==="token_count"){let l=i.info&&typeof i.info=="object"?i.info:{},d=l.last_token_usage&&typeof l.last_token_usage=="object"?l.last_token_usage:{};n.lastAssistant&&(n.lastAssistant.tokenIn=Number(d.input_tokens??0)||0,n.lastAssistant.tokenOut=Number(d.output_tokens??0)||0);return}if(c==="user_message"){o.push(oe(n,t,"user","message",String(i.message??""),{turnId:r.turn_id??null}));return}if(c==="agent_message"){let l=oe(n,t,"assistant","message",String(i.message??""),{phase:i.phase??null});o.push(l),n.lastAssistant=l;return}return}if(a==="response_item"){let c=i.type;if(c==="reasoning"){o.push(oe(n,t,"assistant","reasoning","",{encrypted:!0}));return}if(c==="function_call"){let l=i.name??"tool";o.push(oe(n,t,"assistant","tool_call",`[tool_call:${l}] ${String(i.arguments??"")}`,{name:l,callId:i.call_id??null}));return}if(c==="function_call_output"){let l=typeof i.output=="string"?i.output:JSON.stringify(i.output??"");o.push(oe(n,t,"tool","tool_result",`[tool_result] ${l}`,{callId:i.call_id??null}));return}if(c==="web_search_call"){let l=i.action&&typeof i.action=="object"?i.action:{};o.push(oe(n,t,"assistant","tool_call",`[tool_call:web_search] ${String(l.query??"")}`,{name:"web_search"}));return}return}}function Mt(e,t){return{sessionId:t||Eo(e),project:null,lastModel:null,ts:null,lastAssistant:null}}function jt(e){let t=go(e,"utf8").split(/\r?\n/),n=Mt(e),o=[];for(let s=0;s<t.length;s++)Tt(t[s],s,n,o);return{sessionId:n.sessionId,project:n.project,events:o}}function Ot(e,t,n,o){let s=ho(e),r=s.size,a=`${s.dev}-${s.ino}`,i=t,c=n;i>r&&(i=0,c=0);let l=Mt(e,o),d=[];if(r<=i)return{events:d,sessionId:l.sessionId,project:l.project,inode:a,byteOffset:i,lineNo:c,fileSize:r,hasMore:!1};let p=r-i,m=Math.min(p,vo),y=Buffer.alloc(m),g=yo(e,"r");try{wo(g,y,0,m,i)}finally{ko(g)}let k=y.lastIndexOf(10);if(k<0){if(m<p){let f=i+m;return{events:d,sessionId:l.sessionId,project:l.project,inode:a,byteOffset:f,lineNo:c,fileSize:r,hasMore:f<r}}return{events:d,sessionId:l.sessionId,project:l.project,inode:a,byteOffset:i,lineNo:c,fileSize:r,hasMore:!1}}let b=y.subarray(0,k+1),S=b.toString("utf8").split(/\r?\n/);S.length&&S[S.length-1]===""&&S.pop();for(let f=0;f<S.length;f++)Tt(S[f],c+f,l,d);let w=i+b.length;return{events:d,sessionId:l.sessionId,project:l.project,inode:a,byteOffset:w,lineNo:c+S.length,fileSize:r,hasMore:w<r}}import{readFileSync as $o,statSync as Co,openSync as Io,readSync as Ro,closeSync as Ao}from"node:fs";import{basename as No}from"node:path";var Dt=4e3,To=16*1024*1024,Mo=/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i;function jo(e){let t=Mo.exec(e);if(t)return t[1];let n=No(e);return n.endsWith(".jsonl")?n.slice(0,-6):n}function Oo(e){let t=e.split(/[\\/]/),n=t.lastIndexOf("agent-transcripts");if(n>0)return t[n-1]||null;let o=t.lastIndexOf("projects");return o>=0&&t[o+1]?t[o+1]:null}function Do(e){if(typeof e=="string")return e.slice(0,300);if(Array.isArray(e)){let t=[];for(let n of e)n&&typeof n=="object"&&n.type==="text"&&t.push(String(n.text??""));return t.join(`
|
|
7
|
+
`).slice(0,300)}return""}function Lo(e){if(typeof e=="string")return e;if(Array.isArray(e)){let t=[];for(let n of e)n&&typeof n=="object"&&n.type==="text"&&t.push(String(n.text??""));return t.join(`
|
|
8
|
+
`)}return""}function Po(e,t){if(typeof e=="string")return{preview:e.slice(0,Dt),raw:e};if(!Array.isArray(e))return{preview:"",raw:""};let n=[],o=[];for(let s of e){if(!s||typeof s!="object")continue;let r=s.type;if(r==="text"){let a=String(s.text??"");n.push(a),o.push(a)}else if(r==="thinking"||r==="redacted_thinking"){t.kind="reasoning";let a=String(s.thinking??"");a&&o.push(a)}else if(r==="tool_use"){t.kind="tool_call";let a=s.name??"unknown";n.push(`[tool_call:${a}]`);let i="";try{i=JSON.stringify(s.input??"")}catch{}o.push(`[tool_call:${a}] ${i}`)}else if(r==="tool_result"){t.kind="tool_result";let a=s.content;n.push(`[tool_result] ${Do(a)}`),o.push(`[tool_result] ${Lo(a)}`)}}return{preview:n.join(`
|
|
9
|
+
`).slice(0,Dt).trim(),raw:o.join(`
|
|
10
|
+
`).trim()}}function Lt(e,t,n){let o=e.trim();if(!o)return null;let s;try{s=JSON.parse(o)}catch{return null}for(let g of["sessionId","conversationId","conversation_id"])typeof s[g]=="string"&&s[g]&&(n.sessionId=s[g]);for(let g of["cwd","workspaceRoot","workspace_root","projectRoot"])typeof s[g]=="string"&&s[g]&&(n.project=s[g]);let r=(typeof s.type=="string"?s.type:"")||(typeof s.role=="string"?s.role:"");if(r!=="user"&&r!=="assistant")return null;let a=r==="assistant"?"assistant":"user",i=s.message&&typeof s.message=="object"?s.message:null,c=i?i.content:s.content??s.text,l={kind:"message"},d=Po(c,l);if(!d.preview&&!d.raw&&l.kind==="message")return null;let p=i&&i.usage&&typeof i.usage=="object"?i.usage:{},m=(i&&typeof i.model=="string"?i.model:null)??(typeof s.model=="string"?s.model:null);m&&(n.lastModel=m);let y=typeof s.timestamp=="string"?s.timestamp:typeof s.ts=="string"?s.ts:null;return{sessionId:n.sessionId,seq:t,role:a,eventKind:l.kind,model:a==="assistant"?m??n.lastModel:null,project:n.project,ts:y,text:d.preview,rawText:d.raw,tokenIn:Number(p.input_tokens??0)||0,tokenOut:Number(p.output_tokens??0)||0,meta:{role:a,eventKind:l.kind,agent:"cursor",workspaceSlug:n.workspaceSlug,uuid:s.uuid??s.id??null,stopReason:(i&&i.stop_reason)??null,cacheRead:Number(p.cache_read_input_tokens??0)||0,cacheCreation:Number(p.cache_creation_input_tokens??0)||0}}}function Pt(e,t){return{sessionId:t||jo(e),project:null,workspaceSlug:Oo(e),lastModel:null}}function zt(e){let t=$o(e,"utf8").split(/\r?\n/),n=Pt(e),o=[];for(let s=0;s<t.length;s++){let r=Lt(t[s],s,n);r&&o.push(r)}return{sessionId:n.sessionId,project:n.project,events:o}}function Ft(e,t,n,o){let s=Co(e),r=s.size,a=`${s.dev}-${s.ino}`,i=t,c=n;i>r&&(i=0,c=0);let l=Pt(e,o),d=[];if(r<=i)return{events:d,sessionId:l.sessionId,project:l.project,inode:a,byteOffset:i,lineNo:c,fileSize:r,hasMore:!1};let p=r-i,m=Math.min(p,To),y=Buffer.alloc(m),g=Io(e,"r");try{Ro(g,y,0,m,i)}finally{Ao(g)}let k=y.lastIndexOf(10);if(k<0){if(m<p){let f=i+m;return{events:d,sessionId:l.sessionId,project:l.project,inode:a,byteOffset:f,lineNo:c,fileSize:r,hasMore:f<r}}return{events:d,sessionId:l.sessionId,project:l.project,inode:a,byteOffset:i,lineNo:c,fileSize:r,hasMore:!1}}let b=y.subarray(0,k+1),S=b.toString("utf8").split(/\r?\n/);S.length&&S[S.length-1]===""&&S.pop();for(let f=0;f<S.length;f++){let x=Lt(S[f],c+f,l);x&&d.push(x)}let w=i+b.length;return{events:d,sessionId:l.sessionId,project:l.project,inode:a,byteOffset:w,lineNo:c+S.length,fileSize:r,hasMore:w<r}}import{readFileSync as zo,statSync as Fo}from"node:fs";import{basename as Ko}from"node:path";var tt=4e3;function et(e){let t=e.split(/[\\/]/).filter(Boolean),n=t.lastIndexOf("tmp");return n>=0&&t[n+1]?`gemini-${t[n+1]}`:`gemini-${Ko(e).replace(/\.json$/i,"")}`}function Uo(e){if(Array.isArray(e))return e.filter(t=>t&&typeof t=="object");if(e&&typeof e=="object"){let t=e;for(let n of["messages","history","chunks","entries","turns"])if(Array.isArray(t[n]))return t[n].filter(o=>o&&typeof o=="object")}return[]}function Go(e,t,n){let o=[],s=[];for(let r of e){if(!r||typeof r!="object")continue;let a=r;if(typeof a.text=="string")o.push(a.text),s.push(a.text);else if(a.functionCall&&typeof a.functionCall=="object"){t.kind="tool_call";let i=a.functionCall,c=i.name??"tool",l="";try{l=JSON.stringify(i.args??{})}catch{}o.push(`[tool_call:${c}]`),s.push(`[tool_call:${c}] ${l}`)}else if(a.functionResponse&&typeof a.functionResponse=="object"){t.kind="tool_result",n.role="tool";let i=a.functionResponse,c=i.name??"tool",l="";try{l=typeof i.response=="string"?i.response:JSON.stringify(i.response??{})}catch{}o.push(`[tool_result:${c}] ${l.slice(0,300)}`),s.push(`[tool_result:${c}] ${l}`)}}return{preview:o.join(`
|
|
11
|
+
`).slice(0,tt).trim(),raw:s.join(`
|
|
12
|
+
`).trim()}}function Wo(e,t,n){let o=e.content??e.text??e.message;if(typeof o=="string")return{preview:o.slice(0,tt),raw:o};if(Array.isArray(e.parts))return Go(e.parts,t,n);if(Array.isArray(o)){let s=[];for(let a of o)a&&typeof a=="object"&&a.type==="text"&&s.push(String(a.text??""));let r=s.join(`
|
|
13
|
+
`);return{preview:r.slice(0,tt),raw:r}}return{preview:"",raw:""}}function Jo(e){let t=e.toLowerCase();return t==="user"||t==="human"?"user":t==="gemini"||t==="model"||t==="assistant"||t==="ai"?"assistant":t==="tool"||t==="function"||t==="function_response"||t==="tool_result"?"tool":t==="system"?"system":null}function Kt(e,t){let n;try{let a=zo(e,"utf8").trim();if(!a)return{sessionId:t||et(e),project:null,events:[]};n=JSON.parse(a)}catch{return{sessionId:t||et(e),project:null,events:[]}}let o=Uo(n),s={sessionId:t||et(e),project:null,lastModel:null};if(n&&typeof n=="object"&&!Array.isArray(n)){let a=n;typeof a.sessionId=="string"&&a.sessionId&&(s.sessionId=a.sessionId);for(let i of["projectDir","cwd","project"])typeof a[i]=="string"&&a[i]&&(s.project=a[i])}let r=[];for(let a=0;a<o.length;a++){let i=o[a];for(let k of["sessionId","session_id"])typeof i[k]=="string"&&i[k]&&(s.sessionId=i[k]);for(let k of["projectDir","cwd","project"])typeof i[k]=="string"&&i[k]&&(s.project=i[k]);let c=(typeof i.type=="string"?i.type:"")||(typeof i.role=="string"?i.role:""),l=Jo(c);if(!l)continue;let d={role:l},p={kind:"message"},m=Wo(i,p,d);if(!m.preview&&!m.raw)continue;let y=typeof i.model=="string"?i.model:null;y&&(s.lastModel=y);let g=typeof i.timestamp=="string"?i.timestamp:typeof i.ts=="string"?i.ts:null;r.push({sessionId:s.sessionId,seq:a,role:d.role,eventKind:p.kind,model:d.role==="assistant"&&p.kind==="message"?y??s.lastModel:null,project:s.project,ts:g,text:m.preview,rawText:m.raw,tokenIn:0,tokenOut:0,meta:{role:d.role,eventKind:p.kind,agent:"gemini",id:i.id??i.messageId??null}})}return{sessionId:s.sessionId,project:s.project,events:r}}function Ut(e){return Kt(e)}function Gt(e,t,n,o){let s=Fo(e),r=s.size,a=`${s.dev}-${s.ino}`,i=n>0?n:0,c=Kt(e,o),l=c.events.filter(p=>p.seq>=i),d=c.events.length>0?c.events[c.events.length-1].seq+1:i;return{events:l,sessionId:c.sessionId,project:c.project,inode:a,byteOffset:r,lineNo:Math.max(i,d),fileSize:r,hasMore:!1}}import{readFileSync as Ho,readdirSync as qo}from"node:fs";import{join as we,dirname as X,basename as Z}from"node:path";var Bo=4e3,Xo=300;function ot(e){let t=X(e),n=X(t);if(Z(n)==="message")return{storageRoot:X(n),sessionId:Z(t)};let o=X(n);return Z(o)==="part"?{storageRoot:X(o),sessionId:Z(n)}:null}function Wt(e){try{let t=JSON.parse(Ho(e,"utf8"));return t&&typeof t=="object"?t:null}catch{return null}}function Jt(e){try{return qo(e).filter(t=>t.toLowerCase().endsWith(".json")).sort()}catch{return[]}}function nt(e){let t=e.time;if(t&&typeof t=="object"){let o=t.created,s=Number(o);if(Number.isFinite(s))return s}let n=Number(e.created??e.timestamp);return Number.isFinite(n)?n:0}function Zo(e){let t=e.time;if(t&&typeof t=="object"){let n=t.completed,o=Number(n);if(Number.isFinite(o)&&o>0)return o}return null}function Yo(e){if(!e)return null;try{return new Date(e).toISOString()}catch{return null}}function Vo(e,t){let n=[],o=[],s=!1,r=!1,a=!1;for(let i of e){let c=String(i.type??"");if(c==="text"){let l=String(i.text??"");l&&(s=!0,n.push(l),o.push(l))}else if(c==="reasoning"){a=!0;let l=String(i.text??i.reasoning??"");l&&o.push(l)}else if(c==="tool"){r=!0;let l=String(i.tool??i.name??"tool"),d=i.state&&typeof i.state=="object"?i.state:{},p="",m="";try{p=typeof d.input=="string"?d.input:JSON.stringify(d.input??i.input??{})}catch{}try{m=typeof d.output=="string"?d.output:JSON.stringify(d.output??"")}catch{}n.push(`[tool:${l}] ${m.slice(0,Xo)}`),o.push(`[tool:${l}] input=${p}
|
|
14
|
+
output=${m}`)}}return t.kind=s?"message":r?"tool_call":a?"reasoning":"message",{preview:n.join(`
|
|
15
|
+
`).slice(0,Bo).trim(),raw:o.join(`
|
|
16
|
+
`).trim()}}function Qo(e,t,n,o){if(Array.isArray(o.parts))return o.parts.filter(a=>a&&typeof a=="object");let s=we(e,"part",t,n),r=[];for(let a of Jt(s)){let i=Wt(we(s,a));i&&r.push(i)}return r}function es(e){let t=e.toLowerCase();return t==="assistant"||t==="model"||t==="ai"?"assistant":t==="tool"||t==="function"?"tool":t==="system"?"system":"user"}function st(e,t){let n=we(e,"message",t),s=Jt(n).map(c=>c.replace(/\.json$/i,"")).map(c=>({id:c,data:Wt(we(n,`${c}.json`))})).filter(c=>c.data!==null);s.sort((c,l)=>nt(c.data)-nt(l.data)||c.id.localeCompare(l.id));let r=null,a=[],i=0;for(let c=0;c<s.length;c++){let l=s[c].data,d=es(String(l.role??"user")),p=c===s.length-1;if(!(d!=="assistant"||Zo(l)!==null||!p))break;let y={kind:"message",role:d},g=Qo(e,t,s[c].id,l),k=Vo(g,y),b=l.path&&typeof l.path=="object"?l.path:null,S=(b&&typeof b.cwd=="string"?b.cwd:null)??(typeof l.cwd=="string"?l.cwd:null)??(typeof l.directory=="string"?l.directory:null);S&&!r&&(r=S);let w=(typeof l.modelID=="string"?l.modelID:null)??(typeof l.model=="string"?l.model:null),f=l.tokens&&typeof l.tokens=="object"?l.tokens:{};i=c+1,!(!k.preview&&!k.raw)&&a.push({sessionId:t,seq:c,role:y.role,eventKind:y.kind,model:y.role==="assistant"&&y.kind==="message"?w:null,project:r,ts:Yo(nt(l)),text:k.preview,rawText:k.raw,tokenIn:Number(f.input??0)||0,tokenOut:Number(f.output??0)||0,meta:{role:y.role,eventKind:y.kind,agent:"opencode",messageId:s[c].id,providerID:l.providerID??null,modelID:w}})}return{sessionId:t,project:r,events:a,watermark:i}}function Ht(e){let t=e.toLowerCase().endsWith(".json")?e:we(e,"_.json"),n=ot(t);if(!n){let s=Z(e),r=X(e);Z(r)==="message"&&(n={storageRoot:X(r),sessionId:s})}if(!n)return{sessionId:Z(e),project:null,events:[]};let o=st(n.storageRoot,n.sessionId);return{sessionId:o.sessionId,project:o.project,events:o.events}}var qt=(e,t)=>{let n=process.env[e];return n===void 0?t:n==="1"||n.toLowerCase()==="true"},ts=[{name:"private_key_block",re:/-----BEGIN[ A-Z]*PRIVATE KEY-----[\s\S]*?-----END[ A-Z]*PRIVATE KEY-----/g,mask:"\xABPRIVATE_KEY\xBB"},{name:"aws_access_key",re:/\bAKIA[0-9A-Z]{16}\b/g,mask:"\xABAWS_KEY\xBB"},{name:"anthropic_key",re:/\bsk-ant-[A-Za-z0-9_\-]{20,}\b/g,mask:"\xABANTHROPIC_KEY\xBB"},{name:"openai_key",re:/\bsk-(?!ant-)[A-Za-z0-9_\-]{20,}\b/g,mask:"\xABOPENAI_KEY\xBB"},{name:"github_pat",re:/\bgh[pousr]_[A-Za-z0-9]{20,}\b/g,mask:"\xABGITHUB_PAT\xBB"},{name:"github_fine_pat",re:/\bgithub_pat_[A-Za-z0-9_]{22,}\b/g,mask:"\xABGITHUB_PAT\xBB"},{name:"gitlab_pat",re:/\bglpat-[A-Za-z0-9_\-]{16,}\b/g,mask:"\xABGITLAB_PAT\xBB"},{name:"sendgrid_key",re:/\bSG\.[A-Za-z0-9_\-]{16,}\.[A-Za-z0-9_\-]{16,}\b/g,mask:"\xABSENDGRID_KEY\xBB"},{name:"google_api_key",re:/\bAIza[0-9A-Za-z_\-]{35}\b/g,mask:"\xABGOOGLE_API_KEY\xBB"},{name:"slack_token",re:/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g,mask:"\xABSLACK_TOKEN\xBB"},{name:"stripe_key",re:/\b(sk|rk)_(live|test)_[0-9A-Za-z]{16,}\b/g,mask:"\xABSTRIPE_KEY\xBB"},{name:"authorization_header",re:/\b(authorization)\b\s*[:=]\s*["']?(?:bearer|basic|digest|token)?\s*[A-Za-z0-9._\-+/=]{8,}/gi,mask:"$1: \xABREDACTED\xBB"},{name:"jwt",re:/\beyJ[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\b/g,mask:"\xABJWT\xBB"},{name:"bearer_token",re:/\b([Bb]earer)\s+[A-Za-z0-9._\-]{16,}\b/g,mask:"$1 \xABTOKEN\xBB"},{name:"db_url",re:/\b(postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqp):\/\/[^\s/:@]+:[^\s/@]+@[^\s]+/gi,mask:"$1://\xABREDACTED\xBB"},{name:"url_basic_auth",re:/\b(https?:\/\/[^\s:/@]+):[^\s:/@]+@/gi,mask:"$1:\xABREDACTED\xBB@"},{name:"npm_token",re:/\bnpm_[A-Za-z0-9]{36}\b/g,mask:"\xABNPM_TOKEN\xBB"},{name:"pypi_token",re:/\bpypi-[A-Za-z0-9_\-]{16,}/g,mask:"\xABPYPI_TOKEN\xBB"},{name:"hf_token",re:/\bhf_[A-Za-z0-9]{34,}\b/g,mask:"\xABHF_TOKEN\xBB"},{name:"google_oauth_refresh",re:/\b1\/\/[A-Za-z0-9_\-]{20,}/g,mask:"\xABGOOGLE_OAUTH_REFRESH\xBB"},{name:"gcp_sa_field",re:/("(?:private_key_id|client_email|private_key)"\s*:\s*)"(?:\\.|[^"\\])*"/gi,mask:'$1"\xABREDACTED\xBB"'},{name:"azure_sas_sig",re:/([?&]sig=)[A-Za-z0-9%]{10,}/gi,mask:"$1\xABREDACTED\xBB"},{name:"azure_account_key",re:/\b(AccountKey=)[A-Za-z0-9+/=]{10,}/gi,mask:"$1\xABREDACTED\xBB"},{name:"secret_kv",re:/\b([A-Za-z0-9_.\-]*(?:password|passwd|pwd|secret|token|api[_-]?key|apikey|access[_-]?key|client[_-]?secret|private[_-]?key|credential|passphrase)[A-Za-z0-9_.\-]*)\s*[=:]\s*["']?(?!«)[^\s"',;]{4,}/gi,mask:"$1=\xABREDACTED\xBB"},{name:"cn_idcard",re:/\b[1-9]\d{5}(?:19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}[\dXx]\b/g,mask:"\xABIDCARD\xBB"},{name:"credit_card",re:/\b(?:\d{4}[ -]?){3}\d{4}\b/g,mask:"\xABCREDIT_CARD\xBB"},{name:"cn_phone",re:/(?<!\d)1[3-9]\d{9}(?!\d)/g,mask:"\xABPHONE\xBB"},{name:"email",re:/\b[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}\b/g,mask:"\xABEMAIL\xBB",enabled:()=>qt("AGENTMEM_REDACT_EMAIL",!0)},{name:"private_ip",re:/\b(?:10\.\d{1,3}\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|172\.(?:1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3})\b/g,mask:"\xABPRIVATE_IP\xBB",enabled:()=>qt("AGENTMEM_REDACT_IP",!1)}];function ke(e){let t=e??"",n=[],o={};for(let s of ts){if(s.enabled&&!s.enabled())continue;let r=t.match(s.re),a=r?r.length:0;a>0&&(t=t.replace(s.re,s.mask),n.push(s.name),o[s.name]=a)}return{text:t,rulesHit:n,counts:o}}function ns(e){return e?/[一-鿿]/.test(e)?"zh":"en":null}function se(e){return e.split("\0").join("").replace(/\\u0000/gi,"")}function os(e){let t=se(e).replace(/\s+/g," ").trim();return t?t.slice(0,200):null}var Bt=5*1024*1024,Xt=32*1024,ss=/^\s*<\/?(system-reminder|extremely_important|task-notification|local-command-(caveat|stdout|stderr)|command-(name|message|args)|bash-(input|stdout|stderr)|user-prompt-submit-hook|session-start-hook)\b/i;function rs(e){let t=(e??"").replace(/<system-reminder>[\s\S]*?<\/system-reminder>/gi,"").replace(/<local-command-caveat>[\s\S]*?<\/local-command-caveat>/gi,"").replace(/<EXTREMELY_IMPORTANT>[\s\S]*?<\/EXTREMELY_IMPORTANT>/gi,"").replace(/<task-notification>[\s\S]*?<\/task-notification>/gi,"").trim();if(!t||ss.test(t))return"";let n=t.slice(0,400);return/^Base directory for this skill:/i.test(n)||/SessionStart hook additional context/i.test(n)||/You have superpowers/i.test(n)||/\[SYSTEM NOTIFICATION - NOT USER INPUT\]/i.test(n)||/^Caveat: The messages below were generated by the user while running local commands/i.test(n)?"":t}function Se(e,t,n,o="claude-code"){let s=[],r={},a=0,i={};for(let c of e){let l=ke(c.text);for(let g of l.rulesHit)r[g]=(r[g]??0)+l.counts[g],a+=l.counts[g];i[c.eventKind]=(i[c.eventKind]??0)+1;let d={role:c.role,eventKind:c.eventKind,...c.meta,redaction:{rulesHit:l.rulesHit,counts:l.counts}},p=c.meta.isSidechain?["sidechain"]:[],m=null;if(c.rawText&&c.rawText.length>c.text.length){let g=se(ke(c.rawText).text);g.length>Bt&&(g=g.slice(0,Bt)+`
|
|
17
|
+
\u2026[\u539F\u6587\u8D85 5MB \u5DF2\u622A\u65AD]`),m=g}let y=null;if(c.eventKind==="message"&&!c.meta.isMeta){let g=rs(se(ke(c.rawText??c.text).text));y=g?g.length>Xt?g.slice(0,Xt)+`
|
|
18
|
+
\u2026[\u5185\u5BB9\u8FC7\u957F\u5DF2\u622A\u65AD]`:g:null}s.push({clientId:t,agentType:o,surface:n,sessionId:c.sessionId,seq:c.seq,model:c.model,language:ns(l.text),project:c.project,title:c.title?se(ke(c.title).text):null,summary:os(l.text),content:y,tags:se(JSON.stringify(p)),meta:se(JSON.stringify(d)),ossKey:null,raw:m,tokenIn:c.tokenIn,tokenOut:c.tokenOut,ts:c.ts})}return{dtos:s,totalHits:a,ruleCounts:r,kindBreakdown:i}}import{hostname as Zt,homedir as re}from"node:os";import{join as j,delimiter as is}from"node:path";import{readFileSync as as,writeFileSync as cs,mkdirSync as ls,existsSync as Yt}from"node:fs";import{randomUUID as us,createHash as ds}from"node:crypto";function ie(){let e=j(re(),".agentmem"),t=j(e,"client.json");try{if(Yt(t)){let o=JSON.parse(as(t,"utf8"));if(o&&typeof o.clientId=="string"&&o.clientId)return o.clientId}}catch{}let n=ds("sha256").update(`${Zt()}|${us()}`).digest("hex").slice(0,24);try{ls(e,{recursive:!0}),cs(t,JSON.stringify({clientId:n,host:Zt(),createdAt:new Date().toISOString()},null,2))}catch{}return n}function Y(){return process.env.AGENTMEM_CLAUDE_DIR?process.env.AGENTMEM_CLAUDE_DIR:process.env.CLAUDE_CONFIG_DIR?j(process.env.CLAUDE_CONFIG_DIR,"projects"):j(re(),".claude","projects")}function V(){return process.env.AGENTMEM_CODEX_DIR?process.env.AGENTMEM_CODEX_DIR:process.env.CODEX_HOME?j(process.env.CODEX_HOME,"sessions"):j(re(),".codex","sessions")}function ae(){return process.env.AGENTMEM_CURSOR_DIR?process.env.AGENTMEM_CURSOR_DIR:j(re(),".cursor","projects")}function ce(){return process.env.AGENTMEM_GEMINI_DIR?process.env.AGENTMEM_GEMINI_DIR:process.env.GEMINI_HOME?j(process.env.GEMINI_HOME,"tmp"):j(re(),".gemini","tmp")}function le(){return process.env.AGENTMEM_OPENCODE_DIR?process.env.AGENTMEM_OPENCODE_DIR:process.env.OPENCODE_DATA?j(process.env.OPENCODE_DATA,"storage"):process.env.XDG_DATA_HOME?j(process.env.XDG_DATA_HOME,"opencode","storage"):j(re(),".local","share","opencode","storage")}function be(){let e=process.env.AGENTMEM_EXTRA_DIRS;if(!e)return[];let t=e.split(new RegExp(`[${is},]`)),n=new Set,o=[];for(let s of t){let r=s.trim();!r||n.has(r)||(n.add(r),Yt(r)&&o.push(r))}return o}import{createHmac as fs,randomUUID as ps}from"node:crypto";function z(e,t,n,o,s,r){let a=`${e}&${t}&${n}&${o}&${s}`;return fs("sha256",r).update(a,"utf8").digest("base64")}function F(){return ps().replace(/-/g,"")}function K(e){return Math.floor(e/1e3).toString()}var A="0.1.3",U=`agentmem/${A} (node ${process.versions.node}; ${process.platform})`;function ms(){let e=(process.env.AGENTMEM_LANG||"").toLowerCase();if(e.startsWith("zh"))return"zh";if(e.startsWith("en"))return"en";let t="";try{t=Intl.DateTimeFormat().resolvedOptions().locale||""}catch{}return t=(t||process.env.LC_ALL||process.env.LC_MESSAGES||process.env.LANG||process.env.LANGUAGE||"").toLowerCase(),t.startsWith("zh")?"zh":"en"}var gs=ms();function u(e,t){return gs==="zh"?e:t}var Vt="/api/ingest/ingest",Q=class extends Error{},ue=class extends Error{},de=class extends Error{retryAfterMs;constructor(t,n=0){super(t),this.retryAfterMs=n}},De=0;function Qt(){return De}function hs(e){if(!e)return 0;let t=Number(e);if(Number.isFinite(t))return Math.max(0,t*1e3);let n=Date.parse(e);return Number.isFinite(n)?Math.max(0,n-Date.now()):0}async function rt(e,t){let n=K(Date.now()),o=F(),s=z("POST",Vt,e.accessKey,n,o,e.accessSecret),r=new AbortController,a=setTimeout(()=>r.abort(),e.timeoutMs??1e4),i;try{i=await fetch(e.endpoint+Vt,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":U,accessKey:e.accessKey,timestamp:n,nonce:o,sign:s},body:JSON.stringify({events:t}),signal:r.signal})}catch(m){throw new Q(u(`\u7F51\u7EDC/\u8D85\u65F6: ${m instanceof Error?m.message:String(m)}`,`Network/timeout: ${m instanceof Error?m.message:String(m)}`))}finally{clearTimeout(a)}let c=i.headers.get("date");if(c){let m=Date.parse(c);Number.isFinite(m)&&(De=m-Date.now())}if(i.status>=500)throw new Q(u(`\u670D\u52A1\u7AEF ${i.status}`,`Server error ${i.status}`));if(i.status===401||i.status===403){let m=Math.round(De/1e3);throw Math.abs(De)>12e4?new Q(u(`\u9274\u6743\u5931\u8D25 ${i.status}(\u7591\u4F3C\u65F6\u949F\u6F02\u79FB ${m}s,\u8D85\u7B7E\u540D 5 \u5206\u949F\u7A97;\u5C06\u9000\u907F\u91CD\u8BD5,\u8BF7\u6821\u51C6\u7CFB\u7EDF\u65F6\u95F4)`,`Auth failed ${i.status} (suspected clock drift ${m}s, exceeds 5-min signature window; will retry with backoff, please sync system clock)`)):new ue(u(`\u9274\u6743\u5931\u8D25 ${i.status}(\u68C0\u67E5\u51ED\u8BC1/\u65F6\u949F\u6F02\u79FB ${m}s)`,`Auth failed ${i.status} (check credentials / clock drift ${m}s)`))}if(i.status===429)throw new de(u("\u9650\u6D41 429","Rate limited 429"),hs(i.headers.get("retry-after"))||6e4);let l=await i.text(),d;try{d=JSON.parse(l)}catch{throw new Q(u(`\u975E JSON \u54CD\u5E94(HTTP ${i.status}): ${l.slice(0,160)}`,`Non-JSON response (HTTP ${i.status}): ${l.slice(0,160)}`))}if(d.code===200)return d.result??{accepted:0};let p=d.message??"";throw/配额|超额|quota|限额|exceed/i.test(p)?new de(u(`\u914D\u989D\u53D7\u9650: ${p}`,`Quota limited: ${p}`),5*6e4):new ue(u(`ingest \u62D2\u7EDD code=${d.code} message=${p}`,`Ingest rejected code=${d.code} message=${p}`))}function ys(e){return new Promise(t=>setTimeout(t,e))}async function en(e,t,n=100,o=5){let s=0;for(let r=0;r<t.length;r+=n){let a=t.slice(r,r+n),i=0;for(;;)try{s+=(await rt(e,a)).accepted;break}catch(c){if(c instanceof Q&&i<o){i++;let l=500*2**(i-1);await ys(l+Math.floor(Math.random()*l));continue}throw c}}return s}import{readFileSync as Fe,existsSync as Ke}from"node:fs";import{join as Ue}from"node:path";import{homedir as ws}from"node:os";import{join as fe,dirname as nn}from"node:path";import{mkdirSync as it,writeFileSync as ks,readFileSync as on,renameSync as Ss,existsSync as bs,openSync as sn,closeSync as rn,writeSync as an,fsyncSync as cn,statSync as ln,statfsSync as vs,rmSync as Le,copyFileSync as xs,chmodSync as Es}from"node:fs";import{randomUUID as _s}from"node:crypto";import{execFileSync as tn}from"node:child_process";var I=fe(ws(),".agentmem");function O(e){return new Promise(t=>setTimeout(t,e))}function G(e){it(e,{recursive:!0})}function Pe(e){return G(I),fe(I,e)}function un(){let e=fe(I,"spool");return G(e),e}function pe(){let e=fe(I,"logs");return G(e),e}function $(e,t){G(nn(e));let n=`${e}.tmp.${process.pid}.${_s().slice(0,8)}`,o=sn(n,"w");try{an(o,t),cn(o)}finally{rn(o)}Ss(n,e)}function ze(e,t){G(nn(e));let n=sn(e,"a");try{an(n,t),cn(n)}finally{rn(n)}}function ve(e){try{let t=vs(e);return Number(t.bavail)*Number(t.bsize)}catch{return-1}}function dn(e){try{return ln(e).size}catch{return 0}}function fn(e,t){$(e,t);try{if(process.platform==="win32"){tn("icacls",[e,"/inheritance:r"],{stdio:"ignore"});let n=process.env.USERNAME||process.env.USER;n&&tn("icacls",[e,"/grant:r",`${n}:F`],{stdio:"ignore"})}else Es(e,384)}catch{}}function ee(e){if(!bs(e))return null;let t;try{t=on(e,"utf8")}catch{return null}if(t.charCodeAt(0)===65279&&(t=t.slice(1)),!t.trim())return null;try{return JSON.parse(t)}catch{try{xs(e,`${e}.corrupt`)}catch{}return null}}async function W(e,t,n={}){let o=n.staleMs??3e4,s=n.retryMs??50,r=n.timeoutMs??15e3,a=Date.now();for(;;)try{it(e);break}catch{try{let i=ln(e);if(Date.now()-i.mtimeMs>o){Le(e,{recursive:!0,force:!0});continue}}catch{}if(Date.now()-a>r)throw new Error(u(`\u83B7\u53D6\u9501\u8D85\u65F6: ${e}`,`Lock acquisition timed out: ${e}`));await O(s)}try{return await t()}finally{try{Le(e,{recursive:!0,force:!0})}catch{}}}function $s(e){if(!e)return!1;try{return process.kill(e,0),!0}catch(t){return t?.code==="EPERM"}}function me(e){try{let t=Number(on(fe(e,"pid"),"utf8").trim());return $s(t)}catch{return!1}}function pn(e){for(let t=0;t<2;t++)try{it(e);try{ks(fe(e,"pid"),String(process.pid))}catch{}return()=>{try{Le(e,{recursive:!0,force:!0})}catch{}}}catch{if(me(e))return null;try{Le(e,{recursive:!0,force:!0});continue}catch{return null}}return null}function Cs(e){return`${e.sessionId}:${e.seq}`}var D=class{outbox;ackedLog;deadFile;lock;map=new Map;acked=new Set;dead=new Set;constructor(){let t=un();this.outbox=Ue(t,"outbox.jsonl"),this.ackedLog=Ue(t,"acked.log"),this.deadFile=Ue(t,"dead.jsonl"),this.lock=Ue(t,"spool.lock"),this.load()}load(){if(Ke(this.ackedLog))for(let t of Fe(this.ackedLog,"utf8").split(`
|
|
19
|
+
`)){let n=t.trim();n&&this.acked.add(n)}if(Ke(this.deadFile))for(let t of Fe(this.deadFile,"utf8").split(`
|
|
20
|
+
`)){let n=t.trim();if(n)try{this.dead.add(JSON.parse(n).id)}catch{}}if(Ke(this.outbox))for(let t of Fe(this.outbox,"utf8").split(`
|
|
21
|
+
`)){let n=t.trim();if(n)try{let o=JSON.parse(n);if(!o?.id||this.acked.has(o.id)||this.dead.has(o.id))continue;this.map.set(o.id,o)}catch{}}}async enqueue(t){let n=[];for(let o of t){let s=Cs(o);this.map.has(s)||this.acked.has(s)||this.dead.has(s)||n.push({id:s,payload:o,enqueuedAt:Date.now(),attempts:0})}if(!n.length)return 0;await W(this.lock,()=>{ze(this.outbox,n.map(o=>JSON.stringify(o)).join(`
|
|
22
|
+
`)+`
|
|
23
|
+
`)});for(let o of n)this.map.set(o.id,o);return n.length}pending(t,n=0){let o=Date.now(),s=[];for(let r of this.map.values())if(!(n>0&&r.sentAt&&o-r.sentAt<n)&&(s.push(r),s.length>=t))break;return s}markSent(t){let n=Date.now();for(let o of t){let s=this.map.get(o);s&&(s.sentAt=n)}}allEntries(){return[...this.map.values()]}async ack(t){let n=t.filter(o=>this.map.has(o));if(n.length){await W(this.lock,()=>{ze(this.ackedLog,n.join(`
|
|
24
|
+
`)+`
|
|
25
|
+
`)});for(let o of n)this.acked.add(o),this.map.delete(o);this.acked.size>2e3&&this.acked.size>this.map.size*2&&await this.compact()}}async deadletter(t,n){let o=t.map(s=>this.map.get(s)).filter(s=>!!s);if(o.length){await W(this.lock,()=>{ze(this.deadFile,o.map(s=>JSON.stringify({id:s.id,reason:n,at:Date.now(),payload:s.payload})).join(`
|
|
26
|
+
`)+`
|
|
27
|
+
`)});for(let s of o)this.dead.add(s.id),this.map.delete(s.id)}}async requeueDead(){if(!Ke(this.deadFile))return 0;let t=[],n=[];for(let s of Fe(this.deadFile,"utf8").split(`
|
|
28
|
+
`)){let r=s.trim();if(r)try{let a=JSON.parse(r);a?.id&&a.payload&&(n.push(a.id),t.push(a.payload))}catch{}}for(let s of n)this.dead.delete(s);let o=t.length?await this.enqueue(t):0;return await W(this.lock,()=>{$(this.deadFile,"")}),o}markAttempt(t){for(let n of t){let o=this.map.get(n);o&&o.attempts++}}stats(){let t=0;if(this.map.size){let n=1/0;for(let o of this.map.values())o.enqueuedAt<n&&(n=o.enqueuedAt);t=n===1/0?0:Math.max(0,Date.now()-n)}return{pending:this.map.size,acked:this.acked.size,dead:this.dead.size,oldestMs:t,bytes:dn(this.outbox)}}async compact(){await W(this.lock,()=>{let t=[...this.map.values()].map(n=>JSON.stringify(n));$(this.outbox,t.length?t.join(`
|
|
29
|
+
`)+`
|
|
30
|
+
`:""),$(this.ackedLog,"")}),this.acked.clear()}};import{join as Is}from"node:path";var mn=()=>Pe("cursors.json"),Rs=()=>Is(I,"cursors.lock");function at(){return ee(mn())??{}}function ct(e){return at()[e]??null}function gn(){return at()}async function lt(e){await W(Rs(),()=>{let t=at();t[e.sourcePath]={...e,updatedAt:Date.now()},$(mn(),JSON.stringify(t,null,2))})}var As=256;async function Ge(e,t,n,o,s,r,a){let i=ct(e),c=i?.byteOffset??0,l=i?.lineNo??0,d=i?.sessionId??"";try{let y=ye(e);i&&i.inode&&i.inode!==y&&(a.info(u("\u6587\u4EF6\u8F6E\u8F6C,\u91CD\u626B","File rotated, rescanning"),{file:e}),c=0,l=0)}catch{}let p=0,m=0;for(let y=0;y<As;y++){let g;try{g=n(e,c,l,d||void 0)}catch(b){a.warn(u("\u589E\u91CF\u89E3\u6790\u5931\u8D25,\u7559\u5F85\u4E0B\u6B21","Incremental parse failed, will retry next run"),{file:e,msg:b instanceof Error?b.message:String(b)});break}if(d=g.sessionId,g.events.length){let b=Se(g.events,o,s,t);p+=await r.enqueue(b.dtos),m+=g.events.length}await lt({sourcePath:e,agentType:t,sessionId:g.sessionId,inode:g.inode,byteOffset:g.byteOffset,lineNo:g.lineNo,fileSize:g.fileSize,updatedAt:Date.now()});let k=g.byteOffset>c;if(c=g.byteOffset,l=g.lineNo,!g.hasMore||!k)break}return p&&a.debug(u("\u91C7\u96C6\u5165\u961F","Enqueued for collection"),{file:e,agent:t,events:m,enqueued:p}),{enqueued:p,events:m,sessionId:d}}function te(e,t,n,o,s){return Ge(e,"claude-code",Nt,t,n,o,s)}function ne(e,t,n,o,s){return Ge(e,"codex",Ot,t,n,o,s)}function xe(e,t,n,o,s){return Ge(e,"cursor",Ft,t,n,o,s)}function Ee(e,t,n,o,s){return Ge(e,"gemini",Gt,t,n,o,s)}var Ns="opencode:";async function Ts(e,t,n,o,s,r){let a=Ns+t,i=ct(a)?.lineNo??0,c;try{c=st(e,t)}catch(p){return r.warn(u("OpenCode \u805A\u5408\u5931\u8D25,\u7559\u5F85\u4E0B\u6B21","OpenCode assemble failed, will retry next run"),{sessionId:t,msg:p instanceof Error?p.message:String(p)}),{enqueued:0,events:0,sessionId:t}}let l=c.events.filter(p=>p.seq>=i),d=0;if(l.length){let p=Se(l,n,o,"opencode");d=await s.enqueue(p.dtos)}return await lt({sourcePath:a,agentType:"opencode",sessionId:t,inode:"",byteOffset:0,lineNo:Math.max(i,c.watermark),fileSize:0,updatedAt:Date.now()}),d&&r.debug(u("\u91C7\u96C6\u5165\u961F","Enqueued for collection"),{session:t,agent:"opencode",events:l.length,enqueued:d}),{enqueued:d,events:l.length,sessionId:t}}function _e(e,t,n,o,s){let r=ot(e);return r?Ts(r.storageRoot,r.sessionId,t,n,o,s):Promise.resolve({enqueued:0,events:0,sessionId:""})}var Ms=2*1024*1024,js=8;function Os(e){try{return Buffer.byteLength(JSON.stringify(e),"utf8")}catch{return 0}}async function $e(e,t,n,o={}){let s=o.batchSize??100,r=o.maxWallMs??6e4,a=o.maxBackoffMs??3e5,i=Date.now(),c=0,l=0,d=0,p=500,m=(y,g)=>({sent:c,accepted:l,parked:y,parkedUntilMs:g,dead:d,remaining:t.stats().pending,driftMs:Qt()});for(;!(Date.now()-i>r);){let y=t.pending(s,15e3);if(!y.length)break;let g=[],k=0;for(let w of y){let f=Os(w.payload);if(g.length>0&&k+f>Ms)break;g.push(w),k+=f}if(g.length===1&&g[0].attempts>=js){await t.deadletter([g[0].id],u(`\u8FDE\u7EED ${g[0].attempts} \u6B21\u4E0A\u62A5\u5931\u8D25(\u7591\u4F3C\u8D85\u5927/\u6BD2\u4E38\u4E8B\u4EF6 ${Math.round(k/1024)}KB),\u9694\u79BB\u8F6C\u6B7B\u4FE1`,`Failed ${g[0].attempts} times in a row (suspected oversized/poison event, ${Math.round(k/1024)}KB), isolated to dead-letter`)),d+=1,n.error(u("\u5355\u4E8B\u4EF6\u8FDE\u8D25,\u9694\u79BB\u8F6C\u6B7B\u4FE1(\u9632\u961F\u5934\u963B\u585E)","Single event kept failing, isolated to dead-letter (avoids head-of-line blocking)"),{id:g[0].id,bytes:k});continue}let b=g.map(w=>w.id),S=Math.min(12e4,1e4+Math.floor(k/(200*1024))*1e3);try{let w=await rt({...e,timeoutMs:S},g.map(f=>f.payload));t.markSent(b),c+=b.length,l+=w.accepted,p=500,n.debug(u("flush \u6279\u6B21\u6210\u529F","Flush batch succeeded"),{sent:b.length,accepted:w.accepted})}catch(w){if(w instanceof de){let x=Date.now()+(w.retryAfterMs||3e5);return n.warn(u("\u914D\u989D/\u9650\u6D41,\u6682\u505C\u4E0A\u62A5(\u6570\u636E\u5DF2\u5B89\u5168\u7F13\u5B58)","Quota/rate limited, pausing upload (data safely cached)"),{msg:w.message,retryInMs:w.retryAfterMs}),m(!0,x)}if(w instanceof ue){await t.deadletter(b,w.message),d+=b.length,n.error(u("\u6279\u6B21\u4E0D\u53EF\u91CD\u8BD5,\u8F6C\u5165\u6B7B\u4FE1(\u53EF\u4EBA\u5DE5\u91CD\u6295)","Batch not retriable, moved to dead-letter (manual replay possible)"),{count:b.length,msg:w.message});continue}t.markAttempt(b);let f=Math.min(p,a);if(n.warn(u("\u4E0A\u62A5\u5931\u8D25,\u9000\u907F\u91CD\u8BD5","Upload failed, backing off for retry"),{waitMs:f,msg:w instanceof Error?w.message:String(w)}),Date.now()-i+f>r)break;await O(f+Math.floor(Math.random()*Math.min(p,1e3))),p=Math.min(p*2,a)}}return m(!1,0)}var ut=()=>Pe("credentials.json"),J="https://api.huihuayun.cn";function T(){let e=process.env.AGENTMEM_ENDPOINT,t=process.env.AGENTMEM_ACCESS_KEY,n=process.env.AGENTMEM_ACCESS_SECRET,o=ee(ut()),s=t||o?.accessKey,r=n||o?.accessSecret;return!s||!r?null:{endpoint:e||o?.endpoint||J,accessKey:s,accessSecret:r}}function hn(e){fn(ut(),JSON.stringify({...e,savedAt:new Date().toISOString()},null,2))}function yn(){return ut()}import{appendFileSync as Ds,statSync as Sn,renameSync as Ls,readdirSync as Ps,rmSync as zs}from"node:fs";import{join as dt}from"node:path";var wn={debug:10,info:20,warn:30,error:40},Fs=5*1024*1024,Ks=14;function Us(){return new Date().toISOString().slice(0,10)}function Gs(e){try{let t=Date.now()-Ks*864e5;for(let n of Ps(e))if(!(!n.startsWith("agentmem-")||!n.includes(".log")))try{Sn(dt(e,n)).mtimeMs<t&&zs(dt(e,n),{force:!0})}catch{}}catch{}}var kn=!1;function Ce(e="agentmem",t="info",n=!0){let o=wn[t];kn||(kn=!0,Gs(pe()));let s=(r,a,i)=>{if(wn[r]<o)return;let c={ts:new Date().toISOString(),level:r,scope:e,msg:a,...i??{}},l=JSON.stringify(c)+`
|
|
31
|
+
`;try{let d=dt(pe(),`agentmem-${Us()}.log`);try{Sn(d).size>Fs&&Ls(d,d+".1")}catch{}Ds(d,l)}catch{}n&&(r==="error"||r==="warn"?console.error:console.log)(`[${r}] ${a}${i?" "+JSON.stringify(i):""}`)};return{debug:(r,a)=>s("debug",r,a),info:(r,a)=>s("info",r,a),warn:(r,a)=>s("warn",r,a),error:(r,a)=>s("error",r,a)}}import{readdirSync as ft,statSync as Ws}from"node:fs";import{join as We}from"node:path";function bn(e,t){let n;try{n=ft(e,{withFileTypes:!0})}catch{return}for(let o of n){let s=We(e,o.name);o.isDirectory()?bn(s,t):o.isFile()&&o.name.endsWith(".jsonl")&&t.push(s)}}function R(e){let t=[];return bn(e,t),t}var Js=new Set(["settings.json","oauth_creds.json","google_accounts.json","installation_id.json","user_id.json","package.json","mcp.json",".mcp.json"]);function vn(e,t){let n;try{n=ft(e,{withFileTypes:!0})}catch{return}for(let o of n){let s=We(e,o.name);o.isDirectory()?vn(s,t):o.isFile()&&o.name.toLowerCase().endsWith(".json")&&!Js.has(o.name.toLowerCase())&&t.push(s)}}function ge(e){let t=[];return vn(e,t),t}function xn(e,t){let n;try{n=ft(e,{withFileTypes:!0})}catch{return}for(let o of n){let s=We(e,o.name);o.isDirectory()?xn(s,t):o.isFile()&&o.name.toLowerCase().endsWith(".json")&&t.push(s)}}function he(e){let t=[];return xn(We(e,"message"),t),t}function Je(e){let t="",n=0;for(let o of R(e))try{let s=Ws(o).mtimeMs;s>n&&(n=s,t=o)}catch{}return t}import{watch as qs,statSync as $n}from"node:fs";import{hostname as Bs}from"node:os";import{join as Cn}from"node:path";var En="/api/collector/heartbeat";async function pt(e,t,n,o,s){let r=K(Date.now()),a=F(),i=z("POST",En,e.accessKey,r,a,e.accessSecret),c=new AbortController,l=setTimeout(()=>c.abort(),e.timeoutMs??8e3);try{return(await fetch(e.endpoint+En,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":U,accessKey:e.accessKey,timestamp:r,nonce:a,sign:i},body:JSON.stringify({clientId:t,host:n,version:A,events24h:o,errors24h:s}),signal:c.signal})).ok}catch{return!1}finally{clearTimeout(l)}}var Ie=class{buf=[];windowMs;constructor(t=24*36e5){this.windowMs=t}add(t){t>0&&this.buf.push({t:Date.now(),n:t})}sum(){let t=Date.now()-this.windowMs;this.buf=this.buf.filter(o=>o.t>=t);let n=0;for(let o of this.buf)n+=o.n;return n}};var _n="/api/ingest/watermark";async function Hs(e,t,n){let o=new Map;if(!n.length)return o;let s=K(Date.now()),r=F(),a=z("POST",_n,e.accessKey,s,r,e.accessSecret),i=new AbortController,c=setTimeout(()=>i.abort(),e.timeoutMs??1e4);try{let l=await fetch(e.endpoint+_n,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":U,accessKey:e.accessKey,timestamp:s,nonce:r,sign:a},body:JSON.stringify({clientId:t,sessionIds:n}),signal:i.signal});if(!l.ok)return o;let d=await l.json();for(let p of d?.result??[])o.set(p.sessionId,p.maxSeq)}catch{}finally{clearTimeout(c)}return o}async function Re(e,t,n,o){let s=t.allEntries().filter(c=>c.sentAt);if(!s.length)return{acked:0,checked:0};let r=[...new Set(s.map(c=>c.payload.sessionId))],a=await Hs(e,n,r);if(!a.size)return{acked:0,checked:s.length};let i=[];for(let c of s){let l=a.get(c.payload.sessionId);l!==void 0&&c.payload.seq<=l&&i.push(c.id)}return i.length&&(await t.ack(i),o.debug(u("\u6C34\u4F4D ack(\u5DF2\u843D\u5E93\u786E\u8BA4)","watermark ack (persistence confirmed)"),{acked:i.length})),{acked:i.length,checked:s.length}}async function In(e={}){let t=Ce("daemon"),n=pn(Cn(I,"daemon.lock"));if(!n){t.warn(u("\u5DF2\u6709 daemon \u5728\u8FD0\u884C,\u9000\u51FA","daemon already running, exiting"));return}process.on("uncaughtException",h=>t.error(u("uncaughtException(\u5DF2\u5FFD\u7565,\u8FDB\u7A0B\u7EE7\u7EED)","uncaughtException (ignored, process continues)"),{msg:h?.message??String(h)})),process.on("unhandledRejection",h=>t.error(u("unhandledRejection(\u5DF2\u5FFD\u7565)","unhandledRejection (ignored)"),{msg:h instanceof Error?h.message:String(h)}));let o=ie(),s=Bs(),r=e.surface??"cli",a=e.pollMs??3e3,i=e.watchdogMs??3e4,c=e.heartbeatMs??6e4,l=new D,d=T();d||t.warn(u("\u672A\u914D\u7F6E\u51ED\u8BC1(\u8FD0\u884C `agentmem login`);\u5148\u91C7\u96C6\u5230\u672C\u5730 spool,\u8054\u7F51\u6388\u6743\u540E\u81EA\u52A8\u8865\u4F20","No credentials (run `agentmem login`); capturing to local spool, will backfill after authorization"));let p=h=>{let E=h.toLowerCase().split(/[\\/]/).pop()??"";return E.includes("rollout")||/^rollout-.*\.jsonl$/.test(E)},m=(h,E,_,L,P)=>(p(h)?ne:te)(h,E,_,L,P),y=[{dir:Y(),collect:te},{dir:V(),collect:ne},{dir:ae(),collect:xe},{dir:ce(),collect:Ee,list:ge,watchExt:".json"},{dir:le(),collect:_e,list:he,watchExt:".json",accept:h=>/[\\/]message[\\/]/.test(h)}];for(let h of be())y.push({dir:h,collect:m});let g=h=>(h.list??R)(h.dir),k=h=>{let E=h.toLowerCase(),_;for(let L of y)E.startsWith(L.dir.toLowerCase())&&(!_||L.dir.length>_.dir.length)&&(_=L);return _?_.collect:te},b=new Ie,S=new Ie,w=new Map,f=new Map,x=!1,B=!1,Ze=0,je=async()=>{if(d??=T(),!(!d||x)&&!(Date.now()<Ze)){x=!0;try{let h=await $e(d,l,t,{maxWallMs:25e3});h.dead&&S.add(h.dead),h.parked&&(Ze=h.parkedUntilMs),(h.sent||h.parked||h.dead)&&t.info(u("\u4E0A\u62A5","flush"),{sent:h.sent,accepted:h.accepted,dead:h.dead,remaining:h.remaining}),Math.abs(h.driftMs)>12e4&&t.warn(u("\u65F6\u949F\u6F02\u79FB\u8FC7\u5927(\u7B7E\u540D 5min \u7A97\u53E3),\u8BF7\u6821 NTP","Clock drift too large (5min signature window), sync NTP"),{driftSec:Math.round(h.driftMs/1e3)}),await Re(d,l,o,t)}catch(h){S.add(1),t.error(u("drain \u5F02\u5E38","drain error"),{msg:h instanceof Error?h.message:String(h)})}finally{x=!1}}},Ye=h=>{let E=w.get(h);E&&clearTimeout(E),w.set(h,setTimeout(()=>{w.delete(h),(async()=>{try{let _=await k(h)(h,o,r,l,t);_.events&&b.add(_.events),_.enqueued&&await je()}catch(_){S.add(1),t.error(u("\u91C7\u96C6\u5F02\u5E38","capture error"),{file:h,msg:_ instanceof Error?_.message:String(_)})}})()},200))};for(let h of y)for(let E of g(h)){try{f.set(E,$n(E).mtimeMs)}catch{}Ye(E)}let Ve=[],vt=(h,E,_,L)=>{try{let P=qs(h,{recursive:!0},(Oe,Et)=>{if(!Et)return;let Qe=Cn(h,Et.toString());Qe.endsWith(_)&&(!L||L(Qe))&&Ye(Qe)});P.on("error",Oe=>{t.warn(u("watch \u51FA\u9519,\u7A0D\u540E\u91CD\u6302(\u8F6E\u8BE2\u515C\u5E95\u4E2D)","watch error, re-arming later (polling fallback active)"),{dir:h,msg:Oe instanceof Error?Oe.message:String(Oe)});try{P.close()}catch{}Ve[E]=void 0,B||setTimeout(()=>vt(h,E,_,L),2e3)}),Ve[E]=P}catch(P){t.warn(u("fs.watch \u4E0D\u53EF\u7528,\u8BE5\u6E90\u7EAF\u8F6E\u8BE2","fs.watch unavailable, this source uses polling only"),{dir:h,msg:P instanceof Error?P.message:String(P)})}};y.forEach((h,E)=>vt(h.dir,E,h.watchExt??".jsonl",h.accept));let to=setInterval(()=>{for(let h of y)for(let E of g(h)){let _=0;try{_=$n(E).mtimeMs}catch{continue}f.get(E)!==_&&(f.set(E,_),Ye(E))}},a),no=setInterval(()=>{let h=l.stats();t.debug(u("\u5FC3\u8DF3","heartbeat"),{...h}),h.oldestMs>36e5&&t.warn(u("\u79EF\u538B\u8D85 1 \u5C0F\u65F6,\u68C0\u67E5\u7F51\u7EDC/\u51ED\u8BC1/\u914D\u989D","Backlog over 1 hour, check network/credentials/quota"),{pendingMin:Math.round(h.oldestMs/6e4),pending:h.pending});let E=ve(I);E>=0&&E<200*1024*1024&&t.warn(u("\u78C1\u76D8\u53EF\u7528\u7A7A\u95F4\u4E0D\u8DB3 200MB,\u53EF\u80FD\u5F71\u54CD\u7F13\u5B58","Free disk space below 200MB, may affect cache"),{freeMB:Math.round(E/1048576)}),je()},i),oo=setInterval(()=>{d??=T(),d&&pt(d,o,s,b.sum(),S.sum())},c),xt=async()=>{if(!B){B=!0,t.info(u("\u6536\u5230\u9000\u51FA\u4FE1\u53F7,\u6536\u5C3E drain","shutdown signal received, final drain")),clearInterval(to),clearInterval(no),clearInterval(oo);for(let h of Ve)try{h?.close()}catch{}for(let h of w.values())clearTimeout(h);Ze=0,await je(),n(),process.exit(0)}};for(process.on("SIGINT",()=>void xt()),process.on("SIGTERM",()=>void xt()),t.info(u("daemon \u542F\u52A8","daemon started"),{sources:y.map(h=>h.dir),clientId:o,host:s,hasCreds:!!d}),d&&pt(d,o,s,0,0),await je();!B;)await O(1e3)}async function Rn(e){let t;try{t=await(await fetch(e+"/api/device/code",{method:"POST",headers:{"Content-Type":"application/json"},body:"{}"})).json()}catch(r){return{ok:!1,message:u(`\u8FDE\u63A5\u670D\u52A1\u7AEF\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`,`Failed to connect to server: ${r instanceof Error?r.message:String(r)}`)}}let n=t.result;if(!n?.deviceCode||!n.userCode)return{ok:!1,message:u(`\u83B7\u53D6\u8BBE\u5907\u7801\u5931\u8D25: ${t.message??JSON.stringify(t).slice(0,160)}`,`Failed to obtain device code: ${t.message??JSON.stringify(t).slice(0,160)}`)};console.log(`
|
|
32
|
+
========================================`),console.log(u(` \u8BF7\u5728\u6D4F\u89C8\u5668\u6253\u5F00: ${n.verificationUri}`,` Open in your browser: ${n.verificationUri}`)),console.log(u(` \u5E76\u8F93\u5165\u6388\u6743\u7801: ${n.userCode}`,` Enter the code: ${n.userCode}`)),console.log(u(" (\u6388\u6743\u540E\u672C\u7EC8\u7AEF\u5C06\u81EA\u52A8\u5B8C\u6210\u767B\u5F55\u2026)"," (This terminal will finish login automatically once authorized\u2026)")),console.log(`========================================
|
|
33
|
+
`);let o=(n.interval??5)*1e3,s=Date.now()+(n.expiresIn??600)*1e3;for(;Date.now()<s;){await O(o);let r;try{r=await(await fetch(e+"/api/device/token",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({deviceCode:n.deviceCode})})).json()}catch{continue}let a=r.result;if(a?.accessKey&&a.accessSecret)return hn({endpoint:e,accessKey:a.accessKey,accessSecret:a.accessSecret}),{ok:!0,message:u("\u767B\u5F55\u6210\u529F,\u51ED\u8BC1\u5DF2\u5B89\u5168\u4FDD\u5B58(\u79DF\u6237/\u7528\u6237\u7531\u670D\u52A1\u7AEF\u7ED1\u5B9A)\u3002","Login succeeded; credentials saved securely (tenant/user bound by the server).")};if(a?.status==="expired")return{ok:!1,message:u("\u6388\u6743\u7801\u5DF2\u8FC7\u671F,\u8BF7\u91CD\u65B0\u8FD0\u884C login\u3002","Authorization code expired; please run login again.")};if(a?.status==="denied")return{ok:!1,message:u("\u6388\u6743\u88AB\u62D2\u7EDD\u3002","Authorization denied.")}}return{ok:!1,message:u("\u7B49\u5F85\u6388\u6743\u8D85\u65F6,\u8BF7\u91CD\u8BD5\u3002","Timed out waiting for authorization; please retry.")}}import{homedir as Xs}from"node:os";import{join as Zs}from"node:path";var Nn="agentmem";function Tn(){return Zs(Xs(),".claude","settings.json")}function An(e){return e.some(t=>Array.isArray(t.hooks)&&t.hooks.some(n=>typeof n.command=="string"&&n.command.includes(Nn)))}function mt(e="npx -y @ketaisoft/agentmem flush --stdin"){let t=e.replace(/flush\s+--stdin/,"recall-hook"),n=Tn(),o=ee(n)??{};o.hooks??={};let s=!1;for(let r of["Stop","SessionEnd"]){let a=o.hooks[r]??=[];An(a)||(a.push({hooks:[{type:"command",command:e,async:!0}]}),s=!0)}if(t!==e)for(let r of["SessionStart","UserPromptSubmit"]){let a=o.hooks[r]??=[];An(a)||(a.push({hooks:[{type:"command",command:t}]}),s=!0)}return s&&$(n,JSON.stringify(o,null,2)),{changed:s,path:n,command:e}}function Mn(){let e=Tn(),t=ee(e);if(!t?.hooks)return{changed:!1,path:e};let n=!1;for(let o of Object.keys(t.hooks)){let s=t.hooks[o];if(!Array.isArray(s))continue;let r=s.filter(a=>!(Array.isArray(a.hooks)&&a.hooks.some(i=>typeof i.command=="string"&&i.command.includes(Nn))));r.length!==s.length&&(t.hooks[o]=r,n=!0)}return n&&$(e,JSON.stringify(t,null,2)),{changed:n,path:e}}import{homedir as On}from"node:os";import{join as He}from"node:path";import{existsSync as qe,readFileSync as Dn}from"node:fs";var Ln="agentmem",Pn="agentmem-codex-notify",jn=`# ${Pn}: Codex \u4F1A\u8BDD\u901A\u77E5\u94A9\u5B50(\u7531 agentmem install \u7EF4\u62A4,\u52FF\u624B\u6539)`,gt='notify = ["npx", "-y", "@ketaisoft/agentmem", "codex-notify"]';function Be(){let e=process.env.CODEX_HOME||He(On(),".codex");return He(e,"config.toml")}function zn(){let e=process.env.CODEX_HOME||He(On(),".codex");if(qe(e))return!0;let t=process.env.PATH||"",n=process.platform==="win32"?["codex.exe","codex.cmd","codex.bat","codex"]:["codex"];for(let o of t.split(process.platform==="win32"?";":":")){let s=o.trim();if(s)for(let r of n)try{if(qe(He(s,r)))return!0}catch{}}return!1}function Fn(e){return e.endsWith(`
|
|
34
|
+
`)?e:e+`
|
|
35
|
+
`}function Ys(e){for(let t=0;t<e.length;t++)if(/^\s*\[/.test(e[t]))return t;return e.length}function Kn(){let e=Be(),t=gt;if(!qe(e))return $(e,jn+`
|
|
36
|
+
`+gt+`
|
|
37
|
+
`),{changed:!0,path:e,conflict:!1,command:t};let o=Dn(e,"utf8").split(`
|
|
38
|
+
`),s=Ys(o);for(let i=0;i<s;i++){let c=o[i];if(!/^\s*#/.test(c)&&/^\s*notify\s*=/.test(c))return c.includes(Ln)?{changed:!1,path:e,conflict:!1,command:t}:{changed:!1,path:e,conflict:!0,command:t}}let r=[jn,gt],a;return s<o.length?a=[...o.slice(0,s),...r,"",...o.slice(s)]:a=[...o,...r],$(e,Fn(a.join(`
|
|
39
|
+
`))),{changed:!0,path:e,conflict:!1,command:t}}function Un(){let e=Be();if(!qe(e))return{changed:!1,path:e};let t=Dn(e,"utf8").split(`
|
|
40
|
+
`),n=[],o=!1;for(let s of t){if(/^\s*notify\s*=/.test(s)&&s.includes(Ln)){o=!0;continue}if(s.includes(Pn)){o=!0;continue}n.push(s)}return o&&$(e,Fn(n.join(`
|
|
41
|
+
`))),{changed:o,path:e}}import{join as Xe}from"node:path";async function Vs(e,t,n,o){let s=K(Date.now()),r=F(),a=z("POST",t,e.accessKey,s,r,e.accessSecret),i=new AbortController,c=setTimeout(()=>i.abort(),o);try{let l=await fetch(e.endpoint+t,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":U,accessKey:e.accessKey,timestamp:s,nonce:r,sign:a},body:JSON.stringify(n??{}),signal:i.signal});return{status:l.status,text:await l.text()}}finally{clearTimeout(c)}}async function H(e,t,n=15e3){let o=T();if(!o)throw new Error(u("\u672A\u767B\u5F55\uFF1A\u5148\u6267\u884C agentmem login\uFF0C\u6216\u914D\u7F6E AGENTMEM_ENDPOINT/ACCESS_KEY/ACCESS_SECRET","Not logged in: run `agentmem login` or set AGENTMEM_ENDPOINT/ACCESS_KEY/ACCESS_SECRET"));let s;for(let r=0;r<2;r++){r>0&&await new Promise(c=>setTimeout(c,400));let a;try{a=await Vs(o,e,t,n)}catch(c){s=c;continue}if(a.status>=500){s=new Error(`HTTP ${a.status}`);continue}let i;try{i=JSON.parse(a.text)}catch{throw new Error(`HTTP ${a.status}: ${a.text.slice(0,160)}`)}if(i.code!==200)throw new Error(i.message||`code ${i.code}`);return i.result}throw s instanceof Error?s:new Error("recall failed")}var Qs="2024-11-05",er=[{name:"recall_search",description:"\u5728\u56E2\u961F\u5386\u53F2\u7F16\u7801\u4F1A\u8BDD\u4E2D\u6309\u5173\u952E\u8BCD/\u95EE\u9898\u68C0\u7D22\u76F8\u5173\u8BB0\u5FC6\uFF08\u53D7\u4F60\u7684\u6743\u9650\u6536\u53E3\uFF09\uFF0C\u8FD4\u56DE\u4F1A\u8BDD\u8BB0\u5FC6\u5361\u7247\u3002\u95EE\u201C\u6211\u4EEC\u4EE5\u524D\u600E\u4E48\u89E3\u51B3\u8FC7 X\u201D\u65F6\u7528\u3002",inputSchema:{type:"object",properties:{query:{type:"string",description:"\u68C0\u7D22\u8BCD\u6216\u95EE\u9898"},project:{type:"string",description:"\u53EF\u9009\uFF1A\u9650\u5B9A\u9879\u76EE\u8DEF\u5F84"},limit:{type:"number",description:"\u8FD4\u56DE\u6761\u6570\uFF0C\u9ED8\u8BA4 8"}},required:["query"]}},{name:"recall_recent",description:"\u83B7\u53D6\u56E2\u961F\u6700\u8FD1\u7684\u7F16\u7801\u4F1A\u8BDD\u8BB0\u5FC6\u5361\u7247\uFF08\u53D7\u6743\u9650\u6536\u53E3\uFF09\u3002\u4E86\u89E3\u201C\u6700\u8FD1\u5927\u5BB6\u5728\u8FD9\u4E2A\u9879\u76EE\u5E72\u4E86\u4EC0\u4E48\u201D\u65F6\u7528\u3002",inputSchema:{type:"object",properties:{project:{type:"string",description:"\u53EF\u9009\uFF1A\u9650\u5B9A\u9879\u76EE\u8DEF\u5F84"},limit:{type:"number"}}}},{name:"recall_context",description:"\u83B7\u53D6\u56E2\u961F\u8FD1\u671F\u8BB0\u5FC6\u300C\u4E0A\u4E0B\u6587\u5305\u300D\uFF08Markdown\uFF1A\u5173\u952E\u51B3\u7B56/\u5751/\u7EA6\u5B9A + \u8FD1\u671F\u4F1A\u8BDD\u6458\u8981\uFF09\uFF0C\u9002\u5408\u5728\u5F00\u59CB\u4EFB\u52A1\u65F6\u6CE8\u5165\uFF0C\u4E86\u89E3\u9879\u76EE\u5386\u6765\u7684\u7EA6\u5B9A\u4E0E\u5751\u3002",inputSchema:{type:"object",properties:{project:{type:"string",description:"\u53EF\u9009\uFF1A\u9650\u5B9A\u9879\u76EE\u8DEF\u5F84"},limit:{type:"number"}}}},{name:"save_memory",description:"\u628A\u4E00\u6761\u91CD\u8981\u7684\u56E2\u961F\u8BB0\u5FC6\uFF08\u5173\u952E\u51B3\u7B56/\u8E29\u8FC7\u7684\u5751/\u9879\u76EE\u7EA6\u5B9A\uFF09\u6C89\u6DC0\u5230\u4E91\u7AEF\u56E2\u961F\u8BB0\u5FC6\u5E93\uFF0C\u4F9B\u5168\u56E2\u961F\u540E\u7EED recall\u3002\u505A\u51FA\u91CD\u8981\u51B3\u7B56\u3001\u8E29\u5751\u89E3\u51B3\u6216\u786E\u7ACB\u7EA6\u5B9A\u540E\u8C03\u7528\u3002",inputSchema:{type:"object",properties:{text:{type:"string",description:"\u8BB0\u5FC6\u5185\u5BB9\uFF08\u4E00\u53E5\u81EA\u5305\u542B\u7684\u51B3\u7B56/\u5751/\u7EA6\u5B9A\uFF09"},type:{type:"string",description:"decision|pitfall|convention|note\uFF0C\u9ED8\u8BA4 note"},project:{type:"string",description:"\u53EF\u9009\uFF1A\u5173\u8054\u9879\u76EE\u8DEF\u5F84/cwd"}},required:["text"]}}];function Wn(e){process.stdout.write(JSON.stringify(e)+`
|
|
42
|
+
`)}function Ae(e,t){Wn({jsonrpc:"2.0",id:e,result:t})}function Gn(e){return!Array.isArray(e)||e.length===0?u("\uFF08\u672A\u53EC\u56DE\u5230\u76F8\u5173\u8BB0\u5FC6\uFF09","(no relevant memory found)"):e.map((t,n)=>{let o=t.title||t.sessionId,s=t.project?`\uFF08${t.project}\uFF09`:"",r=String(t.summary||"").slice(0,300);return`${n+1}. ${o}${s} [\u6765\u6E90 ${t.sessionId}]
|
|
43
|
+
${r}`}).join(`
|
|
44
|
+
`)}async function tr(e,t){let n=t||{};if(e==="recall_search")return Gn(await H("/api/recall/search",{query:String(n.query??""),project:n.project,limit:n.limit}));if(e==="recall_recent")return Gn(await H("/api/recall/recent",{project:n.project,limit:n.limit}));if(e==="recall_context"){let o=await H("/api/recall/context",{project:n.project,limit:n.limit});return o&&o.markdown?String(o.markdown):u("\uFF08\u6682\u65E0\u56E2\u961F\u8BB0\u5FC6\uFF09","(no team memory yet)")}if(e==="save_memory"){let o=await H("/api/recall/save",{text:String(n.text??""),type:n.type,project:n.project});return o&&o.message?String(o.message):o&&o.saved?u("\u2713 \u5DF2\u6C89\u6DC0\u5230\u56E2\u961F\u8BB0\u5FC6","\u2713 saved to team memory"):u("\u672A\u4FDD\u5B58","not saved")}throw new Error(`unknown tool: ${e}`)}async function nr(e){let t=e?.id,n=e?.method,o=e?.params;if(!(n==="notifications/initialized"||n==="notifications/cancelled")){if(n==="initialize"){let s=o&&o.protocolVersion||Qs;Ae(t,{protocolVersion:s,capabilities:{tools:{}},serverInfo:{name:"agentmem-recall",version:A}});return}if(n==="ping"){Ae(t,{});return}if(n==="tools/list"){Ae(t,{tools:er});return}if(n==="tools/call"){try{let s=await tr(o?.name,o?.arguments);Ae(t,{content:[{type:"text",text:s}]})}catch(s){Ae(t,{content:[{type:"text",text:u("\u8BB0\u5FC6\u53EC\u56DE\u5931\u8D25\uFF1A","Recall failed: ")+(s instanceof Error?s.message:String(s))}],isError:!0})}return}t!=null&&Wn({jsonrpc:"2.0",id:t,error:{code:-32601,message:`method not found: ${n}`}})}}async function Jn(){process.stderr.write(u(`[agentmem mcp] \u56E2\u961F\u8BB0\u5FC6 MCP server \u5DF2\u542F\u52A8\uFF08stdio\uFF09
|
|
45
|
+
`,`[agentmem mcp] team-memory MCP server started (stdio)
|
|
46
|
+
`)),process.stdin.setEncoding("utf8");let e="";for await(let t of process.stdin){e+=t;let n;for(;(n=e.indexOf(`
|
|
47
|
+
`))>=0;){let o=e.slice(0,n).trim();if(e=e.slice(n+1),!o)continue;let s;try{s=JSON.parse(o)}catch{continue}nr(s).catch(r=>process.stderr.write("[agentmem mcp] "+(r instanceof Error?r.message:String(r))+`
|
|
48
|
+
`))}}}function Hn(){let e={mcpServers:{agentmem:{command:"agentmem",args:["mcp"]}}};process.stdout.write(u("# Claude Code\uFF1A\u5199\u5165\u9879\u76EE\u6839 .mcp.json\uFF08\u6216 `claude mcp add`\uFF09\n","# Claude Code: put into project .mcp.json (or `claude mcp add`)\n")),process.stdout.write(JSON.stringify(e,null,2)+`
|
|
49
|
+
|
|
50
|
+
`),process.stdout.write(u(`# Codex\uFF1A~/.codex/config.toml \u589E\u52A0
|
|
51
|
+
`,`# Codex: add to ~/.codex/config.toml
|
|
52
|
+
`)),process.stdout.write(`[mcp_servers.agentmem]
|
|
53
|
+
command = "agentmem"
|
|
54
|
+
args = ["mcp"]
|
|
55
|
+
|
|
56
|
+
`),process.stdout.write(u(`# \u6CE8\uFF1A\u82E5\u672A\u5168\u5C40\u5B89\u88C5 agentmem\uFF0C\u53EF\u628A command \u6362\u6210 npx\uFF0Cargs \u6362\u6210 ["-y","@ketaisoft/agentmem","mcp"]\uFF1B\u5148\u786E\u4FDD\u5DF2 agentmem login\u3002
|
|
57
|
+
`,'# Note: if agentmem is not installed globally, set command to npx with args ["-y","@ketaisoft/agentmem","mcp"]; ensure `agentmem login` first.\n'))}async function or(){let e=[];process.stdin.setEncoding("utf8");for await(let t of process.stdin)e.push(t);return e.join("")}function qn(e,t){let n=(t||"").trim();n&&process.stdout.write(JSON.stringify({hookSpecificOutput:{hookEventName:e,additionalContext:n}}))}function sr(e){return!Array.isArray(e)||e.length===0?"":e.map((t,n)=>`${n+1}. ${t.title||t.sessionId}\uFF1A${String(t.summary||"").slice(0,240)}`).join(`
|
|
58
|
+
`)}async function Bn(){let e={};try{e=JSON.parse(await or())||{}}catch{}let t=e.hook_event_name||"SessionStart",n=e.cwd||void 0;try{if(t==="UserPromptSubmit"){let o=(e.prompt||"").trim();if(o.length<8)return;let s=await H("/api/recall/search",{query:o,project:n,limit:4},4e3),r=sr(s);r&&qn(t,u(`\u3010\u56E2\u961F\u8BB0\u5FC6\xB7\u4E0E\u672C\u6B21\u63D0\u95EE\u76F8\u5173\u7684\u5386\u53F2\u3011
|
|
59
|
+
`,`[Team memory \xB7 history relevant to this prompt]
|
|
60
|
+
`)+r)}else{let o=await H("/api/recall/context",{project:n,limit:8},5e3);o&&((o.sessionCount??0)>0||(o.factCount??0)>0)&&o.markdown&&qn(t,String(o.markdown))}}catch{}}import{homedir as Xn}from"node:os";import{join as Te,dirname as yt}from"node:path";import{fileURLToPath as rr}from"node:url";import{existsSync as Me,rmSync as Zn}from"node:fs";import{execFileSync as ir}from"node:child_process";var v="agentmem-daemon",Ne="cc.huihuayun.agentmem.daemon";function ar(){let e=rr(import.meta.url),t=yt(e);for(let n of["cli.js","cli.ts"]){let o=Te(t,n);if(Me(o))return o}return null}function wt(){let e=ar();if(e){let t=process.execPath;return{program:t,args:[e,"daemon"],display:`"${t}" "${e}" daemon`}}return{program:"npx",args:["-y","@ketaisoft/agentmem","daemon"],display:"npx -y @ketaisoft/agentmem daemon"}}function M(e,t){try{return{code:0,out:ir(e,t,{encoding:"utf8",stdio:["ignore","pipe","pipe"]})??"",err:""}}catch(n){let o=n,s=String(o.stderr??"")||String(o.message??"")||String(o.code??"");return{code:o.status??1,out:String(o.stdout??""),err:s}}}function q(e){return(e.err.trim()||e.out.trim()||"unknown error").split(`
|
|
61
|
+
`)[0]}function cr(){let e=wt(),t=M("schtasks",["/Create","/TN",v,"/TR",e.display,"/SC","ONLOGON","/F"]);return t.code!==0?{ok:!1,message:u(`\u521B\u5EFA\u767B\u5F55\u81EA\u542F\u8BA1\u5212\u4EFB\u52A1\u5931\u8D25:${q(t)}`,`Failed to create logon auto-start task: ${q(t)}`),command:e.display}:{ok:!0,path:v,command:e.display,message:u(`\u5DF2\u521B\u5EFA\u767B\u5F55\u81EA\u542F\u8BA1\u5212\u4EFB\u52A1\u300C${v}\u300D(\u4E0B\u6B21\u767B\u5F55\u8D77\u81EA\u52A8\u8FD0\u884C daemon)`,`Created logon auto-start task "${v}" (daemon runs at each logon)`)}}function lr(){return M("schtasks",["/Delete","/TN",v,"/F"]).code!==0?{ok:!0,path:v,message:u(`\u672A\u53D1\u73B0\u81EA\u542F\u4EFB\u52A1\u300C${v}\u300D,\u65E0\u9700\u79FB\u9664`,`Auto-start task "${v}" not found; nothing to remove`)}:{ok:!0,path:v,message:u(`\u5DF2\u79FB\u9664\u767B\u5F55\u81EA\u542F\u8BA1\u5212\u4EFB\u52A1\u300C${v}\u300D`,`Removed logon auto-start task "${v}"`)}}function ur(){return M("schtasks",["/Query","/TN",v]).code!==0?{ok:!0,path:v,message:u(`\u672A\u5B89\u88C5(\u65E0\u81EA\u542F\u4EFB\u52A1\u300C${v}\u300D)`,`Not installed (no auto-start task "${v}")`)}:{ok:!0,path:v,message:u(`\u5DF2\u5B89\u88C5:\u767B\u5F55\u81EA\u542F\u8BA1\u5212\u4EFB\u52A1\u300C${v}\u300D\u5B58\u5728`,`Installed: logon auto-start task "${v}" exists`)}}function kt(){return Te(Xn(),"Library","LaunchAgents",`${Ne}.plist`)}function ht(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function dr(e){let n=[e.program,...e.args].map(r=>` <string>${ht(r)}</string>`).join(`
|
|
62
|
+
`),o=Te(pe(),"daemon.out.log"),s=Te(pe(),"daemon.err.log");return`<?xml version="1.0" encoding="UTF-8"?>
|
|
63
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
64
|
+
<plist version="1.0">
|
|
65
|
+
<dict>
|
|
66
|
+
<key>Label</key>
|
|
67
|
+
<string>${Ne}</string>
|
|
68
|
+
<key>ProgramArguments</key>
|
|
69
|
+
<array>
|
|
70
|
+
${n}
|
|
71
|
+
</array>
|
|
72
|
+
<key>RunAtLoad</key>
|
|
73
|
+
<true/>
|
|
74
|
+
<key>KeepAlive</key>
|
|
75
|
+
<true/>
|
|
76
|
+
<key>StandardOutPath</key>
|
|
77
|
+
<string>${ht(o)}</string>
|
|
78
|
+
<key>StandardErrorPath</key>
|
|
79
|
+
<string>${ht(s)}</string>
|
|
80
|
+
</dict>
|
|
81
|
+
</plist>
|
|
82
|
+
`}function fr(){let e=wt(),t=kt();G(yt(t)),M("launchctl",["unload","-w",t]),$(t,dr(e));let n=M("launchctl",["load","-w",t]);return n.code!==0?{ok:!1,path:t,command:e.display,message:u(`\u5DF2\u5199\u5165 plist \u4F46 launchctl load \u5931\u8D25:${q(n)}`,`Wrote plist but launchctl load failed: ${q(n)}`)}:{ok:!0,path:t,command:e.display,message:u(`\u5DF2\u5B89\u88C5 LaunchAgent \u5E76\u52A0\u8F7D(\u767B\u5F55\u81EA\u542F daemon)\u2192 ${t}`,`Installed and loaded LaunchAgent (daemon auto-starts at login) \u2192 ${t}`)}}function pr(){let e=kt();if(!Me(e))return{ok:!0,path:e,message:u(`\u672A\u53D1\u73B0 LaunchAgent,\u65E0\u9700\u79FB\u9664 \u2192 ${e}`,`LaunchAgent not found; nothing to remove \u2192 ${e}`)};M("launchctl",["unload","-w",e]);try{Zn(e,{force:!0})}catch{}return{ok:!0,path:e,message:u(`\u5DF2\u5378\u8F7D\u5E76\u79FB\u9664 LaunchAgent \u2192 ${e}`,`Unloaded and removed LaunchAgent \u2192 ${e}`)}}function mr(){let e=kt();if(!Me(e))return{ok:!0,path:e,message:u(`\u672A\u5B89\u88C5(\u65E0 LaunchAgent \u2192 ${e})`,`Not installed (no LaunchAgent \u2192 ${e})`)};let n=M("launchctl",["list",Ne]).code===0;return{ok:!0,path:e,message:n?u(`\u5DF2\u5B89\u88C5\u4E14\u5DF2\u52A0\u8F7D:LaunchAgent\u300C${Ne}\u300D\u8FD0\u884C\u4E2D`,`Installed and loaded: LaunchAgent "${Ne}" is running`):u(`\u5DF2\u5B89\u88C5\u4F46\u672A\u52A0\u8F7D(\u53EF launchctl load -w ${e})`,`Installed but not loaded (try: launchctl load -w ${e})`)}}function St(){return Te(Xn(),".config","systemd","user",`${v}.service`)}function gr(e){return`[Unit]
|
|
83
|
+
Description=agentmem session collector daemon
|
|
84
|
+
After=default.target
|
|
85
|
+
|
|
86
|
+
[Service]
|
|
87
|
+
Type=simple
|
|
88
|
+
ExecStart=${[e.program,...e.args].map(n=>`"${n}"`).join(" ")}
|
|
89
|
+
Restart=on-failure
|
|
90
|
+
RestartSec=5
|
|
91
|
+
|
|
92
|
+
[Install]
|
|
93
|
+
WantedBy=default.target
|
|
94
|
+
`}function hr(){let e=wt(),t=St();G(yt(t)),$(t,gr(e));let n=M("systemctl",["--user","daemon-reload"]);if(n.code!==0)return{ok:!1,path:t,command:e.display,message:u(`\u5DF2\u5199\u5165\u5355\u5143\u4F46 systemctl --user daemon-reload \u5931\u8D25:${q(n)}`,`Wrote unit but 'systemctl --user daemon-reload' failed: ${q(n)}`)};let o=M("systemctl",["--user","enable","--now",v]);return o.code!==0?{ok:!1,path:t,command:e.display,message:u(`\u5DF2\u5199\u5165\u5355\u5143\u4F46 enable --now \u5931\u8D25:${q(o)}(\u63D0\u793A:\u975E\u767B\u5F55\u4F1A\u8BDD\u9700\u5148 'loginctl enable-linger $USER')`,`Wrote unit but 'enable --now' failed: ${q(o)} (hint: for non-login sessions run 'loginctl enable-linger $USER')`)}:{ok:!0,path:t,command:e.display,message:u(`\u5DF2\u5B89\u88C5\u5E76\u542F\u7528 systemd \u7528\u6237\u5355\u5143\u300C${v}\u300D(\u767B\u5F55\u81EA\u542F daemon)\u2192 ${t}`,`Installed and enabled systemd user unit "${v}" (daemon auto-starts at login) \u2192 ${t}`)}}function yr(){let e=St();M("systemctl",["--user","disable","--now",v]);let t=!1;if(Me(e))try{Zn(e,{force:!0}),t=!0}catch{}return M("systemctl",["--user","daemon-reload"]),{ok:!0,path:e,message:t?u(`\u5DF2\u505C\u7528\u5E76\u79FB\u9664 systemd \u7528\u6237\u5355\u5143\u300C${v}\u300D\u2192 ${e}`,`Disabled and removed systemd user unit "${v}" \u2192 ${e}`):u(`\u672A\u53D1\u73B0\u5355\u5143\u6587\u4EF6,\u5DF2\u5C1D\u8BD5\u505C\u7528\u300C${v}\u300D\u2192 ${e}`,`Unit file not found; attempted to disable "${v}" \u2192 ${e}`)}}function wr(){let e=St();if(!Me(e))return{ok:!0,path:e,message:u(`\u672A\u5B89\u88C5(\u65E0 systemd \u7528\u6237\u5355\u5143 \u2192 ${e})`,`Not installed (no systemd user unit \u2192 ${e})`)};let t=M("systemctl",["--user","is-enabled",v]).out.trim()||"\u672A\u77E5",n=M("systemctl",["--user","is-active",v]).out.trim()||"\u672A\u77E5";return{ok:!0,path:e,message:u(`\u5DF2\u5B89\u88C5:\u5355\u5143\u300C${v}\u300Denabled=${t} active=${n} \u2192 ${e}`,`Installed: unit "${v}" enabled=${t} active=${n} \u2192 ${e}`)}}function bt(){return{ok:!1,message:u(`\u4E0D\u652F\u6301\u7684\u5E73\u53F0:${process.platform}(\u4EC5\u652F\u6301 win32/darwin/linux \u7684\u7528\u6237\u7EA7\u81EA\u542F)`,`Unsupported platform: ${process.platform} (only win32/darwin/linux user-level auto-start)`)}}function Yn(){switch(process.platform){case"win32":return cr();case"darwin":return fr();case"linux":return hr();default:return bt()}}function Vn(){switch(process.platform){case"win32":return lr();case"darwin":return pr();case"linux":return yr();default:return bt()}}function Qn(){switch(process.platform){case"win32":return ur();case"darwin":return mr();case"linux":return wr();default:return bt()}}function br(e){let t={};for(let n=0;n<e.length;n++){let o=e[n];if(!o.startsWith("--"))continue;let s=o.slice(2),r=e[n+1];r===void 0||r.startsWith("--")?t[s]=!0:(t[s]=r,n++)}return t}var C=e=>typeof e=="string"?e:void 0;function vr(e){let t=e.toLowerCase();return/[\\/]opencode[\\/]storage[\\/]/i.test(e)||/[\\/]storage[\\/](message|part)[\\/]/i.test(e)?"opencode":/[\\/]\.gemini[\\/]/i.test(e)||t.endsWith(".json")&&!t.endsWith(".jsonl")?"gemini":/[\\/]\.cursor[\\/]/i.test(e)?"cursor":/[\\/]\.codex[\\/]/i.test(e)?"codex":"claude-code"}function xr(){return new Promise(e=>{if(process.stdin.isTTY){e("");return}let t="";process.stdin.setEncoding("utf8"),process.stdin.on("data",n=>t+=n),process.stdin.on("end",()=>e(t)),setTimeout(()=>e(t),1500)})}async function Er(e){let t=!!e.stdin;if(me(Xe(I,"daemon.lock"))){t||console.log(u("daemon \u6B63\u5728\u8FD0\u884C,\u5DF2\u4EA4\u7531\u5176\u91C7\u96C6\u4E0A\u62A5(\u65E0\u9700 flush)\u3002","daemon is running; it handles capture and upload (no flush needed)."));return}let n=Ce("flush","info",!t),o=ie(),s=C(e.surface)||"cli",r=C(e.transcript),a=C(e.session);if(t){let f=await xr();if(f)try{let x=JSON.parse(f);r??=x.transcript_path||x.transcriptPath||void 0,a??=x.session_id||x.sessionId||void 0}catch{}}let i=Y(),c=V(),l=ae(),d=ce(),p=le(),m=C(e.agent);!r&&e.latest&&(r=Je(m==="cursor"?l:m==="codex"?c:i)),!r&&a&&(r=R(i).find(f=>f.endsWith(`${a}.jsonl`))||R(l).find(f=>f.endsWith(`${a}.jsonl`))||R(c).find(f=>f.includes(a))||ge(d).find(f=>f.includes(a))||he(p).find(f=>f.includes(a)));let y=new D,g=f=>f.toLowerCase().startsWith(p.toLowerCase())||/[\\/]storage[\\/](message|part)[\\/]/i.test(f),k=f=>{let x=f.toLowerCase();return m==="opencode"?_e:m==="gemini"?Ee:m==="cursor"?xe:m==="codex"?ne:m==="claude-code"?te:g(f)?_e:x.endsWith(".json")||x.startsWith(d.toLowerCase())||/[\\/]\.gemini[\\/]/i.test(f)?Ee:x.startsWith(l.toLowerCase())||/[\\/]\.cursor[\\/]/i.test(f)?xe:x.startsWith(c.toLowerCase())||/[\\/]\.codex[\\/]/i.test(f)?ne:te},b=f=>k(f)(f,o,s,y,n);if(r&&N(r))await b(r);else{for(let f of R(i))await b(f);for(let f of R(c))await b(f);for(let f of R(l))await b(f);for(let f of ge(d))await b(f);for(let f of he(p))await b(f)}let S=T();if(!S){n.warn(u("\u672A\u914D\u7F6E\u51ED\u8BC1,\u5DF2\u7F13\u5B58\u5230\u672C\u5730 spool;\u8FD0\u884C `agentmem login` \u540E\u81EA\u52A8\u8865\u4F20","no credentials; cached to local spool, will auto-resend after `agentmem login`"));return}let w=await $e(S,y,n,{maxWallMs:2e4});for(let f=0;f<3&&y.stats().pending>0;f++)await O(2e3),await Re(S,y,o,n);if(!t){let f=y.stats();console.log(u(`flush: \u4E0A\u62A5 ${w.sent} \u6761(\u540E\u7AEF\u65B0\u589E ${w.accepted}), \u5F85\u843D\u5E93\u786E\u8BA4 ${f.pending}${w.parked?" [\u914D\u989D\u6682\u505C]":""}${w.dead?` \u6B7B\u4FE1 ${w.dead}`:""}`,`flush: sent ${w.sent} events (backend added ${w.accepted}), awaiting persist confirm ${f.pending}${w.parked?" [quota paused]":""}${w.dead?` dead ${w.dead}`:""}`))}}async function _r(){let t=await new D().requeueDead();console.log(u(`replay-dead: \u5DF2\u91CD\u6295 ${t} \u6761\u6B7B\u4FE1\u56DE\u5F85\u53D1\u961F\u5217;\u968F\u540E flush / daemon \u4F1A\u81EA\u52A8\u4E0A\u62A5\u3002`,`replay-dead: requeued ${t} dead-letter events; flush / daemon will upload them next.`))}function $r(e){let t=(e||"status").toLowerCase(),n=t==="install"?Yn():t==="uninstall"?Vn():t==="status"?Qn():void 0;n||(console.error(u("\u7528\u6CD5: agentmem service <install|uninstall|status>","Usage: agentmem service <install|uninstall|status>")),process.exit(2)),console.log(`${n.ok?"\u2713":"\u2717"} ${n.message}`),n.command&&console.log(u(" \u81EA\u542F\u547D\u4EE4:"," Auto-start command:"),n.command),t==="install"&&n.ok&&console.log(u(" \u63D0\u793A:\u5148 `agentmem login` \u914D\u597D\u51ED\u8BC1,daemon \u624D\u80FD\u4E0A\u62A5\u3002"," Note: run `agentmem login` first so the daemon can upload.")),n.ok||process.exit(1)}async function Cr(e,t){if(me(Xe(I,"daemon.lock")))return;let n=Ce("codex-notify","info",!1),o=ie(),s=V(),r;for(let d of t){let p=d.trim();if(p.startsWith("{")&&p.endsWith("}"))try{r=JSON.parse(p);break}catch{}}let a=C(e.transcript),i=C(e.session);if(r){let d=r.rollout_path??r.rolloutPath??r.rollout;!a&&typeof d=="string"&&N(d)&&(a=d),i??=r.session_id??r.sessionId??r.thread_id??r.threadId??r.conversation_id??r["turn-id"]??r.turn_id}!a&&i&&(a=R(s).find(d=>d.includes(i))),a||(a=Je(s));let c=new D;a&&N(a)&&await ne(a,o,C(e.surface)||"cli",c,n);let l=T();if(!l){n.warn(u("\u672A\u914D\u7F6E\u51ED\u8BC1,\u5DF2\u7F13\u5B58\u5230\u672C\u5730 spool;\u8FD0\u884C `agentmem login` \u540E\u81EA\u52A8\u8865\u4F20","no credentials; cached to local spool, will auto-resend after `agentmem login`"));return}await $e(l,c,n,{maxWallMs:15e3});for(let d=0;d<3&&c.stats().pending>0;d++)await O(2e3),await Re(l,c,o,n)}function Ir(){let t=new D().stats(),n=T(),o=gn(),s=me(Xe(I,"daemon.lock")),r=ve(I);console.log(u(`=== agentmem \u91C7\u96C6\u7AEF \xB7 \u72B6\u6001 (v${A}) ===`,`=== agentmem collector \xB7 status (v${A}) ===`)),console.log(u("\u5B88\u62A4\u8FDB\u7A0B:","Daemon:"),s?u("\u8FD0\u884C\u4E2D \u2713","running \u2713"):u("\u672A\u8FD0\u884C(\u53EF `agentmem daemon` \u6216\u7528 hook)","not running (run `agentmem daemon` or use a hook)")),console.log(u("\u51ED\u8BC1 :","Credentials:"),n?u(`\u5DF2\u914D\u7F6E \u2192 ${n.endpoint}`,`configured \u2192 ${n.endpoint}`):u(`\u672A\u914D\u7F6E(\u9ED8\u8BA4\u5C06\u8FDE ${J};\u8FD0\u884C agentmem login[ --endpoint <url>])`,`not configured (defaults to ${J}; run agentmem login[ --endpoint <url>])`)),console.log(u("\u672C\u5730\u961F\u5217:","Local queue:"),u(`\u5F85\u53D1 ${t.pending} \xB7 \u5DF2\u786E\u8BA4 ${t.acked} \xB7 \u6B7B\u4FE1 ${t.dead} \xB7 \u79EF\u538B ${Math.round(t.oldestMs/6e4)}min \xB7 \u961F\u5217 ${Math.round(t.bytes/1024)}KB`,`pending ${t.pending} \xB7 acked ${t.acked} \xB7 dead ${t.dead} \xB7 backlog ${Math.round(t.oldestMs/6e4)}min \xB7 queue ${Math.round(t.bytes/1024)}KB`)),r>=0&&console.log(u("\u78C1\u76D8\u53EF\u7528:","Disk free:"),`${Math.round(r/1048576)}MB`),console.log(u("Claude \u76EE\u5F55:","Claude dir:"),Y()),console.log(u("Codex \u76EE\u5F55 :","Codex dir :"),V()),console.log(u("Cursor \u76EE\u5F55:","Cursor dir:"),ae()),console.log(u("Gemini \u76EE\u5F55:","Gemini dir:"),ce()),console.log(u("OpenCode \u76EE\u5F55:","OpenCode dir:"),le());let a=be();a.length&&console.log(u("\u989D\u5916\u76EE\u5F55 :","Extra dirs:"),a.join(", "));let i=Object.keys(o);console.log(u("\u91C7\u96C6\u6E90 :","Sources:"),u(`${i.length} \u4E2A transcript`,`${i.length} transcripts`));for(let c of Object.values(o).slice(0,8))console.log(u(` \xB7 ${c.sessionId??"?"} \u884C=${c.lineNo} \u5B57\u8282=${c.byteOffset}`,` \xB7 ${c.sessionId??"?"} line=${c.lineNo} byte=${c.byteOffset}`));console.log(u("\u51ED\u8BC1\u6587\u4EF6:","Credentials file:"),yn())}function Rr(){let e=w=>w?"\u2713":"\u2717",t=(()=>{let[w,f]=process.versions.node.split(".").map(Number);return w>18||w===18&&f>=18})(),n=Y(),o=R(n),s=V(),r=R(s).length,a=ae(),i=R(a).length,c=ce(),l=ge(c).length,d=le(),p=he(d),m=new Set(p.map(w=>w.replace(/[\\/][^\\/]+$/,""))).size,y=T(),g=!0;try{new D}catch{g=!1}let k=ve(I),b=me(Xe(I,"daemon.lock"));console.log(u(`=== agentmem \u91C7\u96C6\u7AEF \xB7 \u4F53\u68C0 (v${A}) ===`,`=== agentmem collector \xB7 doctor (v${A}) ===`)),console.log(u(`${e(t)} Node ${process.versions.node}(\u53D1\u5E03\u7248\u9700 \u226518.18;\u4ECE\u6E90\u7801\u514D\u6784\u5EFA\u8DD1\u9700 \u226523.6)`,`${e(t)} Node ${process.versions.node} (release needs \u226518.18; running unbundled from source needs \u226523.6)`)),console.log(u(`${e(N(n))} Claude \u4F1A\u8BDD\u76EE\u5F55: ${n}(\u53D1\u73B0 ${o.length} \u4E2A transcript)`,`${e(N(n))} Claude session dir: ${n} (found ${o.length} transcripts)`)),console.log(u(`${e(N(s))} Codex \u4F1A\u8BDD\u76EE\u5F55: ${s}(\u53D1\u73B0 ${r} \u4E2A rollout)`,`${e(N(s))} Codex session dir: ${s} (found ${r} rollouts)`)),console.log(u(`${e(N(a))} Cursor \u4F1A\u8BDD\u76EE\u5F55: ${a}(\u53D1\u73B0 ${i} \u4E2A transcript)`,`${e(N(a))} Cursor session dir: ${a} (found ${i} transcripts)`)),console.log(u(`${e(N(c))} Gemini \u4F1A\u8BDD\u76EE\u5F55: ${c}(\u53D1\u73B0 ${l} \u4E2A\u5019\u9009 .json)`,`${e(N(c))} Gemini session dir: ${c} (found ${l} candidate .json)`)),console.log(u(`${e(N(d))} OpenCode \u5B58\u50A8\u76EE\u5F55: ${d}(\u53D1\u73B0 ${m} \u4E2A session)`,`${e(N(d))} OpenCode storage dir: ${d} (found ${m} sessions)`));let S=be();if(S.length)for(let w of S)console.log(u(`${e(!0)} \u989D\u5916\u76EE\u5F55: ${w}(\u53D1\u73B0 ${R(w).length} \u4E2A\u6587\u4EF6)`,`${e(!0)} extra dir: ${w} (found ${R(w).length} files)`));else console.log(u(" \u989D\u5916\u76EE\u5F55: \u65E0(\u53EF\u8BBE AGENTMEM_EXTRA_DIRS)"," extra dirs: none (set AGENTMEM_EXTRA_DIRS)"));console.log(u(`${e(g)} \u672C\u5730 spool \u53EF\u5199`,`${e(g)} local spool writable`)),console.log(u(`${e(k<0||k>200*1024*1024)} \u78C1\u76D8\u53EF\u7528${k>=0?`: ${Math.round(k/1048576)}MB`:"(\u672A\u77E5)"}`,`${e(k<0||k>200*1024*1024)} disk free${k>=0?`: ${Math.round(k/1048576)}MB`:" (unknown)"}`)),console.log(u(`${e(!!y)} \u51ED\u8BC1\u5DF2\u914D\u7F6E${y?` \u2192 ${y.endpoint}`:`(\u672A\u767B\u5F55;\u9ED8\u8BA4\u5C06\u8FDE ${J})`}`,`${e(!!y)} credentials configured${y?` \u2192 ${y.endpoint}`:` (not logged in; defaults to ${J})`}`)),console.log(u(` \u5B88\u62A4\u8FDB\u7A0B: ${b?"\u8FD0\u884C\u4E2D":"\u672A\u8FD0\u884C"}`,` daemon: ${b?"running":"not running"}`)),console.log(u(` \u672C\u5730\u65F6\u95F4: ${new Date().toISOString()}(\u7B7E\u540D\u6709 5 \u5206\u949F\u7A97\u53E3,\u65F6\u949F\u9700\u4E0E\u670D\u52A1\u7AEF\u4E00\u81F4)`,` local time: ${new Date().toISOString()} (signature has a 5-min window; clock must match server)`))}async function Ar(e){let t=C(e.file);!t&&e.latest&&(t=Je(Y())),t||(console.error(u("\u7528\u6CD5: agentmem upload --file <transcript> [--agent claude-code|codex|cursor|gemini|opencode] [--latest] [--dry-run]","Usage: agentmem upload --file <transcript> [--agent claude-code|codex|cursor|gemini|opencode] [--latest] [--dry-run]")),process.exit(2));let n=C(e["client-id"])||ie(),o=C(e.surface)||"cli",s=C(e.agent)||vr(t),r=s==="codex"?jt(t):s==="cursor"?zt(t):s==="gemini"?Ut(t):s==="opencode"?Ht(t):At(t);e.max&&(r.events=r.events.slice(0,Number(C(e.max))));let a=Se(r.events,n,o,s);console.log(u("\u6587\u4EF6:","File:"),t),console.log("sessionId:",r.sessionId,u(" \u4E8B\u4EF6:"," events:"),a.dtos.length,u(" \u8131\u654F\u547D\u4E2D:"," redacted:"),a.totalHits,JSON.stringify(a.ruleCounts));let i=T(),c=C(e.endpoint)||i?.endpoint||J,l=C(e.ak)||i?.accessKey,d=C(e.secret)||i?.accessSecret;if(!!e["dry-run"]||!(c&&l&&d)){console.log(u("[dry-run] \u672A\u53D1\u9001(\u9700 --endpoint/--ak/--secret,\u6216\u5148 agentmem login)\u3002","[dry-run] not sent (needs --endpoint/--ak/--secret, or run agentmem login first)."));return}let m=await en({endpoint:c,accessKey:l,accessSecret:d},a.dtos);console.log(u(`\u5DF2\u4E0A\u62A5 ${a.dtos.length} \u6761, \u670D\u52A1\u7AEF\u65B0\u589E accepted=${m}(\u5176\u4F59\u5E42\u7B49\u53BB\u91CD)\u3002`,`Sent ${a.dtos.length} events, server added accepted=${m} (rest deduped idempotently).`))}function Nr(e){let t;e.local&&(t=`node "${kr(import.meta.url)}" flush --stdin`);let n=t?mt(t):mt();if(console.log(n.changed?u(`\u2713 \u5DF2\u6CE8\u5165\u91C7\u96C6 hook \u2192 ${n.path}`,`\u2713 injected capture hook \u2192 ${n.path}`):u(`hook \u5DF2\u5B58\u5728,\u65E0\u9700\u6539\u52A8 \u2192 ${n.path}`,`hook already present, no change \u2192 ${n.path}`)),console.log(u(" \u547D\u4EE4:"," Command:"),n.command),console.log(u(" \u4E4B\u540E\u6BCF\u6B21 Claude Code \u4F1A\u8BDD\u7ED3\u675F\u4F1A\u81EA\u52A8\u91C7\u96C6\u4E0A\u62A5;\u5148 `agentmem login` \u914D\u7F6E\u51ED\u8BC1\u3002"," After this, every Claude Code session end auto-captures and uploads; run `agentmem login` first to set credentials.")),zn()){let o=Kn();o.conflict?console.log(u(`! Codex \u5DF2\u5B58\u5728\u975E\u6211\u65B9 notify(\u672A\u8986\u76D6)\u2192 ${o.path};\u5982\u9700\u63A5\u5165\u8BF7\u624B\u5DE5\u6539\u4E3A:${o.command}`,`! Codex already has a non-agentmem notify (not overwritten) \u2192 ${o.path}; to enable, manually set: ${o.command}`)):(console.log(o.changed?u(`\u2713 \u5DF2\u6CE8\u5165 Codex notify \u94A9\u5B50 \u2192 ${o.path}`,`\u2713 injected Codex notify hook \u2192 ${o.path}`):u(`Codex notify \u5DF2\u5B58\u5728,\u65E0\u9700\u6539\u52A8 \u2192 ${o.path}`,`Codex notify already present, no change \u2192 ${o.path}`)),console.log(u(" \u4E4B\u540E\u6BCF\u6B21 Codex \u4F1A\u8BDD\u7ED3\u675F\u4F1A\u81EA\u52A8\u91C7\u96C6\u4E0A\u62A5(notify \u2192 codex-notify)\u3002"," After this, every Codex session end auto-captures and uploads (notify \u2192 codex-notify).")))}}function Tr(){console.log(u(`agentmem \u91C7\u96C6\u7AEF v${A} (node ${process.versions.node})`,`agentmem collector v${A} (node ${process.versions.node})`))}function Mr(){let e="@ketaisoft/agentmem";console.log(u(`\u6B63\u5728\u5347\u7EA7 ${e} \u5230\u6700\u65B0\u7248\u2026`,`Upgrading ${e} to latest\u2026`));let t=process.platform==="win32",n=Sr(t?"npm.cmd":"npm",["install","-g",`${e}@latest`],{stdio:"inherit",shell:t});n.status===0?console.log(u("\u2713 \u5347\u7EA7\u5B8C\u6210\u3002\u8FD0\u884C `agentmem -v` \u786E\u8BA4\u7248\u672C\u3002","\u2713 Upgraded. Run `agentmem -v` to confirm.")):(console.log(u("\u2717 \u5347\u7EA7\u5931\u8D25(\u53EF\u80FD\u5C1A\u672A\u53D1\u5E03 / \u65E0\u7F51\u7EDC / \u6743\u9650\u4E0D\u8DB3)\u3002\u624B\u52A8: npm i -g @ketaisoft/agentmem@latest;\u6216\u6539\u7528 npx\uFF08\u59CB\u7EC8\u6700\u65B0\uFF09\u3002","\u2717 Upgrade failed (not published / offline / no permission). Manual: npm i -g @ketaisoft/agentmem@latest; or use npx (always latest).")),process.exit(n.status??1))}function eo(){console.log(u(`agentmem \u91C7\u96C6\u7AEF v${A}
|
|
95
|
+
\u7528\u6CD5: agentmem <command> [options]
|
|
96
|
+
\u9009\u9879: -v / --version / version \u67E5\u770B\u7248\u672C \xB7 -h / -help / --help \u67E5\u770B\u5E2E\u52A9
|
|
97
|
+
|
|
98
|
+
daemon \u5E38\u9A7B\u91C7\u96C6(Claude/Codex/Cursor/Gemini/OpenCode \u591A\u6E90,watch+\u8F6E\u8BE2\u2192\u672C\u5730WAL\u2192\u4E0A\u62A5)
|
|
99
|
+
flush [--transcript F|--latest|--session S|--stdin]
|
|
100
|
+
\u4E00\u6B21\u6027\u589E\u91CF\u91C7\u96C6+\u6392\u7A7A(hook \u7528 --stdin \u4ECE stdin \u8BFB)
|
|
101
|
+
codex-notify [<json>] Codex notify \u94A9\u5B50\u5165\u53E3(\u91C7\u96C6\u6700\u8FD1/\u6307\u5B9A rollout \u5E76\u6301\u4E45\u4E0A\u62A5)
|
|
102
|
+
replay-dead \u628A\u672C\u5730\u6B7B\u4FE1\u91CD\u6295\u56DE\u5F85\u53D1\u961F\u5217(\u968F\u540E flush/daemon \u4E0A\u62A5)
|
|
103
|
+
login --endpoint <url> \u8BBE\u5907\u6388\u6743\u767B\u5F55(\u514D\u7C98\u8D34\u5BC6\u94A5)
|
|
104
|
+
install [--local] \u5E42\u7B49\u6CE8\u5165 ~/.claude/settings.json hook + Codex notify(\u68C0\u6D4B\u5230 Codex \u65F6)
|
|
105
|
+
uninstall \u79FB\u9664\u6211\u65B9 hook(\u542B Codex notify)
|
|
106
|
+
service <install|uninstall|status> \u670D\u52A1\u5316/\u5F00\u673A\u81EA\u542F:\u767B\u5F55\u540E\u81EA\u52A8\u62C9\u8D77 daemon(Linux=systemd \u7528\u6237\u7EA7/Win=\u8BA1\u5212\u4EFB\u52A1/mac=launchd)
|
|
107
|
+
status \u672C\u5730\u961F\u5217/\u6E38\u6807/\u51ED\u8BC1
|
|
108
|
+
doctor \u4E00\u952E\u4F53\u68C0
|
|
109
|
+
upload --file <jsonl> [--dry-run] \u624B\u5DE5\u5168\u91CF\u4E0A\u62A5(\u8C03\u8BD5)
|
|
110
|
+
mcp [--print-config] \u56E2\u961F\u8BB0\u5FC6 MCP server(\u4F9B Claude Code/Codex \u56DE\u5582)
|
|
111
|
+
update \u5347\u7EA7\u5230\u6700\u65B0\u7248(npm i -g @ketaisoft/agentmem@latest)
|
|
112
|
+
version | -v \u67E5\u770B\u5F53\u524D\u7248\u672C`,`agentmem collector v${A}
|
|
113
|
+
Usage: agentmem <command> [options]
|
|
114
|
+
Options: -v / --version / version print version \xB7 -h / -help / --help show help
|
|
115
|
+
|
|
116
|
+
daemon continuous capture (Claude/Codex/Cursor/Gemini/OpenCode, watch+poll \u2192 local WAL \u2192 upload)
|
|
117
|
+
flush [--transcript F|--latest|--session S|--stdin]
|
|
118
|
+
one-shot incremental capture + drain (hook reads from stdin via --stdin)
|
|
119
|
+
codex-notify [<json>] Codex notify hook entry (capture latest/given rollout and durably upload)
|
|
120
|
+
replay-dead requeue local dead-letter events back to the outbox (flush/daemon uploads next)
|
|
121
|
+
login --endpoint <url> device-authorization login (no key pasting)
|
|
122
|
+
install [--local] idempotently inject ~/.claude/settings.json hook + Codex notify (when Codex detected)
|
|
123
|
+
uninstall remove our hook (incl. Codex notify)
|
|
124
|
+
service <install|uninstall|status> service/auto-start: launch daemon at login (Linux=systemd user / Win=Scheduled Task / mac=launchd)
|
|
125
|
+
status local queue/cursor/credentials
|
|
126
|
+
doctor one-shot health check
|
|
127
|
+
upload --file <jsonl> [--dry-run] manual full upload (debug)
|
|
128
|
+
mcp [--print-config] team-memory MCP server (recall for Claude Code/Codex)
|
|
129
|
+
update upgrade to latest (npm i -g @ketaisoft/agentmem@latest)
|
|
130
|
+
version | -v print current version`))}async function jr(){let e=process.argv.slice(2),t=(e[0]??"").toLowerCase();if(["-v","--version","version"].includes(t)){Tr();return}if(["-h","-help","--help","help"].includes(t)){eo();return}let n=e[0]&&!e[0].startsWith("--")?e[0]:"",o=br(n?e.slice(1):e);switch(n){case"daemon":await In({surface:C(o.surface)||"cli"});break;case"flush":await Er(o);break;case"login":{let s=C(o.endpoint)||process.env.AGENTMEM_ENDPOINT||T()?.endpoint||J,r=await Rn(s);console.log(r.ok?`\u2713 ${r.message}`:`\u2717 ${r.message}`),process.exit(r.ok?0:1);break}case"install":Nr(o);break;case"uninstall":{let s=Mn();console.log(s.changed?u(`\u2713 \u5DF2\u79FB\u9664\u91C7\u96C6 hook \u2192 ${s.path}`,`\u2713 removed capture hook \u2192 ${s.path}`):u(`\u672A\u53D1\u73B0\u6211\u65B9 hook \u2192 ${s.path}`,`our hook not found \u2192 ${s.path}`));let r=Un();r.changed?console.log(u(`\u2713 \u5DF2\u79FB\u9664 Codex notify \u94A9\u5B50 \u2192 ${r.path}`,`\u2713 removed Codex notify hook \u2192 ${r.path}`)):N(Be())&&console.log(u(`\u672A\u53D1\u73B0\u6211\u65B9 Codex notify \u2192 ${r.path}`,`our Codex notify not found \u2192 ${r.path}`));break}case"replay-dead":await _r();break;case"service":$r(e[1]&&!e[1].startsWith("--")?e[1]:void 0);break;case"codex-notify":await Cr(o,n?e.slice(1):e);break;case"status":Ir();break;case"doctor":Rr();break;case"upload":await Ar(o);break;case"mcp":o["print-config"]?Hn():await Jn();break;case"recall-hook":await Bn();break;case"update":Mr();break;default:eo()}}jr().catch(e=>{console.error(u("\u91C7\u96C6\u5931\u8D25:","Capture failed:"),e instanceof Error?e.message:e),process.exit(1)});
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ketaisoft/agentmem",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "编码 Agent 会话采集端(Node/TS,零运行时依赖):采集 Claude Code / Codex / Cursor / Gemini / OpenCode 本地会话 → 客户端脱敏 → HMAC 签名上报 /ingest。本地 WAL 续传、断点恢复、死信重投。",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "ketaisoft",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"agent",
|
|
10
|
+
"ai",
|
|
11
|
+
"claude-code",
|
|
12
|
+
"codex",
|
|
13
|
+
"cursor",
|
|
14
|
+
"gemini",
|
|
15
|
+
"opencode",
|
|
16
|
+
"session",
|
|
17
|
+
"capture",
|
|
18
|
+
"observability",
|
|
19
|
+
"redaction",
|
|
20
|
+
"cli"
|
|
21
|
+
],
|
|
22
|
+
"homepage": "https://github.com/ketaisoft/agentmem#readme",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/ketaisoft/agentmem.git"
|
|
26
|
+
},
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/ketaisoft/agentmem/issues"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public",
|
|
32
|
+
"registry": "https://registry.npmjs.org"
|
|
33
|
+
},
|
|
34
|
+
"engines": { "node": ">=20.0.0" },
|
|
35
|
+
"bin": { "agentmem": "dist/cli.js" },
|
|
36
|
+
"main": "dist/cli.js",
|
|
37
|
+
"files": ["dist", "README.md", "README.en.md", "LICENSE"],
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "npm run typecheck && node esbuild.mjs",
|
|
40
|
+
"typecheck": "tsc --noEmit",
|
|
41
|
+
"test": "node test/redact.test.ts",
|
|
42
|
+
"dev": "node src/cli.ts",
|
|
43
|
+
"prepublishOnly": "npm run build"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"typescript": "^5.7.2",
|
|
47
|
+
"@types/node": "^22.0.0",
|
|
48
|
+
"esbuild": "^0.25.0"
|
|
49
|
+
}
|
|
50
|
+
}
|