@wendongfly/myhi 1.3.13 → 1.3.15

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/dist/chat.html CHANGED
@@ -334,6 +334,7 @@
334
334
  <button class="sk sk-claude" onclick="doSlashCmd('/rename')">命名</button>
335
335
  <button class="sk sk-claude" onclick="openGitSheet()" style="color:#3fb950">提交</button>
336
336
  <button class="sk sk-claude" onclick="showMemory()">记忆</button>
337
+ <button class="sk sk-claude" onclick="openSkillSheet()" style="color:#9d5cf5">技能</button>
337
338
  <span id="sk-custom-skills"></span>
338
339
  </div>
339
340
  </div>
@@ -451,6 +452,34 @@
451
452
  </div>
452
453
  </div>
453
454
 
455
+ <div id="skill-sheet" class="action-sheet">
456
+ <div class="action-sheet-backdrop" onclick="closeSkillSheet()"></div>
457
+ <div class="action-sheet-box" style="max-height:85vh;display:flex;flex-direction:column">
458
+ <div class="action-sheet-title" style="display:flex;align-items:center;justify-content:space-between;text-align:left">
459
+ <span id="skill-sheet-title">技能管理</span>
460
+ <button onclick="showSkillEditor()" style="background:#7c3aed;color:#fff;border:none;border-radius:6px;padding:0.3rem 0.7rem;font-size:0.75rem;cursor:pointer">+ 新建</button>
461
+ </div>
462
+ <!-- 技能列表视图 -->
463
+ <div id="skill-list-view" style="flex:1;overflow-y:auto;scrollbar-width:thin">
464
+ <div style="text-align:center;color:#8b949e;padding:2rem 0">加载中...</div>
465
+ </div>
466
+ <!-- 技能编辑视图 -->
467
+ <div id="skill-edit-view" style="display:none;flex:1;overflow-y:auto;scrollbar-width:thin;padding:0.3rem 0.2rem">
468
+ <div style="display:flex;flex-direction:column;gap:0.4rem">
469
+ <input id="skill-name" class="slash-inp" placeholder="技能名称 (如 mosaic-names)" autocomplete="off">
470
+ <select id="skill-scope" class="slash-inp" style="background:#0d1117;color:#c9d1d9;border:1px solid #30363d;border-radius:8px;padding:0.5rem;font-size:0.82rem">
471
+ <option value="user">用户级 (~/.claude/commands/)</option>
472
+ <option value="project">项目级 (.claude/commands/)</option>
473
+ </select>
474
+ <textarea id="skill-content" class="slash-inp" placeholder="# 技能标题&#10;&#10;技能描述和指令内容..." rows="10" style="resize:vertical;font-family:monospace;font-size:0.78rem;line-height:1.5"></textarea>
475
+ </div>
476
+ <button class="action-sheet-cancel" style="background:#7c3aed;color:#fff;font-weight:600;margin-top:0.5rem;margin-bottom:0.4rem" onclick="saveSkill()">保存</button>
477
+ <button class="action-sheet-cancel" onclick="backToSkillList()">返回列表</button>
478
+ </div>
479
+ <button id="skill-close-btn" class="action-sheet-cancel" onclick="closeSkillSheet()">关闭</button>
480
+ </div>
481
+ </div>
482
+
454
483
  <div id="status-overlay">连接中...</div>
455
484
 
456
485
  <script type="module">
@@ -1950,6 +1979,113 @@
1950
1979
  // 加入会话后加载 skill
1951
1980
  socket.on('joined', () => { if (currentSession?.mode === 'agent') loadSkills(); });
1952
1981
 
