dsh-agent-office 4.6.0 → 4.6.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/README.md +3 -1
- package/lib/client.js +126 -2
- package/lib/index.js +34 -1
- package/lib/panel.html +239 -191
- package/lib/state.js +70 -0
- package/package.json +1 -1
- package/panel-src/assets/exp-uneven.png +0 -0
- package/panel-src/index.html +50 -2
- package/panel-src/main.js +576 -72
package/lib/state.js
CHANGED
|
@@ -301,6 +301,76 @@ export async function fetchDeepSeekBalance(options = {}) {
|
|
|
301
301
|
}
|
|
302
302
|
}
|
|
303
303
|
|
|
304
|
+
/** 获取某个坐标的当前天气;只返回公开天气字段,不含用户位置标识。 */
|
|
305
|
+
const weatherCache = new Map()
|
|
306
|
+
export async function fetchWeather(options = {}) {
|
|
307
|
+
const lat = Number(options.lat)
|
|
308
|
+
const lon = Number(options.lon)
|
|
309
|
+
if (!Number.isFinite(lat) || !Number.isFinite(lon) || lat < -90 || lat > 90 || lon < -180 || lon > 180) {
|
|
310
|
+
return { ok: false, error: '无效的坐标' }
|
|
311
|
+
}
|
|
312
|
+
const key = `${lat.toFixed(2)},${lon.toFixed(2)}`
|
|
313
|
+
const cached = weatherCache.get(key)
|
|
314
|
+
if (cached && Date.now() - cached.at < 10 * 60 * 1000) return cached.payload
|
|
315
|
+
const url = `https://api.open-meteo.com/v1/forecast?latitude=${encodeURIComponent(lat)}&longitude=${encodeURIComponent(lon)}¤t=temperature_2m,weather_code,wind_speed_10m,is_day&timezone=auto`
|
|
316
|
+
try {
|
|
317
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(10_000) })
|
|
318
|
+
if (!response.ok) throw new Error('weather HTTP ' + response.status)
|
|
319
|
+
const body = await response.json()
|
|
320
|
+
const current = body?.current
|
|
321
|
+
if (!current) throw new Error('weather payload empty')
|
|
322
|
+
const payload = {
|
|
323
|
+
ok: true,
|
|
324
|
+
temperature: Number(current.temperature_2m),
|
|
325
|
+
code: Number(current.weather_code),
|
|
326
|
+
wind: Number(current.wind_speed_10m),
|
|
327
|
+
is_day: Number(current.is_day) === 1,
|
|
328
|
+
timezone: body.timezone ?? '',
|
|
329
|
+
updated_at: Date.now(),
|
|
330
|
+
}
|
|
331
|
+
weatherCache.set(key, { at: Date.now(), payload })
|
|
332
|
+
return payload
|
|
333
|
+
} catch (error) {
|
|
334
|
+
const payload = { ok: false, error: '天气请求失败:' + String(error?.message ?? error) }
|
|
335
|
+
weatherCache.set(key, { at: Date.now(), payload })
|
|
336
|
+
return payload
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/** 城市名 → 坐标;用于定位不可用时的天气回退。 */
|
|
341
|
+
const geocodeCache = new Map()
|
|
342
|
+
export async function fetchGeocode(options = {}) {
|
|
343
|
+
const name = String(options.name ?? '').trim()
|
|
344
|
+
if (!name) return { ok: false, error: '请输入城市名' }
|
|
345
|
+
if (name.length > 80) return { ok: false, error: '城市名过长' }
|
|
346
|
+
const cached = geocodeCache.get(name)
|
|
347
|
+
if (cached && Date.now() - cached.at < 24 * 3600 * 1000) return cached.payload
|
|
348
|
+
const url = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(name)}&count=1&language=zh&format=json`
|
|
349
|
+
try {
|
|
350
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(10_000) })
|
|
351
|
+
if (!response.ok) throw new Error('geocode HTTP ' + response.status)
|
|
352
|
+
const body = await response.json()
|
|
353
|
+
const hit = body?.results?.[0]
|
|
354
|
+
if (!hit) {
|
|
355
|
+
const payload = { ok: false, error: '没有找到这个城市,换个写法试试' }
|
|
356
|
+
geocodeCache.set(name, { at: Date.now(), payload })
|
|
357
|
+
return payload
|
|
358
|
+
}
|
|
359
|
+
const payload = {
|
|
360
|
+
ok: true,
|
|
361
|
+
name: hit.name,
|
|
362
|
+
admin1: hit.admin1 ?? '',
|
|
363
|
+
country: hit.country ?? '',
|
|
364
|
+
lat: Number(hit.latitude),
|
|
365
|
+
lon: Number(hit.longitude),
|
|
366
|
+
}
|
|
367
|
+
geocodeCache.set(name, { at: Date.now(), payload })
|
|
368
|
+
return payload
|
|
369
|
+
} catch (error) {
|
|
370
|
+
return { ok: false, error: '城市查询失败:' + String(error?.message ?? error) }
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
304
374
|
export function createNightShiftStore(options = {}) {
|
|
305
375
|
const sessionsDir = options.sessionsDir ?? join(process.env.DSH_HOME || join(homedir(), '.dsh'), 'sessions')
|
|
306
376
|
const maxAgents = Number(options.maxAgents ?? 8)
|
package/package.json
CHANGED
|
Binary file
|
package/panel-src/index.html
CHANGED
|
@@ -29,6 +29,8 @@
|
|
|
29
29
|
--scroll:rgba(255,255,255,.2);
|
|
30
30
|
--scroll-hi:rgba(255,255,255,.32);
|
|
31
31
|
--label:rgba(8,11,15,.82);
|
|
32
|
+
--tag-bg:rgba(8,16,24,.48);
|
|
33
|
+
--tag-line:rgba(255,255,255,.24);
|
|
32
34
|
--hint:rgba(12,15,20,.66);
|
|
33
35
|
--chip:rgba(12,18,22,.86);
|
|
34
36
|
--focus-line:rgba(61,225,198,.3);
|
|
@@ -79,6 +81,8 @@
|
|
|
79
81
|
--scroll:rgba(16,40,54,.2);
|
|
80
82
|
--scroll-hi:rgba(16,40,54,.32);
|
|
81
83
|
--label:rgba(250,252,253,.95);
|
|
84
|
+
--tag-bg:rgba(250,253,255,.44);
|
|
85
|
+
--tag-line:rgba(16,40,54,.2);
|
|
82
86
|
--hint:rgba(250,252,253,.84);
|
|
83
87
|
--chip:rgba(252,253,254,.92);
|
|
84
88
|
--focus-line:rgba(8,117,101,.3);
|
|
@@ -249,7 +253,43 @@
|
|
|
249
253
|
.lbl .badge{display:inline-block;width:6px;height:6px;border-radius:50%;margin-right:5px;vertical-align:1px}
|
|
250
254
|
.floorlbl{position:absolute;transform:translate(-50%,-50%);font-family:var(--mono);font-size:11px;letter-spacing:2px;color:rgba(138,148,163,.9);padding:3px 9px;border:1px solid var(--line-2);border-radius:999px;background:var(--label);white-space:nowrap}
|
|
251
255
|
.floorlbl b{color:var(--ink);font-weight:600;margin-left:6px;letter-spacing:0}
|
|
252
|
-
.
|
|
256
|
+
.mcpTag{
|
|
257
|
+
display:inline-flex;align-items:center;gap:7px;font-family:var(--mono);font-size:11.5px;font-weight:600;
|
|
258
|
+
letter-spacing:1px;color:var(--ink);padding:0;border:0;border-radius:0;background:none;white-space:nowrap;
|
|
259
|
+
pointer-events:none;text-shadow:0 1px 3px rgba(0,0,0,.55);
|
|
260
|
+
}
|
|
261
|
+
body.day .mcpTag{text-shadow:0 1px 2px rgba(255,255,255,.6)}
|
|
262
|
+
.mcpTag .x{color:#4ea8ff;font-size:12px;font-weight:700;line-height:1}
|
|
263
|
+
|
|
264
|
+
.officeTag{
|
|
265
|
+
font-family:var(--mono);font-size:9px;font-weight:600;letter-spacing:1.2px;color:var(--ink);padding:2px 8px;
|
|
266
|
+
border:1px solid rgba(255,255,255,.62);border-radius:999px;background:var(--tag-bg);white-space:nowrap;
|
|
267
|
+
backdrop-filter:blur(10px) saturate(1.2);-webkit-backdrop-filter:blur(10px) saturate(1.2);
|
|
268
|
+
box-shadow:inset 0 1px 0 rgba(255,255,255,.3),0 4px 14px rgba(10,22,34,.12);
|
|
269
|
+
transition:background-color .4s,border-color .4s,color .4s,box-shadow .4s;
|
|
270
|
+
}
|
|
271
|
+
/* ---------- 建造入场 ---------- */
|
|
272
|
+
body.intro #top,body.intro #left,body.intro #right,body.intro #feed,body.intro #credit,body.intro #hint,body.intro .lbl,body.intro .mcpTag{opacity:0;pointer-events:none}
|
|
273
|
+
.lbl,.mcpTag{transition:opacity .45s ease}
|
|
274
|
+
#top,#left,#right,#feed,#credit,#hint{transition:opacity .65s cubic-bezier(.2,0,0,1),transform .65s cubic-bezier(.2,0,0,1)}
|
|
275
|
+
body.intro #top{transform:translateY(-10px)}
|
|
276
|
+
body.intro #left{transform:translateX(-14px)}
|
|
277
|
+
body.intro #right{transform:translateX(14px)}
|
|
278
|
+
body.intro #feed{transform:translateY(14px)}
|
|
279
|
+
#intro{position:absolute;inset:0;z-index:30;display:grid;place-items:center;background:radial-gradient(ellipse at 50% 45%,rgba(5,11,18,.26),rgba(3,7,11,.84));transition:opacity .55s ease,visibility .55s ease}
|
|
280
|
+
#intro.done{opacity:0;visibility:hidden;pointer-events:none}
|
|
281
|
+
.intro__loader{display:grid;justify-items:center;gap:14px;color:var(--ink)}
|
|
282
|
+
.intro__spinner{position:relative;width:76px;height:76px;border-radius:50%;filter:drop-shadow(0 0 18px rgba(61,225,198,.2))}
|
|
283
|
+
.intro__spinner i{position:absolute;inset:0;border-radius:50%;border:2px solid transparent;border-top-color:var(--acc);border-right-color:color-mix(in srgb,var(--acc) 32%,transparent);animation:intro-spin 1.05s linear infinite}
|
|
284
|
+
.intro__spinner i:nth-child(2){inset:9px;border-top-color:#5b8cff;border-left-color:rgba(91,140,255,.34);animation-duration:.78s;animation-direction:reverse}
|
|
285
|
+
.intro__spinner i:nth-child(3){inset:18px;border-top-color:rgba(233,238,245,.78);border-bottom-color:rgba(233,238,245,.18);animation-duration:.54s}
|
|
286
|
+
.intro__spinner::after{content:"";position:absolute;inset:31px;border-radius:50%;background:radial-gradient(circle,var(--acc) 0,rgba(61,225,198,.35) 38%,transparent 70%);box-shadow:0 0 20px rgba(61,225,198,.55);animation:intro-pulse 1.6s ease-in-out infinite}
|
|
287
|
+
.intro__label{font-family:var(--mono);font-size:9.5px;letter-spacing:3.2px;color:var(--dim);margin-top:2px}
|
|
288
|
+
.intro__hint{font-family:var(--mono);font-size:9px;letter-spacing:1.2px;color:var(--dim-2);opacity:.7}
|
|
289
|
+
@keyframes intro-spin{to{transform:rotate(360deg)}}
|
|
290
|
+
@keyframes intro-pulse{0%,100%{transform:scale(.82);opacity:.55}50%{transform:scale(1.1);opacity:.95}}
|
|
291
|
+
@media (prefers-reduced-motion:reduce){.intro__spinner i,.intro__spinner::after{animation:none}}
|
|
292
|
+
@media (prefers-reduced-motion:reduce){#intro{transition:none}}
|
|
253
293
|
@media (max-width:1180px){
|
|
254
294
|
#left{width:280px}
|
|
255
295
|
#right{width:300px}
|
|
@@ -298,7 +338,7 @@
|
|
|
298
338
|
}
|
|
299
339
|
</style>
|
|
300
340
|
</head>
|
|
301
|
-
<body>
|
|
341
|
+
<body class="intro">
|
|
302
342
|
<div id="app">
|
|
303
343
|
<div id="stage"></div>
|
|
304
344
|
<div id="labels"></div>
|
|
@@ -360,6 +400,14 @@
|
|
|
360
400
|
|
|
361
401
|
<div id="hint">左键点楼层聚焦 · 右键返回全局 · 拖动旋转 · 滚轮缩放</div>
|
|
362
402
|
<div id="offline">正在连接 DSH 会话数据…</div>
|
|
403
|
+
|
|
404
|
+
<div id="intro" role="status" aria-live="polite">
|
|
405
|
+
<div class="intro__loader">
|
|
406
|
+
<div class="intro__spinner" aria-hidden="true"><i></i><i></i><i></i></div>
|
|
407
|
+
<div class="intro__label">BUILDING OFFICE</div>
|
|
408
|
+
<div class="intro__hint">点击跳过</div>
|
|
409
|
+
</div>
|
|
410
|
+
</div>
|
|
363
411
|
</div>
|
|
364
412
|
<script>/*__BUNDLE__*/</script>
|
|
365
413
|
</body>
|