@aiyiran/myclaw 1.1.88 → 1.1.89

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.
@@ -2355,9 +2355,8 @@
2355
2355
 
2356
2356
  var deployBtn = document.createElement('button');
2357
2357
  deployBtn.textContent = '⬇创建 -> 训练场';
2358
- deployBtn.style.cssText = _btnMuted;
2359
- deployBtn.onmouseenter = function () { deployBtn.style.background = 'rgba(167,139,250,0.22)'; };
2360
- deployBtn.onmouseleave = function () { deployBtn.style.background = 'rgba(167,139,250,0.12)'; };
2358
+ deployBtn.disabled = true;
2359
+ deployBtn.style.cssText = _btnBase + 'background:rgba(255,255,255,0.05);border:1px solid rgba(255,255,255,0.1);color:rgba(205,214,244,0.3);cursor:not-allowed;';
2361
2360
 
2362
2361
  var copyLocalBtn = document.createElement('button');
2363
2362
  copyLocalBtn.textContent = '⬇创建 -> 新伙伴';
@@ -2382,9 +2381,9 @@
2382
2381
  var footerStatus = document.createElement('span');
2383
2382
  footerStatus.style.cssText = 'font-size:11px;color:rgba(205,214,244,0.45);flex:1;';
2384
2383
 
2385
- rightFooter.appendChild(deployBtn);
2386
2384
  rightFooter.appendChild(copyLocalBtn);
2387
2385
  rightFooter.appendChild(promptBtn);
2386
+ rightFooter.appendChild(deployBtn);
2388
2387
  rightFooter.appendChild(footerStatus);
2389
2388
 
2390
2389
  // currentTpl 在 setActive 时更新,按钮 onclick 通过闭包读取
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiyiran/myclaw",
3
- "version": "1.1.88",
3
+ "version": "1.1.89",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -65,6 +65,9 @@ HISTORY_FILENAME = "history.json"
65
65
  _rollback_suppressed: dict = {}
66
66
  _ROLLBACK_SUPPRESS_TTL = 3.0 # 秒
67
67
 
68
+ # 时间窗口合并:同一文件在此时间窗口内的多次变更只保留最新快照(覆盖,不新增版本)
69
+ _HISTORY_MERGE_WINDOW = 20.0 # 秒
70
+
68
71
 
69
72
  def _is_rollback_suppressed(abs_path: str) -> bool:
70
73
  ts = _rollback_suppressed.get(abs_path)
@@ -94,36 +97,70 @@ def save_history_version(workspace_id: str, relative_path: str, file_path: str):
94
97
 
95
98
  history_data = _load_history_json(history_json_path, workspace_id)
96
99
 
97
- next_ver = history_data.get("next_version", 1)
98
- ver_dir_name = f"v{next_ver}"
100
+ # 检查该文件最后一次快照是否在合并窗口内
101
+ now_ts = time.time()
102
+ records = history_data.get("records", [])
103
+ last_record = next(
104
+ (r for r in reversed(records) if r.get("path") == relative_path),
105
+ None
106
+ )
107
+
108
+ if last_record:
109
+ try:
110
+ last_ts = datetime.fromisoformat(last_record["snapshot_at"]).timestamp()
111
+ except Exception:
112
+ last_ts = 0
113
+ within_window = (now_ts - last_ts) < _HISTORY_MERGE_WINDOW
114
+ else:
115
+ within_window = False
99
116
 
100
- # 复制当前文件内容到 __history__/vN/<relative_path>
101
117
  rel_parts = relative_path.replace("\\", "/").split("/")
102
- dest_path = os.path.join(history_base, ver_dir_name, *rel_parts)
103
- os.makedirs(os.path.dirname(dest_path), exist_ok=True)
104
- try:
105
- with open(file_path, "rb") as src, open(dest_path, "wb") as dst:
106
- dst.write(src.read())
107
- except Exception as e:
108
- print(f"[history] 快照写入失败: {e}")
109
- return
110
118
 
111
- # 更新 next_version、records、current_versions
112
- history_data["next_version"] = next_ver + 1
113
- history_data["records"].append({
114
- "version": next_ver,
115
- "version_dir": ver_dir_name,
116
- "path": relative_path,
117
- "snapshot_at": now_iso()
118
- })
119
- if "current_versions" not in history_data:
120
- history_data["current_versions"] = {}
121
- history_data["current_versions"][relative_path] = next_ver
119
+ if within_window:
120
+ # 覆盖最后一次快照,不新增版本
121
+ ver_dir_name = last_record["version_dir"]
122
+ dest_path = os.path.join(history_base, ver_dir_name, *rel_parts)
123
+ os.makedirs(os.path.dirname(dest_path), exist_ok=True)
124
+ try:
125
+ with open(file_path, "rb") as src, open(dest_path, "wb") as dst:
126
+ dst.write(src.read())
127
+ except Exception as e:
128
+ print(f"[history] 快照覆盖失败: {e}")
129
+ return
130
+ # 更新该 record 的时间戳
131
+ last_record["snapshot_at"] = now_iso()
132
+ with open(history_json_path, "w", encoding="utf-8") as f:
133
+ json.dump(history_data, f, ensure_ascii=False, indent=2)
134
+ print(f"[history] 合并覆盖快照 {ver_dir_name}: {relative_path}")
135
+ else:
136
+ # 超出时间窗口,新增版本
137
+ next_ver = history_data.get("next_version", 1)
138
+ ver_dir_name = f"v{next_ver}"
122
139
 
123
- with open(history_json_path, "w", encoding="utf-8") as f:
124
- json.dump(history_data, f, ensure_ascii=False, indent=2)
140
+ dest_path = os.path.join(history_base, ver_dir_name, *rel_parts)
141
+ os.makedirs(os.path.dirname(dest_path), exist_ok=True)
142
+ try:
143
+ with open(file_path, "rb") as src, open(dest_path, "wb") as dst:
144
+ dst.write(src.read())
145
+ except Exception as e:
146
+ print(f"[history] 快照写入失败: {e}")
147
+ return
148
+
149
+ history_data["next_version"] = next_ver + 1
150
+ history_data["records"].append({
151
+ "version": next_ver,
152
+ "version_dir": ver_dir_name,
153
+ "path": relative_path,
154
+ "snapshot_at": now_iso()
155
+ })
156
+ if "current_versions" not in history_data:
157
+ history_data["current_versions"] = {}
158
+ history_data["current_versions"][relative_path] = next_ver
159
+
160
+ with open(history_json_path, "w", encoding="utf-8") as f:
161
+ json.dump(history_data, f, ensure_ascii=False, indent=2)
125
162
 
126
- print(f"[history] 已保存快照 {ver_dir_name}: {relative_path}")
163
+ print(f"[history] 已保存快照 {ver_dir_name}: {relative_path}")
127
164
 
128
165
 
129
166
  def rollback_to_version(workspace_id: str, relative_path: str, version_dir: str):