sage-mem 0.6.4 → 0.7.1
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 +282 -247
- package/lib/{dream-audit.js → autodream-audit.js} +33 -15
- package/lib/{dream-prompt.js → autodream-prompt.js} +22 -14
- package/lib/{dream-tools.js → autodream-tools.js} +159 -26
- package/lib/autodream.js +1722 -0
- package/lib/client.js +487 -169
- package/lib/index.js +224 -72
- package/lib/typert.host.js +195 -67
- package/package.json +89 -89
- package/lib/dream.js +0 -886
package/lib/client.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* sage-mem —
|
|
2
|
+
* sage-mem — 界面侧:DSH 设置页「记忆管理」界面(文件管理器)。
|
|
3
3
|
*
|
|
4
|
-
* 手写 ModuleLoader bundle
|
|
4
|
+
* 手写 ModuleLoader bundle(`window.__ModuleLoader__.load({ id, factory })` 格式):
|
|
5
5
|
* window.__ModuleLoader__.load({ id, factory }),factory 内 require('react')
|
|
6
6
|
* 可用,module.exports 导出标准 Cordis 插件(apply/inject)。
|
|
7
7
|
*
|
|
8
|
-
* 数据通道:TypertRemoteService
|
|
8
|
+
* 数据通道:TypertRemoteService(宿主侧 MemoryGateway),通过
|
|
9
9
|
* ctx.get("remote.memory") 调用文件列表/读/写/删。remote 返回 {ok, value}
|
|
10
10
|
* 信封。浏览器侧无 zod,schema 手写(codec 只要求 mode==="strict" + parse)。
|
|
11
11
|
*
|
|
@@ -64,7 +64,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
64
64
|
invocation: { kind: "direct" },
|
|
65
65
|
parameters: [],
|
|
66
66
|
result: { mode: "strict", typeSymbol: "sage-starmap/types#StarList", schema: listSchema, create: () => listSchema },
|
|
67
|
-
sourceLocation: { "file": "
|
|
67
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
68
68
|
},
|
|
69
69
|
{
|
|
70
70
|
id: "sage-starmap#starmap/readFile",
|
|
@@ -76,7 +76,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
76
76
|
{ name: "name", wire: "name", source: "json", codec: { mode: "strict", typeSymbol: "sage-starmap/types#FileName", schema: strSchema, create: () => strSchema } },
|
|
77
77
|
],
|
|
78
78
|
result: { mode: "strict", typeSymbol: "sage-starmap/types#FileContent", schema: readSchema, create: () => readSchema },
|
|
79
|
-
sourceLocation: { "file": "
|
|
79
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
80
80
|
},
|
|
81
81
|
],
|
|
82
82
|
};
|
|
@@ -109,7 +109,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
109
109
|
|
|
110
110
|
// ── 常量与纯函数 ─────────────────────────────────────────────
|
|
111
111
|
//
|
|
112
|
-
//
|
|
112
|
+
// 配色(重做过一版):原来五个色都是高饱和高亮度(#ffd27d / #6fe3ff /
|
|
113
113
|
// #b18cff / #7dffb0),配上当时的星芒与脉冲环,整体读起来像贴纸。
|
|
114
114
|
// 现在统一降饱和、压亮度 —— 深空画布上够辨认,又不抢眼。
|
|
115
115
|
const KIND_META = {
|
|
@@ -373,7 +373,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
373
373
|
".smap-modal{width:min(980px,94vw);height:min(680px,92vh);background:linear-gradient(160deg,#0d1226,#111a33);border:1px solid rgba(140,160,220,.22);border-radius:16px;box-shadow:0 24px 80px rgba(0,0,0,.55);padding:16px 18px;display:flex;flex-direction:column;overflow:hidden;pointer-events:auto;animation:smap-pop-in .22s cubic-bezier(.2,.9,.3,1.15);}",
|
|
374
374
|
"@keyframes smap-fade-in{from{opacity:0}to{opacity:1}}",
|
|
375
375
|
"@keyframes smap-pop-in{from{opacity:0;transform:scale(.96) translateY(10px)}to{opacity:1;transform:none}}",
|
|
376
|
-
//
|
|
376
|
+
// 星图整块含 header 与图例,同属一张深色画布。
|
|
377
377
|
//
|
|
378
378
|
// 不这么做的下场是实测出来的:宿主切到**浅色主题**后,这个组件里硬编码的
|
|
379
379
|
// 浅色文字(#dbe4f5 系)落在白色卡片上,标题、搜索框、图例几乎看不见 ——
|
|
@@ -449,7 +449,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
449
449
|
}
|
|
450
450
|
|
|
451
451
|
const SMAP_BG_VS = "attribute vec2 aPos; void main(){ gl_Position = vec4(aPos, 0.0, 1.0); }";
|
|
452
|
-
//
|
|
452
|
+
// 底色(重做过一版)。旧版是四层 fbm 噪声算出来的蓝紫星云,还带 uTime 动画 ——
|
|
453
453
|
// 「会呼吸的彩色底」正是廉价感的一大来源,而且每帧都要重算噪声。
|
|
454
454
|
// 现在只剩一条静态径向渐变:中心略亮的中性深灰,边缘更暗。uTime 保留声明
|
|
455
455
|
// 只为让 uniform 列表不变(用不到时 getUniformLocation 返回 null,调用是安全空操作)。
|
|
@@ -484,7 +484,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
484
484
|
"}",
|
|
485
485
|
].join("\n");
|
|
486
486
|
|
|
487
|
-
//
|
|
487
|
+
// 星点(重做过一版)。去掉了三样东西,它们是「塑料感」的来源:
|
|
488
488
|
// 1. 衍射星芒(横竖两条十字 spike)—— 用户明确要求去掉
|
|
489
489
|
// 2. 脉冲扩散环(fract(uTime*0.3) 画出来的同心圆)—— 看起来像贴纸上的亮环
|
|
490
490
|
// 3. 呼吸闪烁(sin(uTime) 调制整体透明度)—— 满屏一起闪,廉价
|
|
@@ -958,7 +958,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
958
958
|
drawBox.t0 = Date.now();
|
|
959
959
|
renderer.render(0);
|
|
960
960
|
|
|
961
|
-
// ──
|
|
961
|
+
// ── 按需重绘(重做过一版)──
|
|
962
962
|
// 旧版是一个常驻 rAF 循环:只要星图页开着就永远满帧重画,后台标签页也一样,
|
|
963
963
|
// 而画面其实早就静止了。新的规矩只有三种情况会画:
|
|
964
964
|
// 1. 入场展示动画期间(约 1.3s,星点按诞生时间依次点亮)
|
|
@@ -1311,7 +1311,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1311
1311
|
|
|
1312
1312
|
/**
|
|
1313
1313
|
* Client 插件:$mount strict remote contribution(第三方 remote 不在
|
|
1314
|
-
*
|
|
1314
|
+
* 宿主的固定 remote 清单里,必须自己挂),再注册 footer 按钮与 overlay。
|
|
1315
1315
|
*/
|
|
1316
1316
|
async function apply(ctx) {
|
|
1317
1317
|
appCtx = ctx;
|
|
@@ -1366,7 +1366,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1366
1366
|
const starmapListSchema = { parse(v) { if (!v || typeof v !== "object") throw new Error("expected object"); if (!Array.isArray(v.stars)) throw new Error("expected stars array"); v.stars.forEach((f) => starmapStarSchema.parse(f)); return v; } };
|
|
1367
1367
|
const starmapReadSchema = parseSchema({ "name": isStr, "content": isStr });
|
|
1368
1368
|
|
|
1369
|
-
// ──
|
|
1369
|
+
// ── autodream 的 codec ──
|
|
1370
1370
|
// 刻意写得宽:这几个方法返回的是配置 / 状态对象,字段会随版本增删。
|
|
1371
1371
|
// 用 parseSchema 逐字段硬写一遍的代价是 —— host 那边加一个字段,client 的旧
|
|
1372
1372
|
// schema 就把整条调用当「缺字段」拒掉(parseSchema 会 throw missing field),
|
|
@@ -1383,12 +1383,6 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1383
1383
|
return v;
|
|
1384
1384
|
},
|
|
1385
1385
|
};
|
|
1386
|
-
const boolCodec = {
|
|
1387
|
-
parse(v) {
|
|
1388
|
-
if (typeof v !== "boolean") throw new Error("sage-mem: expected boolean");
|
|
1389
|
-
return v;
|
|
1390
|
-
},
|
|
1391
|
-
};
|
|
1392
1386
|
|
|
1393
1387
|
const TYPERT_REMOTE = {
|
|
1394
1388
|
package: "sage-mem",
|
|
@@ -1401,7 +1395,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1401
1395
|
invocation: { kind: "direct" },
|
|
1402
1396
|
parameters: [],
|
|
1403
1397
|
result: { mode: "strict", typeSymbol: "sage-mem/types#FileList", schema: listSchema, create: () => listSchema },
|
|
1404
|
-
sourceLocation: { "file": "
|
|
1398
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
1405
1399
|
},
|
|
1406
1400
|
{
|
|
1407
1401
|
id: "sage-mem#memory/readFile",
|
|
@@ -1413,7 +1407,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1413
1407
|
{ name: "name", wire: "name", source: "json", codec: { mode: "strict", typeSymbol: "sage-mem/types#FileName", schema: strSchema, create: () => strSchema } },
|
|
1414
1408
|
],
|
|
1415
1409
|
result: { mode: "strict", typeSymbol: "sage-mem/types#FileContent", schema: readSchema, create: () => readSchema },
|
|
1416
|
-
sourceLocation: { "file": "
|
|
1410
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
1417
1411
|
},
|
|
1418
1412
|
{
|
|
1419
1413
|
id: "sage-mem#memory/writeFile",
|
|
@@ -1426,7 +1420,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1426
1420
|
{ name: "content", wire: "content", source: "json", codec: { mode: "strict", typeSymbol: "sage-mem/types#FileContent", schema: strSchema, create: () => strSchema } },
|
|
1427
1421
|
],
|
|
1428
1422
|
result: { mode: "strict", typeSymbol: "sage-mem/types#WriteResult", schema: writeSchema, create: () => writeSchema },
|
|
1429
|
-
sourceLocation: { "file": "
|
|
1423
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
1430
1424
|
},
|
|
1431
1425
|
{
|
|
1432
1426
|
id: "sage-mem#memory/deleteFile",
|
|
@@ -1438,7 +1432,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1438
1432
|
{ name: "name", wire: "name", source: "json", codec: { mode: "strict", typeSymbol: "sage-mem/types#FileName", schema: strSchema, create: () => strSchema } },
|
|
1439
1433
|
],
|
|
1440
1434
|
result: { mode: "strict", typeSymbol: "sage-mem/types#DeleteResult", schema: deleteSchema, create: () => deleteSchema },
|
|
1441
|
-
sourceLocation: { "file": "
|
|
1435
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
1442
1436
|
},
|
|
1443
1437
|
{
|
|
1444
1438
|
id: "sage-mem#starmap/listStars",
|
|
@@ -1448,7 +1442,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1448
1442
|
invocation: { kind: "direct" },
|
|
1449
1443
|
parameters: [],
|
|
1450
1444
|
result: { mode: "strict", typeSymbol: "sage-mem/types#StarmapList", schema: starmapListSchema, create: () => starmapListSchema },
|
|
1451
|
-
sourceLocation: { "file": "
|
|
1445
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
1452
1446
|
},
|
|
1453
1447
|
{
|
|
1454
1448
|
id: "sage-mem#starmap/readFile",
|
|
@@ -1460,90 +1454,142 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1460
1454
|
{ name: "name", wire: "name", source: "json", codec: { mode: "strict", typeSymbol: "sage-mem/types#FileName", schema: strSchema, create: () => strSchema } },
|
|
1461
1455
|
],
|
|
1462
1456
|
result: { mode: "strict", typeSymbol: "sage-mem/types#StarmapRead", schema: starmapReadSchema, create: () => starmapReadSchema },
|
|
1463
|
-
sourceLocation: { "file": "
|
|
1457
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
1464
1458
|
},
|
|
1465
|
-
// ──
|
|
1466
|
-
//
|
|
1467
|
-
//
|
|
1468
|
-
// 后加的
|
|
1469
|
-
// 界面上表现为「remote.
|
|
1470
|
-
// 「
|
|
1471
|
-
//
|
|
1459
|
+
// ── autodream(自动做梦)──
|
|
1460
|
+
// 踩到的坑:namespace 不会自动出现。宿主那份 remote 清单是**构建期生成的
|
|
1461
|
+
// 产物**,只有 memory / starmap 在里面;
|
|
1462
|
+
// 后加的 autodream 不在,于是 `ctx.get("remote.autodream")` 永远 undefined ——
|
|
1463
|
+
// 界面上表现为「remote.autodream 不可用」,而 宿主侧日志明确写着
|
|
1464
|
+
// 「autodream gateway mounted ok」(服务是真的挂上了,只是 client 不知道)。
|
|
1465
|
+
// 修法就是自己声明 + $mount,和 memory / starmap 一样(现在共十一条:
|
|
1466
|
+
// 七个原有方法 + listRuns / readDeclaration / rollback / listModels)。
|
|
1472
1467
|
{
|
|
1473
|
-
id: "sage-mem#
|
|
1474
|
-
service: "
|
|
1475
|
-
namespace: "
|
|
1468
|
+
id: "sage-mem#autodream/getConfig",
|
|
1469
|
+
service: "autodream",
|
|
1470
|
+
namespace: "autodream",
|
|
1476
1471
|
method: "getConfig",
|
|
1477
1472
|
invocation: { kind: "direct" },
|
|
1478
1473
|
parameters: [],
|
|
1479
|
-
result: { mode: "strict", typeSymbol: "sage-mem/types#
|
|
1480
|
-
sourceLocation: { "file": "
|
|
1474
|
+
result: { mode: "strict", typeSymbol: "sage-mem/types#AutodreamConfigResult", schema: objCodec, create: () => objCodec },
|
|
1475
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
1481
1476
|
},
|
|
1482
1477
|
{
|
|
1483
|
-
id: "sage-mem#
|
|
1484
|
-
service: "
|
|
1485
|
-
namespace: "
|
|
1478
|
+
id: "sage-mem#autodream/setConfig",
|
|
1479
|
+
service: "autodream",
|
|
1480
|
+
namespace: "autodream",
|
|
1486
1481
|
method: "setConfig",
|
|
1487
1482
|
invocation: { kind: "direct" },
|
|
1488
1483
|
parameters: [
|
|
1489
|
-
{ name: "patch", wire: "patch", source: "json", codec: { mode: "strict", typeSymbol: "sage-mem/types#
|
|
1484
|
+
{ name: "patch", wire: "patch", source: "json", codec: { mode: "strict", typeSymbol: "sage-mem/types#AutodreamPatch", schema: objCodec, create: () => objCodec } },
|
|
1490
1485
|
],
|
|
1491
|
-
result: { mode: "strict", typeSymbol: "sage-mem/types#
|
|
1492
|
-
sourceLocation: { "file": "
|
|
1486
|
+
result: { mode: "strict", typeSymbol: "sage-mem/types#AutodreamConfigResult", schema: objCodec, create: () => objCodec },
|
|
1487
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
1493
1488
|
},
|
|
1494
1489
|
{
|
|
1495
|
-
id: "sage-mem#
|
|
1496
|
-
service: "
|
|
1497
|
-
namespace: "
|
|
1490
|
+
id: "sage-mem#autodream/status",
|
|
1491
|
+
service: "autodream",
|
|
1492
|
+
namespace: "autodream",
|
|
1498
1493
|
method: "status",
|
|
1499
1494
|
invocation: { kind: "direct" },
|
|
1500
1495
|
parameters: [],
|
|
1501
|
-
result: { mode: "strict", typeSymbol: "sage-mem/types#
|
|
1502
|
-
sourceLocation: { "file": "
|
|
1496
|
+
result: { mode: "strict", typeSymbol: "sage-mem/types#AutodreamStatus", schema: objCodec, create: () => objCodec },
|
|
1497
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
1503
1498
|
},
|
|
1504
1499
|
{
|
|
1505
|
-
id: "sage-mem#
|
|
1506
|
-
service: "
|
|
1507
|
-
namespace: "
|
|
1500
|
+
id: "sage-mem#autodream/runNow",
|
|
1501
|
+
service: "autodream",
|
|
1502
|
+
namespace: "autodream",
|
|
1508
1503
|
method: "runNow",
|
|
1509
1504
|
invocation: { kind: "direct" },
|
|
1510
1505
|
parameters: [
|
|
1511
|
-
|
|
1506
|
+
// 契约:runNow({reason})。前端只负责给一个缘由字符串(落进
|
|
1507
|
+
// manifest.reason 给人看);「手动触发跳过门控」由 宿主侧决定。
|
|
1508
|
+
{ name: "opts", wire: "opts", source: "json", codec: { mode: "strict", typeSymbol: "sage-mem/types#AutodreamOpts", schema: objCodec, create: () => objCodec } },
|
|
1512
1509
|
],
|
|
1513
|
-
result: { mode: "strict", typeSymbol: "sage-mem/types#
|
|
1514
|
-
sourceLocation: { "file": "
|
|
1510
|
+
result: { mode: "strict", typeSymbol: "sage-mem/types#AutodreamRunResult", schema: objCodec, create: () => objCodec },
|
|
1511
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
1515
1512
|
},
|
|
1516
1513
|
{
|
|
1517
|
-
id: "sage-mem#
|
|
1518
|
-
service: "
|
|
1519
|
-
namespace: "
|
|
1514
|
+
id: "sage-mem#autodream/listReports",
|
|
1515
|
+
service: "autodream",
|
|
1516
|
+
namespace: "autodream",
|
|
1520
1517
|
method: "listReports",
|
|
1521
1518
|
invocation: { kind: "direct" },
|
|
1522
1519
|
parameters: [],
|
|
1523
|
-
result: { mode: "strict", typeSymbol: "sage-mem/types#
|
|
1524
|
-
sourceLocation: { "file": "
|
|
1520
|
+
result: { mode: "strict", typeSymbol: "sage-mem/types#AutodreamReportList", schema: arrCodec, create: () => arrCodec },
|
|
1521
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
1525
1522
|
},
|
|
1526
1523
|
{
|
|
1527
|
-
id: "sage-mem#
|
|
1528
|
-
service: "
|
|
1529
|
-
namespace: "
|
|
1524
|
+
id: "sage-mem#autodream/readReport",
|
|
1525
|
+
service: "autodream",
|
|
1526
|
+
namespace: "autodream",
|
|
1530
1527
|
method: "readReport",
|
|
1531
1528
|
invocation: { kind: "direct" },
|
|
1532
1529
|
parameters: [
|
|
1533
|
-
{ name: "name", wire: "name", source: "json", codec: { mode: "strict", typeSymbol: "sage-mem/types#
|
|
1530
|
+
{ name: "name", wire: "name", source: "json", codec: { mode: "strict", typeSymbol: "sage-mem/types#AutodreamReportRef", schema: strSchema, create: () => strSchema } },
|
|
1534
1531
|
],
|
|
1535
1532
|
result: { mode: "strict", typeSymbol: "sage-mem/types#FileContent", schema: objCodec, create: () => objCodec },
|
|
1536
|
-
sourceLocation: { "file": "
|
|
1533
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
1537
1534
|
},
|
|
1538
1535
|
{
|
|
1539
|
-
id: "sage-mem#
|
|
1540
|
-
service: "
|
|
1541
|
-
namespace: "
|
|
1536
|
+
id: "sage-mem#autodream/listSnapshots",
|
|
1537
|
+
service: "autodream",
|
|
1538
|
+
namespace: "autodream",
|
|
1542
1539
|
method: "listSnapshots",
|
|
1543
1540
|
invocation: { kind: "direct" },
|
|
1544
1541
|
parameters: [],
|
|
1545
|
-
result: { mode: "strict", typeSymbol: "sage-mem/types#
|
|
1546
|
-
sourceLocation: { "file": "
|
|
1542
|
+
result: { mode: "strict", typeSymbol: "sage-mem/types#AutodreamSnapshotList", schema: arrCodec, create: () => arrCodec },
|
|
1543
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
1544
|
+
},
|
|
1545
|
+
// ── 运行记录 / 整理声明 / 回滚 / 模型目录 ──
|
|
1546
|
+
// 都是「单个对象参数」形态(与 setConfig(patch) 同形),契约第二节的
|
|
1547
|
+
// {limit} / {runId} / {snapshotId, scope} 逐字对应这个对象的字段。
|
|
1548
|
+
{
|
|
1549
|
+
id: "sage-mem#autodream/listRuns",
|
|
1550
|
+
service: "autodream",
|
|
1551
|
+
namespace: "autodream",
|
|
1552
|
+
method: "listRuns",
|
|
1553
|
+
invocation: { kind: "direct" },
|
|
1554
|
+
parameters: [
|
|
1555
|
+
{ name: "opts", wire: "opts", source: "json", codec: { mode: "strict", typeSymbol: "sage-mem/types#AutodreamOpts", schema: objCodec, create: () => objCodec } },
|
|
1556
|
+
],
|
|
1557
|
+
result: { mode: "strict", typeSymbol: "sage-mem/types#AutodreamRunList", schema: arrCodec, create: () => arrCodec },
|
|
1558
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
1559
|
+
},
|
|
1560
|
+
{
|
|
1561
|
+
id: "sage-mem#autodream/readDeclaration",
|
|
1562
|
+
service: "autodream",
|
|
1563
|
+
namespace: "autodream",
|
|
1564
|
+
method: "readDeclaration",
|
|
1565
|
+
invocation: { kind: "direct" },
|
|
1566
|
+
parameters: [
|
|
1567
|
+
{ name: "opts", wire: "opts", source: "json", codec: { mode: "strict", typeSymbol: "sage-mem/types#AutodreamOpts", schema: objCodec, create: () => objCodec } },
|
|
1568
|
+
],
|
|
1569
|
+
result: { mode: "strict", typeSymbol: "sage-mem/types#AutodreamDeclaration", schema: objCodec, create: () => objCodec },
|
|
1570
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
1571
|
+
},
|
|
1572
|
+
{
|
|
1573
|
+
id: "sage-mem#autodream/rollback",
|
|
1574
|
+
service: "autodream",
|
|
1575
|
+
namespace: "autodream",
|
|
1576
|
+
method: "rollback",
|
|
1577
|
+
invocation: { kind: "direct" },
|
|
1578
|
+
parameters: [
|
|
1579
|
+
{ name: "opts", wire: "opts", source: "json", codec: { mode: "strict", typeSymbol: "sage-mem/types#AutodreamOpts", schema: objCodec, create: () => objCodec } },
|
|
1580
|
+
],
|
|
1581
|
+
result: { mode: "strict", typeSymbol: "sage-mem/types#AutodreamRollbackResult", schema: objCodec, create: () => objCodec },
|
|
1582
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
1583
|
+
},
|
|
1584
|
+
{
|
|
1585
|
+
id: "sage-mem#autodream/listModels",
|
|
1586
|
+
service: "autodream",
|
|
1587
|
+
namespace: "autodream",
|
|
1588
|
+
method: "listModels",
|
|
1589
|
+
invocation: { kind: "direct" },
|
|
1590
|
+
parameters: [],
|
|
1591
|
+
result: { mode: "strict", typeSymbol: "sage-mem/types#AutodreamModelList", schema: objCodec, create: () => objCodec },
|
|
1592
|
+
sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
|
|
1547
1593
|
},
|
|
1548
1594
|
],
|
|
1549
1595
|
};
|
|
@@ -1557,7 +1603,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1557
1603
|
".smem-muted{color:var(--dsw-alias-label-secondary);font-size:12px;}",
|
|
1558
1604
|
".smem-toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}",
|
|
1559
1605
|
// 筛选条:类型 + 自定义标签两组 chip,与搜索框是 AND 关系。
|
|
1560
|
-
//
|
|
1606
|
+
// 只消费宿主 CSS 变量,不另造配色 —— 浅色深色共用同一套语言。
|
|
1561
1607
|
".smem-filters{display:flex;align-items:center;gap:6px;flex-wrap:wrap;}",
|
|
1562
1608
|
".smem-filters-label{font-size:11.5px;color:var(--dsw-alias-label-secondary);flex:none;}",
|
|
1563
1609
|
".smem-sep{width:1px;height:15px;background:var(--dsw-alias-border-l2);flex:none;margin:0 3px;}",
|
|
@@ -1602,14 +1648,14 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1602
1648
|
'.smem-tab--on{color:var(--dsw-alias-label-primary);}',
|
|
1603
1649
|
'.smem-tab--on:after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;border-radius:2px 2px 0 0;background:var(--dsw-alias-label-primary);}',
|
|
1604
1650
|
// 高度预算压到 62vh(原 70vh):设置弹窗本身高度有限,
|
|
1605
|
-
// 70vh
|
|
1651
|
+
// 70vh 在较矮的设置弹窗视口下会把星图底部的图例和计数挤出面板之外。
|
|
1606
1652
|
".smem-starmap{display:flex;flex-direction:column;height:min(62vh,660px);min-height:400px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;overflow:hidden;}",
|
|
1607
|
-
// ──
|
|
1653
|
+
// ── 「自动做梦」面板 ──
|
|
1608
1654
|
// 融入型:全部走宿主变量,控件复用已有的 chip / input / btn 语言,不另造一套。
|
|
1609
|
-
".smem-
|
|
1610
|
-
".smem-
|
|
1611
|
-
".smem-
|
|
1612
|
-
".smem-
|
|
1655
|
+
".smem-autodream{display:flex;flex-direction:column;gap:12px;}",
|
|
1656
|
+
".smem-autodream-sec{border:1px solid var(--dsw-alias-border-l1);border-radius:10px;background:var(--dsw-alias-bg-layer-1);padding:10px 12px;display:flex;flex-direction:column;gap:9px;}",
|
|
1657
|
+
".smem-autodream-row{display:flex;align-items:center;gap:9px;flex-wrap:wrap;}",
|
|
1658
|
+
".smem-autodream-key{font-size:12px;color:var(--dsw-alias-label-secondary);flex:none;min-width:78px;}",
|
|
1613
1659
|
".smem-switch{border:1px solid var(--dsw-alias-border-l2);background:transparent;border-radius:999px;width:38px;height:21px;position:relative;cursor:pointer;flex:none;padding:0;}",
|
|
1614
1660
|
'.smem-switch::after{content:"";position:absolute;top:2px;left:2px;width:15px;height:15px;border-radius:50%;background:var(--dsw-alias-label-secondary);transition:left .15s,background .15s;}',
|
|
1615
1661
|
'.smem-switch[data-on="1"]{border-color:var(--dsw-alias-brand-primary,#4d76e6);background:var(--dsw-alias-brand-primary,#4d76e6);}',
|
|
@@ -1617,14 +1663,31 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1617
1663
|
".smem-num{width:66px;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;background:var(--dsw-alias-bg-base);color:inherit;padding:4px 8px;font-size:12px;font-family:inherit;outline:none;}",
|
|
1618
1664
|
".smem-num:focus{border-color:var(--dsw-alias-brand-primary,#4d76e6);}",
|
|
1619
1665
|
".smem-status{font-size:12px;color:var(--dsw-alias-label-secondary);}",
|
|
1620
|
-
".smem-
|
|
1621
|
-
".smem-
|
|
1666
|
+
".smem-autodream-note{font-size:11.5px;color:var(--dsw-alias-label-secondary);line-height:1.5;}",
|
|
1667
|
+
".smem-autodream-list{display:flex;flex-direction:column;gap:6px;}",
|
|
1622
1668
|
".smem-report{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:6px 9px;font-size:12px;cursor:pointer;background:transparent;color:inherit;text-align:left;font-family:inherit;}",
|
|
1623
1669
|
".smem-report:hover{border-color:var(--dsw-alias-border-l2);}",
|
|
1624
1670
|
'.smem-report[data-on="1"]{border-color:var(--dsw-alias-brand-primary,#4d76e6);}',
|
|
1625
1671
|
".smem-report-pre{max-height:320px;overflow:auto;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:10px 12px;background:var(--dsw-alias-bg-layer-2);font-size:12px;white-space:pre-wrap;overflow-wrap:anywhere;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;line-height:1.6;}",
|
|
1626
|
-
".smem-
|
|
1627
|
-
".smem-
|
|
1672
|
+
".smem-autodream-adv>summary{cursor:pointer;font-size:12px;color:var(--dsw-alias-label-secondary);}",
|
|
1673
|
+
".smem-autodream-adv>div{display:flex;flex-direction:column;gap:8px;padding-top:9px;}",
|
|
1674
|
+
// ── 回滚点区 / 整理声明区 ──
|
|
1675
|
+
// 新元素一律 .smem-ad-* 前缀,不动主题外的全局样式(契约第六节第 6 条)。
|
|
1676
|
+
".smem-ad-select{flex:1;min-width:190px;}",
|
|
1677
|
+
".smem-ad-err{color:var(--dsw-alias-state-error-primary,#ef4444);}",
|
|
1678
|
+
".smem-ad-wrap{display:flex;flex-direction:column;gap:6px;}",
|
|
1679
|
+
".smem-ad-snap{display:flex;align-items:center;gap:8px;flex-wrap:wrap;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:6px 9px;font-size:12px;}",
|
|
1680
|
+
".smem-ad-main{flex:1;min-width:140px;overflow-wrap:anywhere;}",
|
|
1681
|
+
".smem-ad-sub{color:var(--dsw-alias-label-secondary);font-size:11.5px;overflow-wrap:anywhere;}",
|
|
1682
|
+
".smem-ad-badge{display:inline-flex;align-items:center;font-size:11px;color:var(--dsw-alias-label-secondary);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;padding:0 5px;white-space:nowrap;}",
|
|
1683
|
+
".smem-ad-badge--warn{color:var(--dsw-alias-state-warning-primary,#d97706);border-color:var(--dsw-alias-state-warning-primary,#d97706);}",
|
|
1684
|
+
".smem-ad-badge--legacy{opacity:.78;}",
|
|
1685
|
+
".smem-ad-confirm{border:1px solid var(--dsw-alias-state-error-primary,#ef4444);border-radius:8px;padding:7px 9px;font-size:12px;line-height:1.55;display:flex;flex-direction:column;gap:6px;overflow-wrap:anywhere;}",
|
|
1686
|
+
".smem-ad-rb{font-size:12px;line-height:1.5;overflow-wrap:anywhere;}",
|
|
1687
|
+
".smem-ad-run{display:flex;align-items:center;gap:8px;flex-wrap:wrap;width:100%;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:6px 9px;background:transparent;color:inherit;text-align:left;font-family:inherit;font-size:12px;cursor:pointer;}",
|
|
1688
|
+
".smem-ad-run:hover{border-color:var(--dsw-alias-border-l2);}",
|
|
1689
|
+
'.smem-ad-run[data-on="1"]{border-color:var(--dsw-alias-brand-primary,#4d76e6);}',
|
|
1690
|
+
".smem-ad-md{max-height:360px;overflow:auto;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:10px 12px;background:var(--dsw-alias-bg-layer-2);font-size:12px;white-space:pre-wrap;overflow-wrap:anywhere;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;line-height:1.6;}",
|
|
1628
1691
|
].join("\n");
|
|
1629
1692
|
|
|
1630
1693
|
const TYPE_META = {
|
|
@@ -1635,7 +1698,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1635
1698
|
};
|
|
1636
1699
|
const TYPE_ORDER = ["user", "feedback", "project", "reference"];
|
|
1637
1700
|
// 筛选条上的显示名:emoji 在筛选条里太吵,只用文字;special 是星图的兜底类,
|
|
1638
|
-
// 文件列表里出现它说明 frontmatter 写了 type: special
|
|
1701
|
+
// 文件列表里出现它说明 frontmatter 写了 type: special。
|
|
1639
1702
|
const TYPE_LABEL = { user: "用户", feedback: "反馈", project: "项目", reference: "参考", special: "特殊" };
|
|
1640
1703
|
const TYPE_SORT = ["user", "feedback", "project", "reference", "special"];
|
|
1641
1704
|
|
|
@@ -1657,17 +1720,17 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1657
1720
|
|
|
1658
1721
|
// ── frontmatter 纯逻辑(顶层自包含普通函数,不碰 React state)─────
|
|
1659
1722
|
//
|
|
1660
|
-
//
|
|
1723
|
+
// 这里曾出过一次 P0 级数据丢失事故,根因全在这几行里,三条硬规矩:
|
|
1661
1724
|
// 1) 绝不「重建」frontmatter —— 就地合并,除 description / type 外每一行
|
|
1662
1725
|
// 逐字保留。旧版 buildFrontmatter() 只写 name/description/type 三个字段,
|
|
1663
1726
|
// 保存一次就把 baseline / node_type / originSessionId / updated 全抹掉
|
|
1664
1727
|
// (baseline 一丢,「每次会话必读」的记忆从此不再注入)。
|
|
1665
1728
|
// 2) 类型正则必须锚行首:` node_type: memory` 里的 `type:` 否则会被先命中,
|
|
1666
|
-
// 捕获到 memory → 不在 TYPE_ORDER 里 → 兜底成 reference
|
|
1729
|
+
// 捕获到 memory → 不在 TYPE_ORDER 里 → 兜底成 reference。
|
|
1667
1730
|
// 3) 换行必须容忍 CRLF(Windows 编辑器碰一次就是 \r\n);回写沿用原文件的
|
|
1668
1731
|
// 换行风格,从而 LF / CRLF 都能逐字节 round-trip。
|
|
1669
1732
|
|
|
1670
|
-
/** 去掉值两侧成对的引号(与
|
|
1733
|
+
/** 去掉值两侧成对的引号(与 宿主侧 parseFrontmatter 的剥法一致)。 */
|
|
1671
1734
|
function stripQuotes(v) {
|
|
1672
1735
|
const s = typeof v === "string" ? v.trim() : "";
|
|
1673
1736
|
return s.replace(/^["']|["']$/g, "").trim();
|
|
@@ -1701,7 +1764,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1701
1764
|
* 识别记忆类型。锚行首(^ + m),**不看 node_type**:
|
|
1702
1765
|
* 1) 顶层 `type: X`
|
|
1703
1766
|
* 2) metadata 块内的缩进写法 ` type: X`
|
|
1704
|
-
* 优先级与
|
|
1767
|
+
* 优先级与 宿主侧 parseFrontmatter 一致(顶层优先)。找不到返回 ""。
|
|
1705
1768
|
*/
|
|
1706
1769
|
function detectType(text) {
|
|
1707
1770
|
const fm = fmInner(text);
|
|
@@ -1713,8 +1776,8 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1713
1776
|
}
|
|
1714
1777
|
|
|
1715
1778
|
/**
|
|
1716
|
-
* 兜底:读 node_type
|
|
1717
|
-
*
|
|
1779
|
+
* 兜底:读 node_type。个别老文件没有 type 行,node_type 直接就是类型
|
|
1780
|
+
* (例如 project_example.md → project)。
|
|
1718
1781
|
* 只由调用方在 detectType 返回空时使用 —— detectType 本身绝不认 node_type。
|
|
1719
1782
|
*/
|
|
1720
1783
|
function detectNodeType(text) {
|
|
@@ -1731,7 +1794,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1731
1794
|
}
|
|
1732
1795
|
|
|
1733
1796
|
/**
|
|
1734
|
-
* 取顶层 tags 的值。三种写法都认,与
|
|
1797
|
+
* 取顶层 tags 的值。三种写法都认,与 宿主侧 parseTags 保持同一套规则:
|
|
1735
1798
|
* tags: ["a", "b"] (flow,本插件自己写出去的就是这种)
|
|
1736
1799
|
* tags:\n - a\n - b (block,手写文件常见)
|
|
1737
1800
|
* tags: a, b (松散逗号串)
|
|
@@ -1959,17 +2022,37 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1959
2022
|
}
|
|
1960
2023
|
|
|
1961
2024
|
/**
|
|
1962
|
-
*
|
|
2025
|
+
* 模型路线的编码:`<select>` 的 value ↔ {provider, model}。
|
|
1963
2026
|
*
|
|
1964
|
-
*
|
|
2027
|
+
* 用 JSON 数组而不是 "provider/model" 拼串 —— provider 名里带斜杠的情况
|
|
2028
|
+
* (比如 openrouter 的 "deepseek/deepseek-chat")会把分隔符解析弄错。
|
|
2029
|
+
* 空串代表「跟随当前会话默认模型」(值是 ['', ''])。
|
|
2030
|
+
*/
|
|
2031
|
+
function encodeRoute(provider, model) {
|
|
2032
|
+
return JSON.stringify([String(provider == null ? "" : provider), String(model == null ? "" : model)]);
|
|
2033
|
+
}
|
|
2034
|
+
function decodeRoute(v) {
|
|
2035
|
+
try {
|
|
2036
|
+
const a = JSON.parse(String(v == null ? "" : v));
|
|
2037
|
+
if (Array.isArray(a) && a.length === 2) {
|
|
2038
|
+
return { provider: String(a[0] == null ? "" : a[0]), model: String(a[1] == null ? "" : a[1]) };
|
|
2039
|
+
}
|
|
2040
|
+
} catch (_) {}
|
|
2041
|
+
return { provider: "", model: "" };
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
/**
|
|
2045
|
+
* 「自动做梦」面板 —— 让记忆自己整理一遍(引擎在 宿主侧 lib/autodream.js)。
|
|
2046
|
+
*
|
|
2047
|
+
* 数据全走 remote.autodream(宿主侧的 AutodreamGateway)。两条实现约定:
|
|
1965
2048
|
* 1. **轮询而不是等待**。「立即整理」启动后台任务后立刻返回 —— 一趟可能跑
|
|
1966
2049
|
* 几分钟,把 remote 调用挂在那儿等会撞上前端超时。进度靠每 2 秒拉一次
|
|
1967
2050
|
* status() 显示。
|
|
1968
2051
|
* 2. **不替用户做判断**。触发方式 / 改动方式 / 输入源三件事各自明说代价
|
|
1969
2052
|
* (比如「记忆 + 会话记录」会把私密对话送进模型),默认全是最保守的那一档。
|
|
1970
2053
|
*/
|
|
1971
|
-
function
|
|
1972
|
-
const remote = props.ctx && props.ctx.get ? props.ctx.get("remote.
|
|
2054
|
+
function AutodreamPanel(props) {
|
|
2055
|
+
const remote = props.ctx && props.ctx.get ? props.ctx.get("remote.autodream") : null;
|
|
1973
2056
|
const sCfg = react.useState(null); const cfg = sCfg[0], setCfg = sCfg[1];
|
|
1974
2057
|
const sSt = react.useState(null); const st = sSt[0], setSt = sSt[1];
|
|
1975
2058
|
const sErr = react.useState(null); const err = sErr[0], setErr = sErr[1];
|
|
@@ -1978,153 +2061,291 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
1978
2061
|
const sReports = react.useState([]); const reports = sReports[0], setReports = sReports[1];
|
|
1979
2062
|
const sOpen = react.useState(null); const open = sOpen[0], setOpen = sOpen[1];
|
|
1980
2063
|
const sBody = react.useState(""); const body = sBody[0], setBody = sBody[1];
|
|
1981
|
-
const sModelEdit = react.useState(false); const modelEdit = sModelEdit[0], setModelEdit = sModelEdit[1];
|
|
1982
2064
|
const sProv = react.useState(""); const prov = sProv[0], setProv = sProv[1];
|
|
1983
2065
|
const sModel = react.useState(""); const model = sModel[0], setModel = sModel[1];
|
|
2066
|
+
// ── 模型目录 / 回滚点 / 整理记录 / 整理声明 ──
|
|
2067
|
+
const sModels = react.useState(null); const models = sModels[0], setModels = sModels[1];
|
|
2068
|
+
const sSnaps = react.useState([]); const snaps = sSnaps[0], setSnaps = sSnaps[1];
|
|
2069
|
+
const sRuns = react.useState([]); const runs = sRuns[0], setRuns = sRuns[1];
|
|
2070
|
+
const sDeclOpen = react.useState(null); const declOpen = sDeclOpen[0], setDeclOpen = sDeclOpen[1];
|
|
2071
|
+
const sDeclBody = react.useState(""); const declBody = sDeclBody[0], setDeclBody = sDeclBody[1];
|
|
2072
|
+
const sConfirm = react.useState(null); const confirmSnap = sConfirm[0], setConfirmSnap = sConfirm[1];
|
|
2073
|
+
const sRbBusy = react.useState(null); const rbBusy = sRbBusy[0], setRbBusy = sRbBusy[1];
|
|
2074
|
+
const sRbMsg = react.useState(null); const rbMsg = sRbMsg[0], setRbMsg = sRbMsg[1];
|
|
2075
|
+
const sListErr = react.useState(null); const listErr = sListErr[0], setListErr = sListErr[1];
|
|
2076
|
+
const sWasRunning = react.useState(false); const wasRunning = sWasRunning[0], setWasRunning = sWasRunning[1];
|
|
2077
|
+
|
|
2078
|
+
// 派生量放在 effect 之前:下面几个 effect 的依赖数组要在渲染期就能取到值。
|
|
2079
|
+
const c = cfg || {};
|
|
2080
|
+
const running = !!(st && st.running);
|
|
2081
|
+
const last = (st && st.lastResult) || null;
|
|
2082
|
+
const route = (st && st.route) || null;
|
|
2083
|
+
const rollbackScope = c.rollbackScope === "all" ? "all" : "files";
|
|
1984
2084
|
|
|
1985
2085
|
react.useEffect(function () {
|
|
1986
|
-
if (!remote) { setErr("remote.
|
|
2086
|
+
if (!remote) { setErr("remote.autodream 不可用 —— 插件的 宿主侧可能没加载成功,看 DSH 启动日志"); return undefined; }
|
|
1987
2087
|
let alive = true;
|
|
1988
2088
|
function pull() {
|
|
1989
|
-
|
|
1990
|
-
if (!alive) return;
|
|
1991
|
-
|
|
1992
|
-
if (d) { setSt(d); if (d.config) setCfg(d.config); }
|
|
2089
|
+
callRemote("status", [], function (d) {
|
|
2090
|
+
if (!alive || !d) return;
|
|
2091
|
+
setSt(d); if (d.config) setCfg(d.config);
|
|
1993
2092
|
setErr(null);
|
|
1994
|
-
}
|
|
2093
|
+
}, function (m) { if (alive) setErr(m); });
|
|
1995
2094
|
}
|
|
1996
2095
|
pull();
|
|
1997
|
-
|
|
2096
|
+
refreshLists();
|
|
2097
|
+
loadModels();
|
|
1998
2098
|
const id = setInterval(pull, 2000);
|
|
1999
2099
|
return function () { alive = false; clearInterval(id); };
|
|
2000
2100
|
}, [remote]);
|
|
2001
2101
|
|
|
2102
|
+
// 一趟跑完(running true → false)就把回滚点 / 整理记录 / 报告刷一遍:
|
|
2103
|
+
// 刚跑完那一刻列表还是旧的,等下一次进面板才更新会让人以为没生效。
|
|
2104
|
+
react.useEffect(function () {
|
|
2105
|
+
if (wasRunning && !running) refreshLists();
|
|
2106
|
+
if (wasRunning !== running) setWasRunning(running);
|
|
2107
|
+
}, [running]);
|
|
2108
|
+
|
|
2109
|
+
// 模型行的手填框:配置里的 provider/model 变了就同步过去(保存后回填)。
|
|
2110
|
+
react.useEffect(function () {
|
|
2111
|
+
setProv(c.provider || "");
|
|
2112
|
+
setModel(c.model || "");
|
|
2113
|
+
}, [c.provider, c.model]);
|
|
2114
|
+
|
|
2115
|
+
/**
|
|
2116
|
+
* 所有 remote 调用的统一出口。
|
|
2117
|
+
*
|
|
2118
|
+
* 契约的硬约束是「每个调用都 try/catch,失败显示错误文案、不白屏」,而
|
|
2119
|
+
* 这里还有第三种失败:宿主侧是旧版本、方法根本不在 remote 对象上
|
|
2120
|
+
* (typeof !== "function")—— 那会在 `.then` 之前就抛 TypeError。
|
|
2121
|
+
* 三种都收敛到 onErr,面板只会多一行红字。
|
|
2122
|
+
*/
|
|
2123
|
+
function callRemote(name, args, onOk, onErr) {
|
|
2124
|
+
const fn = remote ? remote[name] : null;
|
|
2125
|
+
if (typeof fn !== "function") { if (onErr) onErr("宿主侧没有 " + name + " 接口(版本较旧?)"); return; }
|
|
2126
|
+
let p;
|
|
2127
|
+
try { p = fn.apply(remote, args || []); }
|
|
2128
|
+
catch (e) { if (onErr) onErr(detail(e)); return; }
|
|
2129
|
+
Promise.resolve(p).then(function (r) { if (onOk) onOk(unwrap(r)); })
|
|
2130
|
+
.catch(function (e) { if (onErr) onErr(detail(e)); });
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2002
2133
|
function patch(p) {
|
|
2003
2134
|
setErr(null); setNotice("");
|
|
2004
|
-
|
|
2005
|
-
const d = unwrap(r);
|
|
2135
|
+
callRemote("setConfig", [p], function (d) {
|
|
2006
2136
|
if (d && d.config) setCfg(d.config);
|
|
2007
|
-
}
|
|
2137
|
+
}, function (m) { setErr(m); });
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
/** 报告 / 回滚点 / 整理记录三份列表一起刷。 */
|
|
2141
|
+
function refreshLists() {
|
|
2142
|
+
callRemote("listReports", [], function (d) {
|
|
2143
|
+
setReports(Array.isArray(d) ? d : []);
|
|
2144
|
+
}, function () {});
|
|
2145
|
+
callRemote("listSnapshots", [], function (d) {
|
|
2146
|
+
setSnaps(Array.isArray(d) ? d : []);
|
|
2147
|
+
}, function (m) { setListErr(m); });
|
|
2148
|
+
callRemote("listRuns", [{ limit: 20 }], function (d) {
|
|
2149
|
+
setRuns(Array.isArray(d) ? d : []);
|
|
2150
|
+
}, function (m) { setListErr(m); });
|
|
2151
|
+
}
|
|
2152
|
+
|
|
2153
|
+
function loadModels() {
|
|
2154
|
+
callRemote("listModels", [], function (d) {
|
|
2155
|
+
setModels(d && typeof d === "object" && !Array.isArray(d) ? d : { catalogAvailable: false, routes: [], note: "" });
|
|
2156
|
+
}, function (m) {
|
|
2157
|
+
setModels({ catalogAvailable: false, routes: [], note: "模型目录不可用(" + m + ")—— 请在下面手填 provider 与 model。" });
|
|
2158
|
+
});
|
|
2008
2159
|
}
|
|
2009
2160
|
|
|
2010
2161
|
function run() {
|
|
2011
2162
|
setErr(null); setNotice(""); setBusy(true);
|
|
2012
|
-
|
|
2013
|
-
|
|
2163
|
+
// 契约:runNow({ reason })。reason 只落进 manifest 给人看;门控的豁免
|
|
2164
|
+
// 由 宿主侧负责(手动点了按钮就不该被「还没到 N 小时」挡回来)。
|
|
2165
|
+
callRemote("runNow", [{ reason: "设置页手动触发" }], function (d) {
|
|
2014
2166
|
if (d && d.ok === false) setErr(d.error || "启动失败");
|
|
2015
|
-
else setNotice("已开始整理 —— 进度每 2 秒刷新一次");
|
|
2016
|
-
|
|
2017
|
-
}
|
|
2167
|
+
else { setNotice("已开始整理 —— 进度每 2 秒刷新一次"); refreshLists(); }
|
|
2168
|
+
setBusy(false);
|
|
2169
|
+
}, function (m) { setErr(m); setBusy(false); });
|
|
2018
2170
|
}
|
|
2019
2171
|
|
|
2020
2172
|
function openReport(name) {
|
|
2021
2173
|
if (name === null) { setOpen(null); setBody(""); return; }
|
|
2022
2174
|
setOpen(name); setBody("载入中…");
|
|
2023
|
-
|
|
2024
|
-
const d = unwrap(r);
|
|
2175
|
+
callRemote("readReport", [name], function (d) {
|
|
2025
2176
|
setBody((d && d.content) || "(空)");
|
|
2026
|
-
}
|
|
2177
|
+
}, function (m) { setBody("读取失败:" + m); });
|
|
2027
2178
|
}
|
|
2028
2179
|
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2180
|
+
/** 整理声明:点开才拉,拉回来的是 Markdown 原文,直接用 pre 呈现。 */
|
|
2181
|
+
function openDecl(runId) {
|
|
2182
|
+
if (declOpen === runId) { setDeclOpen(null); setDeclBody(""); return; }
|
|
2183
|
+
setDeclOpen(runId); setDeclBody("载入中…");
|
|
2184
|
+
callRemote("readDeclaration", [{ runId: runId }], function (d) {
|
|
2185
|
+
setDeclBody((d && d.markdown) || "(这一趟没有留下声明正文)");
|
|
2186
|
+
}, function (m) { setDeclBody("读取失败:" + m); });
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
/**
|
|
2190
|
+
* 回滚。二次确认在 JSX 里(点了「回滚」先展开确认条),这里只负责调用。
|
|
2191
|
+
* 结果就地回显 —— 恢复几个、移走几个、保护快照 id,全都写在同一行里。
|
|
2192
|
+
*/
|
|
2193
|
+
function doRollback(sp) {
|
|
2194
|
+
const scope = rollbackScope;
|
|
2195
|
+
setErr(null); setNotice(""); setRbMsg(null); setRbBusy(sp.name);
|
|
2196
|
+
callRemote("rollback", [{ snapshotId: sp.name, scope: scope }], function (d) {
|
|
2197
|
+
const x = d || {};
|
|
2198
|
+
if (x.ok === false) {
|
|
2199
|
+
setRbMsg({ bad: true, text: "回滚失败:" + (x.error || "未知原因") });
|
|
2200
|
+
} else {
|
|
2201
|
+
setRbMsg({ bad: false, text: "已回滚到 " + String(sp.atHuman || "") + ":恢复 " +
|
|
2202
|
+
(x.restored == null ? "?" : x.restored) + " 个文件,移走 " + (x.parked == null ? "?" : x.parked) + " 个" +
|
|
2203
|
+
// skipped = 想动但没动的(archive/ 已有同名、或回滚点里没那一版)。
|
|
2204
|
+
// 不显示它等于「部分成功」被说成「成功」——回滚这种事不能含糊。
|
|
2205
|
+
(x.skipped ? ",跳过 " + x.skipped + " 个(详见回滚报告)" : "") +
|
|
2206
|
+
(x.protection ? " · 保护快照 " + x.protection : "") + (x.report ? " · 报告 " + x.report : "") });
|
|
2207
|
+
setConfirmSnap(null);
|
|
2208
|
+
}
|
|
2209
|
+
setRbBusy(null);
|
|
2210
|
+
refreshLists();
|
|
2211
|
+
}, function (m) { setRbMsg({ bad: true, text: "回滚失败:" + m }); setRbBusy(null); });
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
// 实际生效路线(契约:route 可能为 null;source==='none' 时 error 里是原因)。
|
|
2215
|
+
const routeBad = !route || route.source === "none" || !route.provider || !route.model;
|
|
2216
|
+
const routeInfo = routeBad
|
|
2217
|
+
? ("实际生效路线:拿不到 —— " + ((route && route.error) || "宿主没能解析出 provider / model(配置留空且取不到会话默认模型)"))
|
|
2218
|
+
: ("实际生效路线:" + route.provider + " / " + route.model + (route.fromDefault ? "(跟随默认)" : "(配置指定)"));
|
|
2219
|
+
|
|
2220
|
+
// 模型 <select> 的取值:''=跟随默认;否则是 "provider::model" 的 JSON 编码。
|
|
2221
|
+
// 配置里指定的路线万一下架了(不在目录里),也要让它显示出来 —— 否则
|
|
2222
|
+
// 下拉框会悄悄跳到「跟随默认」,与下面那行「实际生效路线」自相矛盾。
|
|
2223
|
+
const modelRoutes = (models && Array.isArray(models.routes)) ? models.routes : [];
|
|
2224
|
+
const modelValue = (c.provider && c.model) ? encodeRoute(c.provider, c.model) : "";
|
|
2225
|
+
const modelValueInCatalog = modelValue === "" || modelRoutes.some(function (r) {
|
|
2226
|
+
return encodeRoute(r.provider, r.model) === modelValue;
|
|
2227
|
+
});
|
|
2032
2228
|
|
|
2033
|
-
return h("div", { className: "smem-
|
|
2034
|
-
h("div", { className: "smem-
|
|
2035
|
-
h("div", { className: "smem-
|
|
2229
|
+
return h("div", { className: "smem-autodream" }, [
|
|
2230
|
+
h("div", { className: "smem-autodream-sec", key: "top" }, [
|
|
2231
|
+
h("div", { className: "smem-autodream-row", key: "r" }, [
|
|
2036
2232
|
h("button", {
|
|
2037
2233
|
type: "button", key: "sw", className: "smem-switch",
|
|
2038
2234
|
"data-on": c.enabled ? "1" : "0",
|
|
2039
2235
|
title: c.enabled ? "点击停用" : "点击启用",
|
|
2040
|
-
"aria-label": "
|
|
2236
|
+
"aria-label": "启用或停用自动做梦",
|
|
2041
2237
|
onClick: function () { patch({ enabled: !c.enabled }); },
|
|
2042
2238
|
}),
|
|
2043
|
-
h("span", { key: "t", style: { fontWeight: "600" } }, "
|
|
2239
|
+
h("span", { key: "t", style: { fontWeight: "600" } }, "自动做梦"),
|
|
2044
2240
|
h("span", { className: "smem-status", key: "s" },
|
|
2045
2241
|
running ? ("运行中 · " + String((st && st.phase) || "准备中")) : (c.enabled ? "已启用 · 空闲" : "未启用")),
|
|
2046
2242
|
]),
|
|
2047
|
-
h("div", { className: "smem-
|
|
2243
|
+
h("div", { className: "smem-autodream-note", key: "n" },
|
|
2048
2244
|
"把记忆目录通读一遍:合并重复的、删掉被推翻的、修索引与断链、把相对日期换成绝对日期。"),
|
|
2049
2245
|
]),
|
|
2050
|
-
h("div", { className: "smem-
|
|
2051
|
-
h("div", { className: "smem-
|
|
2052
|
-
h("span", { className: "smem-
|
|
2246
|
+
h("div", { className: "smem-autodream-sec", key: "mode" }, [
|
|
2247
|
+
h("div", { className: "smem-autodream-row", key: "a" }, [
|
|
2248
|
+
h("span", { className: "smem-autodream-key", key: "k" }, "触发"),
|
|
2053
2249
|
h(Seg, {
|
|
2054
2250
|
key: "v", value: c.trigger,
|
|
2055
2251
|
options: [{ value: "manual", label: "只手动" }, { value: "auto", label: "满足条件自动跑" }],
|
|
2056
2252
|
onChange: function (v) { patch({ trigger: v }); },
|
|
2057
2253
|
}),
|
|
2058
2254
|
]),
|
|
2059
|
-
h("div", { className: "smem-
|
|
2060
|
-
h("span", { className: "smem-
|
|
2255
|
+
h("div", { className: "smem-autodream-row", key: "b" }, [
|
|
2256
|
+
h("span", { className: "smem-autodream-key", key: "k" }, "改动方式"),
|
|
2061
2257
|
h(Seg, {
|
|
2062
2258
|
key: "v", value: c.apply ? "apply" : "report",
|
|
2063
2259
|
options: [{ value: "report", label: "只出报告" }, { value: "apply", label: "直接改写(先快照)" }],
|
|
2064
2260
|
onChange: function (v) { patch({ apply: v === "apply" }); },
|
|
2065
2261
|
}),
|
|
2066
2262
|
]),
|
|
2067
|
-
h("div", { className: "smem-
|
|
2068
|
-
h("span", { className: "smem-
|
|
2263
|
+
h("div", { className: "smem-autodream-row", key: "c" }, [
|
|
2264
|
+
h("span", { className: "smem-autodream-key", key: "k" }, "输入源"),
|
|
2069
2265
|
h(Seg, {
|
|
2070
2266
|
key: "v", value: c.source,
|
|
2071
2267
|
options: [{ value: "memory", label: "仅记忆目录" }, { value: "memory+sessions", label: "记忆 + 会话记录" }],
|
|
2072
2268
|
onChange: function (v) { patch({ source: v }); },
|
|
2073
2269
|
}),
|
|
2074
2270
|
]),
|
|
2075
|
-
h("div", { className: "smem-
|
|
2271
|
+
h("div", { className: "smem-autodream-note", key: "w" },
|
|
2076
2272
|
c.source === "memory+sessions"
|
|
2077
2273
|
? "会解压会话记录做定向搜索 —— 私密对话会进入模型上下文,token 成本也更高。"
|
|
2078
2274
|
: "只看记忆文件本身,不碰会话记录。"),
|
|
2079
|
-
h("div", { className: "smem-
|
|
2275
|
+
h("div", { className: "smem-autodream-note", key: "w2" },
|
|
2080
2276
|
c.apply
|
|
2081
|
-
? "改写前会自动把整个记忆目录快照一份(memory 上一层 .sage-mem/snapshots/),改坏可回退。"
|
|
2277
|
+
? "改写前会自动把整个记忆目录快照一份(memory 上一层 .sage-mem/autodream/snapshots/),改坏可回退。"
|
|
2082
2278
|
: "只读模式:这一趟连写工具都不会挂给模型,所以它不可能改到任何文件。"),
|
|
2083
2279
|
]),
|
|
2084
|
-
h("details", { className: "smem-
|
|
2280
|
+
h("details", { className: "smem-autodream-adv", key: "adv" }, [
|
|
2085
2281
|
h("summary", { key: "s" }, "高级设置"),
|
|
2086
2282
|
h("div", { key: "d" }, [
|
|
2087
|
-
c.trigger === "auto" ? h("div", { className: "smem-
|
|
2088
|
-
h("span", { className: "smem-
|
|
2283
|
+
c.trigger === "auto" ? h("div", { className: "smem-autodream-row", key: "gate" }, [
|
|
2284
|
+
h("span", { className: "smem-autodream-key", key: "k" }, "自动触发"),
|
|
2089
2285
|
h("span", { className: "smem-status", key: "a" }, "距上次 ≥"),
|
|
2090
2286
|
h("input", { className: "smem-num", key: "h", type: "number", min: "1", max: "720", value: c.minHours, onChange: function (e) { patch({ minHours: Number(e.target.value) }); } }),
|
|
2091
2287
|
h("span", { className: "smem-status", key: "b" }, "小时,且期间 ≥"),
|
|
2092
2288
|
h("input", { className: "smem-num", key: "m", type: "number", min: "1", max: "200", value: c.minSessions, onChange: function (e) { patch({ minSessions: Number(e.target.value) }); } }),
|
|
2093
2289
|
h("span", { className: "smem-status", key: "c" }, "个会话有更新"),
|
|
2094
2290
|
]) : null,
|
|
2095
|
-
h("div", { className: "smem-
|
|
2096
|
-
h("span", { className: "smem-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2291
|
+
h("div", { className: "smem-autodream-row", key: "model" }, [
|
|
2292
|
+
h("span", { className: "smem-autodream-key", key: "k" }, "模型"),
|
|
2293
|
+
// 有可枚举的模型目录就给 <select>(首项 = 跟随会话默认,值 "":"");
|
|
2294
|
+
// 目录不可用就退化成两个文本框(契约第六节第 2 条)。
|
|
2295
|
+
(models && models.catalogAvailable)
|
|
2296
|
+
? h("select", {
|
|
2297
|
+
className: "smem-input smem-ad-select", key: "sel",
|
|
2298
|
+
value: modelValue,
|
|
2299
|
+
onChange: function (e) {
|
|
2300
|
+
const v = e.target.value;
|
|
2301
|
+
if (!v) { patch({ provider: "", model: "" }); return; }
|
|
2302
|
+
const r = decodeRoute(v);
|
|
2303
|
+
patch({ provider: r.provider, model: r.model });
|
|
2304
|
+
},
|
|
2305
|
+
}, [h("option", { key: "__def", value: "" },
|
|
2306
|
+
"跟随当前会话默认模型" + ((models.defaultRoute && models.defaultRoute.provider && models.defaultRoute.model)
|
|
2307
|
+
? ("(" + String(models.defaultRoute.provider) + " / " + String(models.defaultRoute.model) + ")")
|
|
2308
|
+
: ""),
|
|
2309
|
+
)].concat(
|
|
2310
|
+
modelValueInCatalog ? [] : [h("option", { key: "__cur", value: modelValue }, String(c.provider) + " / " + String(c.model) + "(配置里指定,不在目录中)")],
|
|
2311
|
+
modelRoutes.map(function (r) {
|
|
2312
|
+
return h("option", { key: String(r.provider) + "/" + String(r.model), value: encodeRoute(r.provider, r.model) },
|
|
2313
|
+
r.label || (String(r.provider) + " / " + String(r.model)));
|
|
2314
|
+
}),
|
|
2315
|
+
))
|
|
2316
|
+
: models
|
|
2317
|
+
? [
|
|
2318
|
+
h("input", { className: "smem-input", key: "p", style: { flex: "1", minWidth: "110px" }, value: prov, placeholder: "provider(留空=跟随默认)", onChange: function (e) { setProv(e.target.value); } }),
|
|
2319
|
+
h("input", { className: "smem-input", key: "m", style: { flex: "1", minWidth: "110px" }, value: model, placeholder: "model(留空=跟随默认)", onChange: function (e) { setModel(e.target.value); } }),
|
|
2320
|
+
h("button", { type: "button", className: "smem-btn smem-btn-primary", key: "ok", onClick: function () { patch({ provider: prov, model: model }); setNotice("模型已保存"); } }, "保存"),
|
|
2321
|
+
]
|
|
2322
|
+
: [
|
|
2323
|
+
h("span", { className: "smem-status", key: "load" }, "模型目录载入中…"),
|
|
2324
|
+
h("button", { type: "button", className: "smem-btn", key: "man", onClick: function () { setModels({ catalogAvailable: false, routes: [], note: "" }); } }, "手填"),
|
|
2325
|
+
],
|
|
2112
2326
|
]),
|
|
2113
|
-
h("div", {
|
|
2114
|
-
|
|
2327
|
+
h("div", {
|
|
2328
|
+
className: "smem-autodream-note" + (routeBad ? " smem-ad-err" : ""),
|
|
2329
|
+
key: "route",
|
|
2330
|
+
}, (routeBad ? "✗ " : "✓ ") + routeInfo),
|
|
2331
|
+
models && models.catalogAvailable === false && models.note
|
|
2332
|
+
? h("div", { className: "smem-autodream-note", key: "mnote" }, String(models.note))
|
|
2333
|
+
: null,
|
|
2334
|
+
h("div", { className: "smem-autodream-row", key: "steps" }, [
|
|
2335
|
+
h("span", { className: "smem-autodream-key", key: "k" }, "最多轮数"),
|
|
2115
2336
|
h("input", { className: "smem-num", key: "v", type: "number", min: "1", max: "80", value: c.maxSteps, onChange: function (e) { patch({ maxSteps: Number(e.target.value) }); } }),
|
|
2116
2337
|
h("span", { className: "smem-status", key: "s" }, "一轮 = 一次模型调用 + 它要的工具调用"),
|
|
2117
2338
|
]),
|
|
2118
|
-
h("div", { className: "smem-
|
|
2119
|
-
h("span", { className: "smem-
|
|
2339
|
+
h("div", { className: "smem-autodream-row", key: "keep" }, [
|
|
2340
|
+
h("span", { className: "smem-autodream-key", key: "k" }, "保留快照"),
|
|
2120
2341
|
h("input", { className: "smem-num", key: "v", type: "number", min: "1", max: "50", value: c.maxSnapshotKeep, onChange: function (e) { patch({ maxSnapshotKeep: Number(e.target.value) }); } }),
|
|
2121
2342
|
h("span", { className: "smem-status", key: "s" }, "份"),
|
|
2122
2343
|
]),
|
|
2123
2344
|
h("div", { className: "smem-status", key: "paths" }, "配置与状态:" + ((st && st.paths && st.paths.configPath) || "—")),
|
|
2124
2345
|
]),
|
|
2125
2346
|
]),
|
|
2126
|
-
h("div", { className: "smem-
|
|
2127
|
-
h("div", { className: "smem-
|
|
2347
|
+
h("div", { className: "smem-autodream-sec", key: "run" }, [
|
|
2348
|
+
h("div", { className: "smem-autodream-row", key: "r" }, [
|
|
2128
2349
|
h("button", {
|
|
2129
2350
|
type: "button", className: "smem-btn smem-btn-primary", key: "go",
|
|
2130
2351
|
disabled: busy || running || !remote,
|
|
@@ -2136,7 +2357,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2136
2357
|
: (st && st.hoursSince != null ? ("距上次整理 " + st.hoursSince.toFixed(1) + " 小时") : "从未整理过")),
|
|
2137
2358
|
]),
|
|
2138
2359
|
running && st && st.steps && st.steps.length
|
|
2139
|
-
? h("div", { className: "smem-
|
|
2360
|
+
? h("div", { className: "smem-autodream-note", key: "prog" }, st.steps.map(function (x) {
|
|
2140
2361
|
return "第 " + x.step + " 轮:" + (x.tools.length ? x.tools.join("、") : "结束");
|
|
2141
2362
|
}).join(" · "))
|
|
2142
2363
|
: null,
|
|
@@ -2150,22 +2371,119 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2150
2371
|
(last.report ? " · 报告 " + last.report : ""))
|
|
2151
2372
|
: null,
|
|
2152
2373
|
]),
|
|
2153
|
-
|
|
2154
|
-
|
|
2374
|
+
// ── 回滚点(新)──────────────────────────────────────────────
|
|
2375
|
+
// 只改这一个文件、只用既有 h() 写法;数据全走 remote.autodream。
|
|
2376
|
+
h("div", { className: "smem-autodream-sec", key: "snap" }, [
|
|
2377
|
+
h("div", { className: "smem-autodream-row", key: "h" }, [
|
|
2378
|
+
h("span", { key: "t", style: { fontWeight: "600", fontSize: "12.5px" } }, "回滚点"),
|
|
2379
|
+
h("span", { className: "smem-status", key: "c" }, String(snaps.length) + " 个"),
|
|
2380
|
+
h("button", { type: "button", className: "smem-btn", key: "rf", onClick: refreshLists }, "刷新"),
|
|
2381
|
+
]),
|
|
2382
|
+
h("div", { className: "smem-autodream-row", key: "scope" }, [
|
|
2383
|
+
h("span", { className: "smem-autodream-key", key: "k" }, "回滚范围"),
|
|
2384
|
+
h(Seg, {
|
|
2385
|
+
key: "v", value: rollbackScope,
|
|
2386
|
+
options: [{ value: "files", label: "只恢复本次动过的文件" }, { value: "all", label: "整目录回到该时点" }],
|
|
2387
|
+
onChange: function (v) { patch({ rollbackScope: v }); },
|
|
2388
|
+
}),
|
|
2389
|
+
]),
|
|
2390
|
+
h("div", { className: "smem-autodream-note", key: "n" },
|
|
2391
|
+
"回滚前会自动把整个记忆目录再存一份保护快照 —— 所以回滚本身也能再退回来。多出来的文件只移进 archive/,不删除。"),
|
|
2392
|
+
snaps.length === 0
|
|
2393
|
+
? h("div", { className: "smem-status", key: "e" }, "还没有回滚点 —— 用「直接改写」跑过一次就有了。")
|
|
2394
|
+
: h("div", { className: "smem-autodream-list", key: "l" }, snaps.slice(0, 15).map(function (sp) {
|
|
2395
|
+
const label = sp.legacy ? "旧版快照" : (sp.runId ? ("运行 " + String(sp.runId)) : "回滚保护");
|
|
2396
|
+
return h("div", { className: "smem-ad-wrap", key: String(sp.name) }, [
|
|
2397
|
+
h("div", { className: "smem-ad-snap", key: "row" }, [
|
|
2398
|
+
h("div", { className: "smem-ad-main", key: "m" }, [
|
|
2399
|
+
h("div", { key: "l1" }, String(sp.atHuman || "") + " · " + (sp.files == null ? "?" : sp.files) + " 个文件"),
|
|
2400
|
+
h("div", { className: "smem-ad-sub", key: "l2" }, label + " · " + String(sp.name || "")),
|
|
2401
|
+
]),
|
|
2402
|
+
sp.legacy ? h("span", { className: "smem-ad-badge smem-ad-badge--legacy", key: "lg" }, "旧版") : null,
|
|
2403
|
+
confirmSnap === sp.name
|
|
2404
|
+
? null
|
|
2405
|
+
: h("button", {
|
|
2406
|
+
type: "button", className: "smem-btn", key: "go",
|
|
2407
|
+
disabled: rbBusy !== null,
|
|
2408
|
+
onClick: function () { setRbMsg(null); setConfirmSnap(sp.name); },
|
|
2409
|
+
}, "回滚"),
|
|
2410
|
+
]),
|
|
2411
|
+
confirmSnap === sp.name
|
|
2412
|
+
? h("div", { className: "smem-ad-confirm", key: "cf" }, [
|
|
2413
|
+
h("div", { key: "t", style: { fontWeight: "600" } }, "确认回滚到 " + String(sp.atHuman || "") + "?"),
|
|
2414
|
+
h("div", { key: "d" }, "范围:" + (rollbackScope === "all"
|
|
2415
|
+
? "整目录回到该时点 —— 快照里没有、当前目录里有的文件会被移进 archive/(不删除)"
|
|
2416
|
+
: "只恢复这次运行动过的文件 —— 该次新建的移进 archive/,该次归档的移回顶层") +
|
|
2417
|
+
"。回滚前会先存一份保护快照,所以这一步本身也能退。"),
|
|
2418
|
+
h("div", { className: "smem-autodream-row", key: "acts" }, [
|
|
2419
|
+
h("button", {
|
|
2420
|
+
type: "button", className: "smem-btn smem-btn-danger", key: "yes",
|
|
2421
|
+
disabled: rbBusy === sp.name,
|
|
2422
|
+
onClick: function () { doRollback(sp); },
|
|
2423
|
+
}, rbBusy === sp.name ? "回滚中…" : "确认回滚"),
|
|
2424
|
+
h("button", { type: "button", className: "smem-btn", key: "no", onClick: function () { setConfirmSnap(null); } }, "取消"),
|
|
2425
|
+
]),
|
|
2426
|
+
])
|
|
2427
|
+
: null,
|
|
2428
|
+
]);
|
|
2429
|
+
})),
|
|
2430
|
+
rbMsg ? h("div", { className: "smem-ad-rb " + (rbMsg.bad ? "smem-ad-err" : "smem-ok"), key: "rb" }, (rbMsg.bad ? "⚠ " : "✓ ") + rbMsg.text) : null,
|
|
2431
|
+
]),
|
|
2432
|
+
// ── 整理声明(新)──────────────────────────────────────────
|
|
2433
|
+
h("div", { className: "smem-autodream-sec", key: "runs" }, [
|
|
2434
|
+
h("div", { className: "smem-autodream-row", key: "h" }, [
|
|
2435
|
+
h("span", { key: "t", style: { fontWeight: "600", fontSize: "12.5px" } }, "整理记录"),
|
|
2436
|
+
h("span", { className: "smem-status", key: "c" }, String(runs.length) + " 条"),
|
|
2437
|
+
h("button", { type: "button", className: "smem-btn", key: "rf", onClick: refreshLists }, "刷新"),
|
|
2438
|
+
]),
|
|
2439
|
+
h("div", { className: "smem-autodream-note", key: "n" },
|
|
2440
|
+
"每一趟都留一份整理声明:改了什么、为什么改、哪些想法被拒了。点一条看全文。"),
|
|
2441
|
+
runs.length === 0
|
|
2442
|
+
? h("div", { className: "smem-status", key: "e" }, "还没有整理记录 —— 跑一次就有了。")
|
|
2443
|
+
: h("div", { className: "smem-autodream-list", key: "l" }, runs.slice(0, 15).map(function (rn) {
|
|
2444
|
+
return h("div", { className: "smem-ad-wrap", key: String(rn.runId) }, [
|
|
2445
|
+
h("button", {
|
|
2446
|
+
type: "button", className: "smem-ad-run",
|
|
2447
|
+
"data-on": declOpen === rn.runId ? "1" : "0",
|
|
2448
|
+
onClick: function () { openDecl(rn.runId); },
|
|
2449
|
+
}, [
|
|
2450
|
+
h("span", { key: "t" }, String(rn.atHuman || "")),
|
|
2451
|
+
h("span", { className: "smem-ad-badge", key: "m" }, rn.mode === "apply" ? "直接改写" : "只出报告"),
|
|
2452
|
+
h("span", { key: "c" }, "改 " + (rn.changeCount == null ? "?" : rn.changeCount) + " 条"),
|
|
2453
|
+
rn.report ? h("span", { className: "smem-ad-sub", key: "r" }, "报告 " + String(rn.report)) : null,
|
|
2454
|
+
rn.rolledBackAt
|
|
2455
|
+
? h("span", { className: "smem-ad-badge smem-ad-badge--warn", key: "rb" },
|
|
2456
|
+
"已回滚" + (rn.rolledBackAtHuman ? (" · " + String(rn.rolledBackAtHuman)) : ""))
|
|
2457
|
+
: null,
|
|
2458
|
+
h("span", { className: "smem-ad-sub", key: "x" }, declOpen === rn.runId ? "收起" : "看声明"),
|
|
2459
|
+
]),
|
|
2460
|
+
declOpen === rn.runId
|
|
2461
|
+
? h("pre", { className: "smem-ad-md", key: "body" }, declBody)
|
|
2462
|
+
: null,
|
|
2463
|
+
]);
|
|
2464
|
+
})),
|
|
2465
|
+
]),
|
|
2466
|
+
h("div", { className: "smem-autodream-sec", key: "rep" }, [
|
|
2467
|
+
h("div", { className: "smem-autodream-row", key: "h" }, [
|
|
2155
2468
|
h("span", { key: "t", style: { fontWeight: "600", fontSize: "12.5px" } }, "历史报告"),
|
|
2156
2469
|
h("span", { className: "smem-status", key: "c" }, String(reports.length) + " 份"),
|
|
2157
2470
|
]),
|
|
2158
2471
|
reports.length === 0
|
|
2159
|
-
? h("div", { className: "smem-status", key: "e" }, "还没有报告 —— 跑一次就有了。报告写在 memory/
|
|
2160
|
-
: h("div", { className: "smem-
|
|
2472
|
+
? h("div", { className: "smem-status", key: "e" }, "还没有报告 —— 跑一次就有了。报告写在 memory/autodream/ 下,不会混进记忆列表。")
|
|
2473
|
+
: h("div", { className: "smem-autodream-list", key: "l" }, reports.slice(0, 12).map(function (r) {
|
|
2161
2474
|
return h("button", {
|
|
2162
2475
|
type: "button", key: r.name, className: "smem-report",
|
|
2163
2476
|
"data-on": open === r.name ? "1" : "0",
|
|
2164
2477
|
onClick: function () { openReport(open === r.name ? null : r.name); },
|
|
2165
|
-
},
|
|
2478
|
+
}, [
|
|
2479
|
+
h("span", { key: "t" }, String(r.atHuman || "") + " · " + String(r.name) + " · " + fmtSize(r.bytes)),
|
|
2480
|
+
r.legacy ? h("span", { className: "smem-ad-badge smem-ad-badge--legacy", key: "lg", style: { marginLeft: "6px" } }, "旧版") : null,
|
|
2481
|
+
h("span", { className: "smem-ad-sub", key: "x", style: { marginLeft: "6px" } }, open === r.name ? "收起" : "查看"),
|
|
2482
|
+
]);
|
|
2166
2483
|
})),
|
|
2167
2484
|
open && body ? h("pre", { className: "smem-report-pre", key: "body" }, body) : null,
|
|
2168
2485
|
]),
|
|
2486
|
+
listErr && !err ? h("div", { className: "smem-err", key: "lerr" }, "⚠ " + listErr) : null,
|
|
2169
2487
|
err ? h("div", { className: "smem-err", key: "err" }, "⚠ " + err) : null,
|
|
2170
2488
|
notice && !err ? h("div", { className: "smem-ok", key: "ok" }, "✓ " + notice) : null,
|
|
2171
2489
|
]);
|
|
@@ -2387,7 +2705,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2387
2705
|
h("div", { className: "smem-tabs", key: "tabs" }, [
|
|
2388
2706
|
h("button", { type: "button", className: "smem-tab" + (tab === "files" ? " smem-tab--on" : ""), key: "f", onClick: function () { setTab("files"); } }, "文件列表"),
|
|
2389
2707
|
h("button", { type: "button", className: "smem-tab" + (tab === "star" ? " smem-tab--on" : ""), key: "s", onClick: function () { setTab("star"); } }, "记忆星图"),
|
|
2390
|
-
h("button", { type: "button", className: "smem-tab" + (tab === "
|
|
2708
|
+
h("button", { type: "button", className: "smem-tab" + (tab === "autodream" ? " smem-tab--on" : ""), key: "d", onClick: function () { setTab("autodream"); } }, "自动做梦"),
|
|
2391
2709
|
]),
|
|
2392
2710
|
h("div", { className: "smem-head", key: "head" }, [
|
|
2393
2711
|
h("span", { className: "smem-title", key: "t" }, "记忆文件(sage-mem)"),
|
|
@@ -2398,8 +2716,8 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2398
2716
|
: "共 " + String(items.length) + " 个文件"),
|
|
2399
2717
|
]),
|
|
2400
2718
|
// 搜索 / 刷新 / 添加 / 筛选都只属于「文件列表」这个视图。
|
|
2401
|
-
// 放在 tab
|
|
2402
|
-
//
|
|
2719
|
+
// 放在 tab 分支外面,会让星图和自动做梦页也顶着一排用不上的控件
|
|
2720
|
+
// (走查时发现:「+ 添加记忆」出现在星图页上)。
|
|
2403
2721
|
tab === "files" ? h("div", { className: "smem-toolbar", key: "bar" }, [
|
|
2404
2722
|
h("input", { className: "smem-search", key: "q", value: query, placeholder: "搜索文件名 / 描述 / 类型 / 标签…", onChange: function (e) { setQuery(e.target.value); } }),
|
|
2405
2723
|
h("button", { type: "button", className: "smem-btn", key: "refresh", disabled: busy || loading, onClick: load }, "刷新"),
|
|
@@ -2450,11 +2768,11 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2450
2768
|
})),
|
|
2451
2769
|
]),
|
|
2452
2770
|
h("label", { className: "smem-label", key: "ln" }, "文件名(.md,留空自动 " + formType + "_note.md)"),
|
|
2453
|
-
h("input", { className: "smem-input", key: "tn", value: formName, onChange: function (e) { setFormName(e.target.value); }, placeholder: "例如
|
|
2771
|
+
h("input", { className: "smem-input", key: "tn", value: formName, onChange: function (e) { setFormName(e.target.value); }, placeholder: "例如 project_example.md" }),
|
|
2454
2772
|
h("label", { className: "smem-label", key: "ld" }, "描述(写进 frontmatter,检索与列表都靠它)"),
|
|
2455
2773
|
h("input", { className: "smem-input", key: "td", value: formDesc, onChange: function (e) { setFormDesc(e.target.value); }, placeholder: "一句话说清这条记忆是什么" }),
|
|
2456
2774
|
h("label", { className: "smem-label", key: "lt" }, "自定义标签(可选,逗号分隔;会写进 frontmatter 的 tags,列表页可按它筛)"),
|
|
2457
|
-
h("input", { className: "smem-input", key: "tt", value: formTags, onChange: function (e) { setFormTags(e.target.value); }, placeholder: "例如
|
|
2775
|
+
h("input", { className: "smem-input", key: "tt", value: formTags, onChange: function (e) { setFormTags(e.target.value); }, placeholder: "例如 部署, 笔记, dsh" }),
|
|
2458
2776
|
h("label", { className: "smem-label", key: "lb" }, "正文(可选,frontmatter 自动生成)"),
|
|
2459
2777
|
h("textarea", { className: "smem-textarea", key: "tb", rows: 6, value: formBody, onChange: function (e) { setFormBody(e.target.value); }, placeholder: "要长期记住的细节" }),
|
|
2460
2778
|
h("div", { className: "smem-row", key: "btns" }, [
|
|
@@ -2463,8 +2781,8 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2463
2781
|
]),
|
|
2464
2782
|
])
|
|
2465
2783
|
: null,
|
|
2466
|
-
tab === "
|
|
2467
|
-
? h(
|
|
2784
|
+
tab === "autodream"
|
|
2785
|
+
? h(AutodreamPanel, { key: "autodream", ctx: props.ctx })
|
|
2468
2786
|
: tab === "star"
|
|
2469
2787
|
? h("div", { className: "smem-starmap", key: "starmap" },
|
|
2470
2788
|
h(StarmapRuntime.StarMap, { ctx: props.ctx }))
|
|
@@ -2499,7 +2817,7 @@ const StarmapRuntime = (function (require, _react) {
|
|
|
2499
2817
|
|
|
2500
2818
|
/**
|
|
2501
2819
|
* Client 插件:$mount strict remote contribution(第三方 remote 不在
|
|
2502
|
-
*
|
|
2820
|
+
* 宿主的固定 remote 清单里,必须自己挂),再注册设置页签。
|
|
2503
2821
|
*/
|
|
2504
2822
|
async function apply(ctx) {
|
|
2505
2823
|
await ctx.remote.$mount(TYPERT_REMOTE);
|