@lingerai/cli 0.1.1 → 0.1.2
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/package.json +1 -1
- package/src/callback-pages.js +174 -0
- package/src/oauth.js +7 -4
package/package.json
CHANGED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// -*- linger auth login 本地 loopback 回调页(三状态 HTML)-*-
|
|
2
|
+
//
|
|
3
|
+
// 设计:对齐 A2A 平台网页设计规范(a2a-frontend/src/shared/tokens.css)——
|
|
4
|
+
// 白底(#F5F6F8 / #FFFFFF)+ 近黑文字(#0F1419 / #4B5563)+ 黑白为主、克制。
|
|
5
|
+
// 不用桌面端 Aria 琥珀金(那是另一条产品线的品牌色 · 2026-06-20 产品负责人纠正)。
|
|
6
|
+
// 参考飞书/主流 OAuth 成功页:居中、一屏、纯内联零外部资源(localhost 离线可渲染)、
|
|
7
|
+
// 图标用内联 SVG、动画包 prefers-reduced-motion 降级、文案极简(每页 1 句 caption)。
|
|
8
|
+
//
|
|
9
|
+
// 三个常量对应 oauth.js loopback handler 的三个 res.end:
|
|
10
|
+
// SUCCESS — 拿到 code(绑定成功 · 带「打开 Linger 主页」按钮)
|
|
11
|
+
// ERROR — error(授权未完成 · 回命令行重试)
|
|
12
|
+
// MISSING — 缺授权码(回调异常)
|
|
13
|
+
|
|
14
|
+
const CALLBACK_HTML_SUCCESS = `<!DOCTYPE html>
|
|
15
|
+
<html lang="zh-CN">
|
|
16
|
+
<head>
|
|
17
|
+
<meta charset="utf-8">
|
|
18
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
19
|
+
<title>绑定成功 · Linger</title>
|
|
20
|
+
<style>
|
|
21
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
22
|
+
html,body{height:100%}
|
|
23
|
+
body{
|
|
24
|
+
font-family:-apple-system,BlinkMacSystemFont,"SF Pro Display","SF Pro Text","Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",system-ui,sans-serif;
|
|
25
|
+
background:#F5F6F8;color:#0F1419;
|
|
26
|
+
display:flex;align-items:center;justify-content:center;
|
|
27
|
+
min-height:100vh;min-height:100dvh;
|
|
28
|
+
padding:24px;line-height:1.6;-webkit-font-smoothing:antialiased;
|
|
29
|
+
}
|
|
30
|
+
.card{
|
|
31
|
+
width:100%;max-width:380px;text-align:center;
|
|
32
|
+
padding:8px;opacity:0;transform:translateY(10px);
|
|
33
|
+
animation:rise .6s cubic-bezier(.16,1,.3,1) .05s forwards;
|
|
34
|
+
}
|
|
35
|
+
.badge{
|
|
36
|
+
width:72px;height:72px;border-radius:999px;margin:0 auto 32px;
|
|
37
|
+
display:flex;align-items:center;justify-content:center;
|
|
38
|
+
background:rgba(15,20,25,.06);
|
|
39
|
+
}
|
|
40
|
+
.badge svg{width:34px;height:34px}
|
|
41
|
+
.check{
|
|
42
|
+
fill:none;stroke:#0F1419;stroke-width:2.5;
|
|
43
|
+
stroke-linecap:round;stroke-linejoin:round;
|
|
44
|
+
stroke-dasharray:32;stroke-dashoffset:32;
|
|
45
|
+
animation:draw .5s cubic-bezier(.65,0,.45,1) .35s forwards;
|
|
46
|
+
}
|
|
47
|
+
h1{font-size:21px;font-weight:500;letter-spacing:.02em;margin-bottom:12px}
|
|
48
|
+
p{font-size:14px;color:#4B5563;letter-spacing:.02em;margin-bottom:36px}
|
|
49
|
+
.btn{
|
|
50
|
+
display:inline-block;padding:13px 32px;border-radius:8px;
|
|
51
|
+
background:#0F1419;color:#fff;
|
|
52
|
+
font-size:14px;font-weight:500;letter-spacing:.02em;text-decoration:none;
|
|
53
|
+
transition:transform .2s ease-out,background .2s ease-out;
|
|
54
|
+
}
|
|
55
|
+
.btn:hover{background:#2C3340}
|
|
56
|
+
.btn:active{transform:scale(.97)}
|
|
57
|
+
@keyframes rise{to{opacity:1;transform:translateY(0)}}
|
|
58
|
+
@keyframes draw{to{stroke-dashoffset:0}}
|
|
59
|
+
@media (prefers-reduced-motion:reduce){
|
|
60
|
+
.card{animation:none;opacity:1;transform:none}
|
|
61
|
+
.check{animation:none;stroke-dashoffset:0}
|
|
62
|
+
.btn{transition:none}
|
|
63
|
+
}
|
|
64
|
+
</style>
|
|
65
|
+
</head>
|
|
66
|
+
<body>
|
|
67
|
+
<main class="card">
|
|
68
|
+
<div class="badge" aria-hidden="true">
|
|
69
|
+
<svg viewBox="0 0 24 24"><path class="check" d="M5 13l4 4L19 7"/></svg>
|
|
70
|
+
</div>
|
|
71
|
+
<h1>绑定成功 · 已连接 Linger</h1>
|
|
72
|
+
<p>可以关闭此页面,回到命令行</p>
|
|
73
|
+
<a class="btn" href="https://a2a.linger.chimap.cn">打开 Linger 主页</a>
|
|
74
|
+
</main>
|
|
75
|
+
</body>
|
|
76
|
+
</html>`;
|
|
77
|
+
|
|
78
|
+
const CALLBACK_HTML_ERROR = `<!DOCTYPE html>
|
|
79
|
+
<html lang="zh-CN">
|
|
80
|
+
<head>
|
|
81
|
+
<meta charset="utf-8">
|
|
82
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
83
|
+
<title>授权未完成 · Linger</title>
|
|
84
|
+
<style>
|
|
85
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
86
|
+
html,body{height:100%}
|
|
87
|
+
body{
|
|
88
|
+
font-family:-apple-system,BlinkMacSystemFont,"SF Pro Display","SF Pro Text","Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",system-ui,sans-serif;
|
|
89
|
+
background:#F5F6F8;color:#0F1419;
|
|
90
|
+
display:flex;align-items:center;justify-content:center;
|
|
91
|
+
min-height:100vh;min-height:100dvh;
|
|
92
|
+
padding:24px;line-height:1.6;-webkit-font-smoothing:antialiased;
|
|
93
|
+
}
|
|
94
|
+
.card{
|
|
95
|
+
width:100%;max-width:380px;text-align:center;padding:8px;
|
|
96
|
+
opacity:0;transform:translateY(10px);
|
|
97
|
+
animation:rise .6s cubic-bezier(.16,1,.3,1) .05s forwards;
|
|
98
|
+
}
|
|
99
|
+
.badge{
|
|
100
|
+
width:72px;height:72px;border-radius:999px;margin:0 auto 32px;
|
|
101
|
+
display:flex;align-items:center;justify-content:center;
|
|
102
|
+
background:rgba(15,20,25,.05);
|
|
103
|
+
}
|
|
104
|
+
.badge svg{width:32px;height:32px}
|
|
105
|
+
.mark{fill:none;stroke:#0F1419;stroke-width:2.2;stroke-linecap:round;opacity:.55}
|
|
106
|
+
h1{font-size:21px;font-weight:500;letter-spacing:.02em;margin-bottom:12px}
|
|
107
|
+
p{font-size:14px;color:#4B5563;letter-spacing:.02em}
|
|
108
|
+
@keyframes rise{to{opacity:1;transform:translateY(0)}}
|
|
109
|
+
@media (prefers-reduced-motion:reduce){.card{animation:none;opacity:1;transform:none}}
|
|
110
|
+
</style>
|
|
111
|
+
</head>
|
|
112
|
+
<body>
|
|
113
|
+
<main class="card">
|
|
114
|
+
<div class="badge" aria-hidden="true">
|
|
115
|
+
<svg viewBox="0 0 24 24">
|
|
116
|
+
<line class="mark" x1="12" y1="7" x2="12" y2="13"/>
|
|
117
|
+
<line class="mark" x1="12" y1="17" x2="12" y2="17"/>
|
|
118
|
+
</svg>
|
|
119
|
+
</div>
|
|
120
|
+
<h1>授权未完成</h1>
|
|
121
|
+
<p>可以关闭此页面,回到命令行重试</p>
|
|
122
|
+
</main>
|
|
123
|
+
</body>
|
|
124
|
+
</html>`;
|
|
125
|
+
|
|
126
|
+
const CALLBACK_HTML_MISSING = `<!DOCTYPE html>
|
|
127
|
+
<html lang="zh-CN">
|
|
128
|
+
<head>
|
|
129
|
+
<meta charset="utf-8">
|
|
130
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
131
|
+
<title>回调异常 · Linger</title>
|
|
132
|
+
<style>
|
|
133
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
134
|
+
html,body{height:100%}
|
|
135
|
+
body{
|
|
136
|
+
font-family:-apple-system,BlinkMacSystemFont,"SF Pro Display","SF Pro Text","Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",system-ui,sans-serif;
|
|
137
|
+
background:#F5F6F8;color:#0F1419;
|
|
138
|
+
display:flex;align-items:center;justify-content:center;
|
|
139
|
+
min-height:100vh;min-height:100dvh;
|
|
140
|
+
padding:24px;line-height:1.6;-webkit-font-smoothing:antialiased;
|
|
141
|
+
}
|
|
142
|
+
.card{
|
|
143
|
+
width:100%;max-width:380px;text-align:center;padding:8px;
|
|
144
|
+
opacity:0;transform:translateY(10px);
|
|
145
|
+
animation:rise .6s cubic-bezier(.16,1,.3,1) .05s forwards;
|
|
146
|
+
}
|
|
147
|
+
.badge{
|
|
148
|
+
width:72px;height:72px;border-radius:999px;margin:0 auto 32px;
|
|
149
|
+
display:flex;align-items:center;justify-content:center;
|
|
150
|
+
background:rgba(15,20,25,.05);
|
|
151
|
+
}
|
|
152
|
+
.badge svg{width:30px;height:30px}
|
|
153
|
+
.mark{fill:none;stroke:#0F1419;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round;opacity:.55}
|
|
154
|
+
h1{font-size:21px;font-weight:500;letter-spacing:.02em;margin-bottom:12px}
|
|
155
|
+
p{font-size:14px;color:#4B5563;letter-spacing:.02em}
|
|
156
|
+
@keyframes rise{to{opacity:1;transform:translateY(0)}}
|
|
157
|
+
@media (prefers-reduced-motion:reduce){.card{animation:none;opacity:1;transform:none}}
|
|
158
|
+
</style>
|
|
159
|
+
</head>
|
|
160
|
+
<body>
|
|
161
|
+
<main class="card">
|
|
162
|
+
<div class="badge" aria-hidden="true">
|
|
163
|
+
<svg viewBox="0 0 24 24">
|
|
164
|
+
<path class="mark" d="M9.2 9.2a2.8 2.8 0 1 1 4.3 2.6c-.9.6-1.5 1.1-1.5 2.2"/>
|
|
165
|
+
<line class="mark" x1="12" y1="17.5" x2="12" y2="17.5"/>
|
|
166
|
+
</svg>
|
|
167
|
+
</div>
|
|
168
|
+
<h1>回调异常,缺少授权码</h1>
|
|
169
|
+
<p>可以关闭此页面</p>
|
|
170
|
+
</main>
|
|
171
|
+
</body>
|
|
172
|
+
</html>`;
|
|
173
|
+
|
|
174
|
+
export { CALLBACK_HTML_SUCCESS, CALLBACK_HTML_ERROR, CALLBACK_HTML_MISSING };
|
package/src/oauth.js
CHANGED
|
@@ -17,6 +17,7 @@ import { spawn } from 'node:child_process';
|
|
|
17
17
|
|
|
18
18
|
import { generateVerifier, challengeFromVerifier, generateState } from './pkce.js';
|
|
19
19
|
import { saveCredentials } from './credentials.js';
|
|
20
|
+
import { CALLBACK_HTML_SUCCESS, CALLBACK_HTML_ERROR, CALLBACK_HTML_MISSING } from './callback-pages.js';
|
|
20
21
|
|
|
21
22
|
// M5 预注册 client_id(已在平台 oauth_clients 表预注册,无需动态注册)。
|
|
22
23
|
export const POC_CLIENT_ID = 'linger-cli';
|
|
@@ -116,13 +117,13 @@ export function startLoopbackServer({ host = '127.0.0.1', port = 0 } = {}) {
|
|
|
116
117
|
// 给浏览器一个「可以关掉这个标签页了」的极简页面
|
|
117
118
|
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
118
119
|
if (error) {
|
|
119
|
-
res.end(
|
|
120
|
+
res.end(CALLBACK_HTML_ERROR);
|
|
120
121
|
rejectCode(new Error(`用户未授权或授权被拒绝:${error}`));
|
|
121
122
|
} else if (code) {
|
|
122
|
-
res.end(
|
|
123
|
+
res.end(CALLBACK_HTML_SUCCESS);
|
|
123
124
|
resolveCode({ code, state });
|
|
124
125
|
} else {
|
|
125
|
-
res.end(
|
|
126
|
+
res.end(CALLBACK_HTML_MISSING);
|
|
126
127
|
rejectCode(new Error('回调地址未带授权码'));
|
|
127
128
|
}
|
|
128
129
|
});
|
|
@@ -275,6 +276,8 @@ export async function runAuthLogin(opts = {}) {
|
|
|
275
276
|
|
|
276
277
|
const creds = { ...tokenObj, base_url: baseUrl };
|
|
277
278
|
const file = saveCredentials(creds, credDir ? { dir: credDir } : {});
|
|
278
|
-
log(
|
|
279
|
+
log('✓ 绑定成功,你的 Agent 已接入 Linger。');
|
|
280
|
+
log(` 在主页查看你的 Agent:${baseUrl}`);
|
|
281
|
+
log(` 凭证已保存到 ${file}`);
|
|
279
282
|
return creds;
|
|
280
283
|
}
|