@1agents/session-reader 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/cordis.patch.yml +4 -0
- package/dist/bin/1session.js +26 -1
- package/dist/src/dsh/adapter.d.ts +18 -0
- package/dist/src/dsh/adapter.js +198 -0
- package/dist/src/dsh/client.d.ts +2 -0
- package/dist/src/dsh/client.js +18997 -0
- package/dist/src/dsh/index.d.ts +2 -0
- package/dist/src/dsh/index.js +2 -0
- package/dist/src/dsh/plugin.d.ts +3 -0
- package/dist/src/dsh/plugin.js +392 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- package/dist/src/resolver.d.ts +7 -0
- package/dist/src/resolver.js +13 -8
- package/dist/src/store/read.d.ts +6 -2
- package/dist/src/store/read.js +14 -12
- package/dist/src/web/api.d.ts +72 -0
- package/dist/src/web/api.js +126 -0
- package/dist/src/web/app.d.ts +1 -0
- package/dist/src/web/app.js +18975 -0
- package/dist/src/web/server.d.ts +20 -0
- package/dist/src/web/server.js +126 -0
- package/package.json +25 -4
- package/skills/1session/SKILL.md +2 -1
- package/skills/1session/references/cli.md +16 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
export declare const DEFAULT_WEB_PORT = 7780;
|
|
3
|
+
export interface WebOptions {
|
|
4
|
+
port?: number;
|
|
5
|
+
host?: string;
|
|
6
|
+
/** Workspace the UI treats as "当前工作区". Defaults to process.cwd(). */
|
|
7
|
+
cwd?: string;
|
|
8
|
+
/** Initial scope dropdown: cwd (default) or global. */
|
|
9
|
+
defaultScope?: 'cwd' | 'global';
|
|
10
|
+
/** Open the page in the default browser after listen. */
|
|
11
|
+
open?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface SrUiBoot {
|
|
14
|
+
mode: 'standalone';
|
|
15
|
+
cwd: string;
|
|
16
|
+
title: string;
|
|
17
|
+
defaultScope: 'cwd' | 'global';
|
|
18
|
+
}
|
|
19
|
+
export declare function renderIndexHtml(boot: SrUiBoot): string;
|
|
20
|
+
export declare function serveWeb(options?: WebOptions): Promise<http.Server>;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `1session web` — a standalone browser for the same session list, chat
|
|
3
|
+
* preview and file ledger the DSH plugin shows. Loopback by default; no
|
|
4
|
+
* DreamMate / DSH runtime required.
|
|
5
|
+
*/
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import http from 'node:http';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
import { handleSessionApi } from './api.js';
|
|
12
|
+
export const DEFAULT_WEB_PORT = 7780;
|
|
13
|
+
function appJsPath() {
|
|
14
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const sibling = path.join(here, 'app.js');
|
|
16
|
+
// tsx from src/web → repo dist/src/web/app.js; compiled run → sibling.
|
|
17
|
+
const fromSrc = path.resolve(here, '../../dist/src/web/app.js');
|
|
18
|
+
if (fs.existsSync(fromSrc))
|
|
19
|
+
return fromSrc;
|
|
20
|
+
return sibling;
|
|
21
|
+
}
|
|
22
|
+
export function renderIndexHtml(boot) {
|
|
23
|
+
const bootJson = JSON.stringify(boot).replace(/</g, '\\u003c');
|
|
24
|
+
return `<!DOCTYPE html>
|
|
25
|
+
<html lang="zh-CN">
|
|
26
|
+
<head>
|
|
27
|
+
<meta charset="utf-8" />
|
|
28
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
29
|
+
<title>历史会话 · 1session</title>
|
|
30
|
+
<script>window.__SR_UI__=${bootJson};</script>
|
|
31
|
+
<script src="/app.js" defer></script>
|
|
32
|
+
</head>
|
|
33
|
+
<body></body>
|
|
34
|
+
</html>
|
|
35
|
+
`;
|
|
36
|
+
}
|
|
37
|
+
function openBrowser(url) {
|
|
38
|
+
const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'cmd' : 'xdg-open';
|
|
39
|
+
const args = process.platform === 'win32' ? ['/c', 'start', '', url] : [url];
|
|
40
|
+
spawn(cmd, args, { stdio: 'ignore', detached: true }).unref();
|
|
41
|
+
}
|
|
42
|
+
export async function serveWeb(options = {}) {
|
|
43
|
+
const host = options.host ?? '127.0.0.1';
|
|
44
|
+
const cwd = options.cwd ?? process.cwd();
|
|
45
|
+
const defaultScope = options.defaultScope ?? 'cwd';
|
|
46
|
+
const boot = {
|
|
47
|
+
mode: 'standalone',
|
|
48
|
+
cwd,
|
|
49
|
+
title: path.basename(cwd) || '当前工作区',
|
|
50
|
+
defaultScope,
|
|
51
|
+
};
|
|
52
|
+
const appJs = appJsPath();
|
|
53
|
+
const server = http.createServer(async (req, res) => {
|
|
54
|
+
const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
|
|
55
|
+
const pathname = url.pathname;
|
|
56
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
57
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
|
58
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
59
|
+
if (req.method === 'OPTIONS') {
|
|
60
|
+
res.statusCode = 204;
|
|
61
|
+
res.end();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
if (pathname === '/' || pathname === '/index.html') {
|
|
66
|
+
const body = renderIndexHtml(boot);
|
|
67
|
+
res.writeHead(200, { 'content-type': 'text/html; charset=utf-8' });
|
|
68
|
+
res.end(body);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (pathname === '/app.js') {
|
|
72
|
+
if (!fs.existsSync(appJs)) {
|
|
73
|
+
res.writeHead(500, { 'content-type': 'text/plain; charset=utf-8' });
|
|
74
|
+
res.end('missing dist/src/web/app.js — run npm run build');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
res.writeHead(200, {
|
|
78
|
+
'content-type': 'application/javascript; charset=utf-8',
|
|
79
|
+
'cache-control': 'no-store',
|
|
80
|
+
});
|
|
81
|
+
res.end(fs.readFileSync(appJs));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (pathname.startsWith('/api/session-reader')) {
|
|
85
|
+
const apiPath = pathname.replace(/^\/api\/session-reader/, '') || '/';
|
|
86
|
+
const handled = await handleSessionApi(apiPath, url, res, { fallbackCwd: cwd });
|
|
87
|
+
if (handled)
|
|
88
|
+
return;
|
|
89
|
+
res.writeHead(404, { 'content-type': 'application/json; charset=utf-8' });
|
|
90
|
+
res.end(JSON.stringify({ error: 'Endpoint not found' }));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
res.writeHead(404, { 'content-type': 'text/plain; charset=utf-8' });
|
|
94
|
+
res.end('Not found');
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
98
|
+
if (!res.headersSent) {
|
|
99
|
+
res.writeHead(500, { 'content-type': 'application/json; charset=utf-8' });
|
|
100
|
+
}
|
|
101
|
+
res.end(JSON.stringify({ error: message }));
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
const wanted = options.port ?? DEFAULT_WEB_PORT;
|
|
105
|
+
await new Promise((resolve, reject) => {
|
|
106
|
+
server.once('error', (error) => {
|
|
107
|
+
reject(error.code === 'EADDRINUSE'
|
|
108
|
+
? new Error(`端口 ${wanted} 已被占用。换一个:1session web --port <n>;或先停掉占用它的进程:` +
|
|
109
|
+
`lsof -nP -iTCP:${wanted} -sTCP:LISTEN`)
|
|
110
|
+
: error);
|
|
111
|
+
});
|
|
112
|
+
server.listen(wanted, host, resolve);
|
|
113
|
+
});
|
|
114
|
+
const { port } = server.address();
|
|
115
|
+
const origin = `http://${host}:${port}`;
|
|
116
|
+
console.log('1session web — 独立历史会话浏览器');
|
|
117
|
+
console.log(` ${origin}`);
|
|
118
|
+
console.log(` 工作区 ${cwd}`);
|
|
119
|
+
console.log(' 列表只拉元数据,点击会话后再加载对话与文件。Ctrl+C 退出。');
|
|
120
|
+
if (host !== '127.0.0.1' && host !== 'localhost' && host !== '::1') {
|
|
121
|
+
console.warn(` ⚠️ 绑定在 ${host}:会话原文(代码、shell 历史、密钥)将对该网络开放。`);
|
|
122
|
+
}
|
|
123
|
+
if (options.open)
|
|
124
|
+
openBrowser(origin);
|
|
125
|
+
return server;
|
|
126
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1agents/session-reader",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Read Plane: cross-agent session discovery, turn inspection, workspace aggregation and distillation from raw local session files.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
@@ -29,6 +29,23 @@
|
|
|
29
29
|
".": {
|
|
30
30
|
"types": "./dist/src/index.d.ts",
|
|
31
31
|
"import": "./dist/src/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./client": {
|
|
34
|
+
"types": "./dist/src/dsh/client.d.ts",
|
|
35
|
+
"default": "./dist/src/dsh/client.js"
|
|
36
|
+
},
|
|
37
|
+
"./dsh": {
|
|
38
|
+
"types": "./dist/src/dsh/index.d.ts",
|
|
39
|
+
"import": "./dist/src/dsh/index.js"
|
|
40
|
+
},
|
|
41
|
+
"./cordis.patch.yml": "./cordis.patch.yml"
|
|
42
|
+
},
|
|
43
|
+
"dsh": {
|
|
44
|
+
"bundle": {
|
|
45
|
+
"patch": "./cordis.patch.yml"
|
|
46
|
+
},
|
|
47
|
+
"client": {
|
|
48
|
+
"platform": "web"
|
|
32
49
|
}
|
|
33
50
|
},
|
|
34
51
|
"bin": {
|
|
@@ -37,6 +54,7 @@
|
|
|
37
54
|
"files": [
|
|
38
55
|
"dist",
|
|
39
56
|
"skills",
|
|
57
|
+
"cordis.patch.yml",
|
|
40
58
|
"README.md"
|
|
41
59
|
],
|
|
42
60
|
"publishConfig": {
|
|
@@ -44,9 +62,9 @@
|
|
|
44
62
|
"provenance": true
|
|
45
63
|
},
|
|
46
64
|
"scripts": {
|
|
47
|
-
"build": "tsc -p tsconfig.build.json",
|
|
65
|
+
"build": "tsc -p tsconfig.build.json && node scripts/bundle-client.js",
|
|
48
66
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
49
|
-
"test": "node --import tsx --test test/session-reader.test.ts",
|
|
67
|
+
"test": "node --import tsx --test test/session-reader.test.ts test/dsh-adapter.test.ts test/web.test.ts",
|
|
50
68
|
"prepack": "npm run build",
|
|
51
69
|
"1session": "tsx bin/1session.ts"
|
|
52
70
|
},
|
|
@@ -55,11 +73,14 @@
|
|
|
55
73
|
},
|
|
56
74
|
"devDependencies": {
|
|
57
75
|
"@types/node": "^22.10.2",
|
|
76
|
+
"esbuild": "^0.28.2",
|
|
58
77
|
"tsx": "^4.19.2",
|
|
59
78
|
"typescript": "^5.7.2"
|
|
60
79
|
},
|
|
61
80
|
"dependencies": {
|
|
81
|
+
"@1agents/chat-ui": "^0.1.0",
|
|
62
82
|
"@1agents/dreammate-network": "^0.3.0",
|
|
63
|
-
"@1agents/dreammate-node": "^0.4.0"
|
|
83
|
+
"@1agents/dreammate-node": "^0.4.0",
|
|
84
|
+
"preact": "^10.19.6"
|
|
64
85
|
}
|
|
65
86
|
}
|
package/skills/1session/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: 1session
|
|
3
|
-
description:
|
|
3
|
+
description: 通过 1session CLI 从本地原始会话文件中检索并读取用户在 Claude Code、Codex、Antigravity、Grok 和 DeepSeek Harness (dsh) 中沉淀的历史 AI 编程会话。每当用户提及之前会话中完成的工作而非当前对话内容时激活此技能——例如“上次/之前/昨天我们改了什么”、“那个报错后来怎么解决的”、“我在哪个会话里提过 X”、“这个功能是哪一轮加的”、“codex 那边做到哪了”、“grok/dsh 那边呢”、“跨项目找一下”、“整理一下最近几天的会话/写个周报”。在要求用户重复解释本机上已有明确记录的上下文之前,也应主动调用此技能——答案通常已保存在磁盘中。纯只读设计:绝不修改或恢复历史会话。本技能还包含自身的自举运行与分发逻辑:在未安装 1session CLI 时自动降级为 npx 随用随走,并支持将包全局安装以及一键同步技能至全部五款 Agent——因此当用户要求安装、升级、卸载、分享或分发 1session / session-reader,或报告未找到 1session 命令时也可使用本技能。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# 1session — the cross-agent Read Plane
|
|
@@ -79,6 +79,7 @@ whole ladder by reflex:
|
|
|
79
79
|
| "find where we talked about X / which turn was that" | `turns` |
|
|
80
80
|
| "what exactly did it do at step N" | `turn <n>`, then `--event k` |
|
|
81
81
|
| "what did all the agents do in this project" | `workspace` |
|
|
82
|
+
| "open a browser / web UI for sessions" (no DSH) | `web` |
|
|
82
83
|
|
|
83
84
|
"What happened in that session" and "find where we talked about X" look like the
|
|
84
85
|
same question and are not. `overview` compresses a session into statistics and
|
|
@@ -141,6 +141,22 @@ The file ledger never contains `candidate` paths — a path only enters after a
|
|
|
141
141
|
write is proven. Here-doc bodies are stripped before command analysis, so source
|
|
142
142
|
code being written to a file cannot masquerade as a redirect or an `ssh` host.
|
|
143
143
|
|
|
144
|
+
## Standalone web UI
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
1session web [--port 7780] [--host 127.0.0.1] [--open] [--scope <path>|cwd|global]
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
A local browser for the same session list, chat preview and file ledger the DSH
|
|
151
|
+
plugin shows. Does not require DSH. Default bind is loopback `127.0.0.1:7780`.
|
|
152
|
+
|
|
153
|
+
The listing is metadata-only; clicking a row loads that session's turns and
|
|
154
|
+
files. `--open` launches the default browser. `--scope global` starts the UI
|
|
155
|
+
on every workspace; a path scopes "当前工作区" to that directory.
|
|
156
|
+
|
|
157
|
+
This is not `1session serve`. `serve` is the DreamMate Network JSON service;
|
|
158
|
+
`web` is a human-facing page.
|
|
159
|
+
|
|
144
160
|
## Index and graph
|
|
145
161
|
|
|
146
162
|
```
|