1982
+ // ── 技能管理 ──────────────────────────────────
1983
+ let _editingSkill = null; // 编辑中的技能名,null 表示新建
1984
+
1985
+ window.openSkillSheet = async function() {
1986
+ document.getElementById('skill-sheet').classList.add('open');
1987
+ document.getElementById('skill-list-view').style.display = '';
1988
+ document.getElementById('skill-edit-view').style.display = 'none';
1989
+ document.getElementById('skill-close-btn').style.display = '';
1990
+ await refreshSkillList();
1991
+ };
1992
+ window.closeSkillSheet = function() {
1993
+ document.getElementById('skill-sheet').classList.remove('open');
1994
+ };
1995
+
1996
+ async function refreshSkillList() {
1997
+ const listEl = document.getElementById('skill-list-view');
1998
+ listEl.innerHTML = '<div style="text-align:center;color:#8b949e;padding:2rem 0">加载中...</div>';
1999
+ try {
2000
+ const resp = await fetch(`/api/skills?sessionId=${SESSION_ID}&detail=1`);
2001
+ const data = await resp.json();
2002
+ if (!data.skills || !data.skills.length) {
2003
+ listEl.innerHTML = '<div style="text-align:center;color:#8b949e;padding:2rem 0">暂无技能,点击右上角 + 新建</div>';
2004
+ return;
2005
+ }
2006
+ listEl.innerHTML = data.skills.map(s => `
2007
+ <div class="action-sheet-item" style="gap:0.5rem">
2008
+ <div style="min-width:0;flex:1;cursor:pointer" onclick="editSkill('${escHtml(s.name)}','${escHtml(s.source)}')">
2009
+ <div style="color:#9d5cf5;font-weight:500">/${escHtml(s.name)}</div>
2010
+ <div class="desc">${escHtml(s.desc)} · ${s.source === 'project' ? '项目级' : '用户级'}</div>
2011
+ </div>
2012
+ <button onclick="deleteSkill('${escHtml(s.name)}','${escHtml(s.source)}')" style="background:none;border:none;color:#f85149;font-size:0.78rem;cursor:pointer;padding:0.3rem 0.5rem;white-space:nowrap">删除</button>
2013
+ </div>
2014
+ `).join('');
2015
+ } catch (e) {
2016
+ listEl.innerHTML = `<div style="text-align:center;color:#f85149;padding:2rem 0">加载失败: ${e.message}</div>`;
2017
+ }
2018
+ }
2019
+
2020
+ window.showSkillEditor = function(name, scope, content) {
2021
+ _editingSkill = name || null;
2022
+ document.getElementById('skill-list-view').style.display = 'none';
2023
+ document.getElementById('skill-edit-view').style.display = '';
2024
+ document.getElementById('skill-close-btn').style.display = 'none';
2025
+ document.getElementById('skill-sheet-title').textContent = name ? `编辑 /${name}` : '新建技能';
2026
+ document.getElementById('skill-name').value = name || '';
2027
+ document.getElementById('skill-name').disabled = !!name;
2028
+ document.getElementById('skill-scope').value = scope || 'user';
2029
+ document.getElementById('skill-content').value = content || '# 技能标题\n\n在此输入技能指令...\n';
2030
+ };
2031
+
2032
+ window.editSkill = async function(name, source) {
2033
+ try {
2034
+ const resp = await fetch(`/api/skills?sessionId=${SESSION_ID}&detail=1`);
2035
+ const data = await resp.json();
2036
+ const skill = data.skills?.find(s => s.name === name && s.source === source);
2037
+ showSkillEditor(name, source, skill?.content || '');
2038
+ } catch {}
2039
+ };
2040
+
2041
+ window.backToSkillList = function() {
2042
+ document.getElementById('skill-list-view').style.display = '';
2043
+ document.getElementById('skill-edit-view').style.display = 'none';
2044
+ document.getElementById('skill-close-btn').style.display = '';
2045
+ document.getElementById('skill-sheet-title').textContent = '技能管理';
2046
+ refreshSkillList();
2047
+ };
2048
+
2049
+ window.saveSkill = async function() {
2050
+ const name = document.getElementById('skill-name').value.trim();
2051
+ const scope = document.getElementById('skill-scope').value;
2052
+ const content = document.getElementById('skill-content').value;
2053
+ if (!name) { addStatusMessage('请输入技能名称'); return; }
2054
+ if (!content.trim()) { addStatusMessage('请输入技能内容'); return; }
2055
+ try {
2056
+ const resp = await fetch(`/api/skills?sessionId=${SESSION_ID}`, {
2057
+ method: 'POST',
2058
+ headers: { 'Content-Type': 'application/json' },
2059
+ body: JSON.stringify({ name, scope, content }),
2060
+ });
2061
+ const data = await resp.json();
2062
+ if (data.error) { addStatusMessage('保存失败: ' + data.error); return; }
2063
+ addStatusMessage(`技能 /${name} 已保存`);
2064
+ backToSkillList();
2065
+ loadSkills(); // 刷新快捷栏按钮
2066
+ } catch (e) {
2067
+ addStatusMessage('保存失败: ' + e.message);
2068
+ }
2069
+ };
2070
+
2071
+ window.deleteSkill = async function(name, source) {
2072
+ if (!confirm(`确定删除技能 /${name}?`)) return;
2073
+ try {
2074
+ const resp = await fetch(`/api/skills?sessionId=${SESSION_ID}`, {
2075
+ method: 'DELETE',
2076
+ headers: { 'Content-Type': 'application/json' },
2077
+ body: JSON.stringify({ name, scope: source }),
2078
+ });
2079
+ const data = await resp.json();
2080
+ if (data.error) { addStatusMessage('删除失败: ' + data.error); return; }
2081
+ addStatusMessage(`技能 /${name} 已删除`);
2082
+ refreshSkillList();
2083
+ loadSkills(); // 刷新快捷栏按钮
2084
+ } catch (e) {
2085
+ addStatusMessage('删除失败: ' + e.message);
2086
+ }
2087
+ };
2088
+
1953
2089
  // ── Git 提交推送 ──────────────────────────────
1954
2090
  const GIT_STORAGE_KEY = 'myhi-git-' + SESSION_ID;
1955
2091