@adversity/coding-tool-x 2.4.2 → 2.5.0

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.
@@ -1,4 +1,4 @@
1
- import{S as t}from"./vue-vendor-hRp8vsrL.js";"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self&&self;function e(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}function n(t){if(t.__esModule)return t;var e=t.default;if("function"==typeof e){var n=function t(){return this instanceof t?Reflect.construct(e,arguments,this.constructor):e.apply(this,arguments)};n.prototype=e.prototype}else n={};return Object.defineProperty(n,"__esModule",{value:!0}),Object.keys(t).forEach(function(e){var r=Object.getOwnPropertyDescriptor(t,e);Object.defineProperty(n,e,r.get?r:{enumerable:!0,get:function(){return t[e]}})}),n}var r={exports:{}};const o=n(t);
1
+ import{S as t}from"./vue-vendor-CEeI-Azr.js";"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self&&self;function e(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}function n(t){if(t.__esModule)return t;var e=t.default;if("function"==typeof e){var n=function t(){return this instanceof t?Reflect.construct(e,arguments,this.constructor):e.apply(this,arguments)};n.prototype=e.prototype}else n={};return Object.defineProperty(n,"__esModule",{value:!0}),Object.keys(t).forEach(function(e){var r=Object.getOwnPropertyDescriptor(t,e);Object.defineProperty(n,e,r.get?r:{enumerable:!0,get:function(){return t[e]}})}),n}var r={exports:{}};const o=n(t);
2
2
  /**!
3
3
  * Sortable 1.14.0
4
4
  * @author RubaXa <trash@rubaxa.org>
@@ -41,4 +41,4 @@ let ic;const lc=e=>ic=e,cc=Symbol();function ac(e){return e&&"object"==typeof e&
41
41
  * vue-router v4.6.4
42
42
  * (c) 2025 Eduardo San Martin Morote
43
43
  * @license MIT
44
- */(e,t);n=Na(o.reverse(),"beforeRouteLeave",e,t);for(const s of o)s.leaveGuards.forEach(o=>{n.push(Ra(o,e,t))});const c=y.bind(null,e,t);return n.push(c),M(n).then(()=>{n=[];for(const o of s.list())n.push(Ra(o,e,t));return n.push(c),M(n)}).then(()=>{n=Na(r,"beforeRouteUpdate",e,t);for(const o of r)o.updateGuards.forEach(o=>{n.push(Ra(o,e,t))});return n.push(c),M(n)}).then(()=>{n=[];for(const o of l)if(o.beforeEnter)if(Pc(o.beforeEnter))for(const r of o.beforeEnter)n.push(Ra(r,e,t));else n.push(Ra(o.beforeEnter,e,t));return n.push(c),M(n)}).then(()=>(e.matched.forEach(e=>e.enterCallbacks={}),n=Na(l,"beforeRouteEnter",e,t,b),n.push(c),M(n))).then(()=>{n=[];for(const o of i.list())n.push(Ra(o,e,t));return n.push(c),M(n)}).catch(e=>ba(e,va.NAVIGATION_CANCELLED)?e:Promise.reject(e))}function S(e,t,n){l.list().forEach(o=>b(()=>o(e,t,n)))}function C(e,t,n,o,s){const i=g(e,t);if(i)return i;const l=t===ia,a=Tc?history.state:{};n&&(o||l?r.replace(e.fullPath,Oc({scroll:l&&a&&a.scroll},s)):r.push(e.fullPath,s)),c.value=e,N(e,t,n,l),R()}let x;function w(){x||(x=r.listen((e,t,n)=>{if(!L.listening)return;const o=d(e),s=v(o,L.currentRoute.value);if(s)return void _(Oc(s,{replace:!0,force:!0}),o).catch(Nc);a=o;const i=c.value;var l,u;Tc&&(l=ha(i.fullPath,n.delta),u=pa(),ga.set(l,u)),E(o,i).catch(e=>ba(e,va.NAVIGATION_ABORTED|va.NAVIGATION_CANCELLED)?e:ba(e,va.NAVIGATION_GUARD_REDIRECT)?(_(Oc(h(e.to),{force:!0}),o).then(e=>{ba(e,va.NAVIGATION_ABORTED|va.NAVIGATION_DUPLICATED)&&!n.delta&&n.type===la.pop&&r.go(-1,!1)}).catch(Nc),Promise.reject()):(n.delta&&r.go(-n.delta,!1),O(e,o,i))).then(e=>{(e=e||C(o,i,!1))&&(n.delta&&!ba(e,va.NAVIGATION_CANCELLED)?r.go(-n.delta,!1):n.type===la.pop&&ba(e,va.NAVIGATION_ABORTED|va.NAVIGATION_DUPLICATED)&&r.go(-1,!1)),S(o,i,e)}).catch(Nc)}))}let A,T=Oa(),k=Oa();function O(e,t,n){R(e);const o=k.list();return o.length&&o.forEach(o=>o(e,t,n)),Promise.reject(e)}function R(e){return A||(A=!e,w(),T.list().forEach(([t,n])=>e?n(e):t()),T.reset()),e}function N(t,n,o,r){const{scrollBehavior:s}=e;if(!Tc||!s)return Promise.resolve();const i=!o&&function(e){const t=ga.get(e);return ga.delete(e),t}(ha(t.fullPath,0))||(r||!o)&&history.state&&history.state.scroll||null;return an().then(()=>s(t,n,i)).then(e=>e&&da(e)).catch(e=>O(e,t,n))}const P=e=>r.go(e);let I;const D=new Set,L={currentRoute:c,listening:!0,addRoute:function(e,n){let o,r;return ma(e)?(o=t.getRecordMatcher(e),r=n):r=e,t.addRoute(r,o)},removeRoute:function(e){const n=t.getRecordMatcher(e);n&&t.removeRoute(n)},clearRoutes:t.clearRoutes,hasRoute:function(e){return!!t.getRecordMatcher(e)},getRoutes:function(){return t.getRoutes().map(e=>e.record)},resolve:d,options:e,push:m,replace:function(e){return m(Oc(h(e),{replace:!0}))},go:P,back:()=>P(-1),forward:()=>P(1),beforeEach:s.add,beforeResolve:i.add,afterEach:l.add,onError:k.add,isReady:function(){return A&&c.value!==ia?Promise.resolve():new Promise((e,t)=>{T.add([e,t])})},install(e){e.component("RouterLink",ou),e.component("RouterView",lu),e.config.globalProperties.$router=L,Object.defineProperty(e.config.globalProperties,"$route",{enumerable:!0,get:()=>Dt(c)}),Tc&&!I&&c.value===ia&&(I=!0,m(r.location).catch(e=>{}));const t={};for(const o in ia)Object.defineProperty(t,o,{get:()=>c.value[o],enumerable:!0});e.provide(Aa,L),e.provide(Ta,vt(t)),e.provide(ka,c);const n=e.unmount;D.add(e),e.unmount=function(){D.delete(e),D.size<1&&(a=ia,x&&x(),x=null,c.value=ia,I=!1,A=!1),n()}}};function M(e){return e.reduce((e,t)=>e.then(()=>b(t)),Promise.resolve())}return L}function au(){return An(Aa)}function uu(e){return An(Ta)}export{Qo as $,Ki as A,Ls as B,vs as C,ms as D,At as E,gs as F,$o as G,W as H,ec as I,Dt as J,xt as K,wt as L,jt as M,U as N,As as O,Ps as P,Es as Q,Fs as R,sc as S,Wn as T,wc as U,Ac as V,Is as W,Sn as X,Vs as Y,Ts as Z,X as _,_t as a,au as a0,Jo as a1,Wl as a2,uu as a3,ql as a4,cu as a5,La as a6,er as a7,zo as a8,To as a9,pc as aa,Bo as b,ui as c,Fo as d,mt as e,Oo as f,zs as g,Ro as h,An as i,Ms as j,co as k,Cn as l,fi as m,an as n,Vo as o,wn as p,tr as q,Rt as r,$s as s,$t as t,ks as u,Nt as v,Pn as w,Rn as x,Ri as y,Cl as z};
44
+ */(e,t);n=Na(o.reverse(),"beforeRouteLeave",e,t);for(const s of o)s.leaveGuards.forEach(o=>{n.push(Ra(o,e,t))});const c=y.bind(null,e,t);return n.push(c),M(n).then(()=>{n=[];for(const o of s.list())n.push(Ra(o,e,t));return n.push(c),M(n)}).then(()=>{n=Na(r,"beforeRouteUpdate",e,t);for(const o of r)o.updateGuards.forEach(o=>{n.push(Ra(o,e,t))});return n.push(c),M(n)}).then(()=>{n=[];for(const o of l)if(o.beforeEnter)if(Pc(o.beforeEnter))for(const r of o.beforeEnter)n.push(Ra(r,e,t));else n.push(Ra(o.beforeEnter,e,t));return n.push(c),M(n)}).then(()=>(e.matched.forEach(e=>e.enterCallbacks={}),n=Na(l,"beforeRouteEnter",e,t,b),n.push(c),M(n))).then(()=>{n=[];for(const o of i.list())n.push(Ra(o,e,t));return n.push(c),M(n)}).catch(e=>ba(e,va.NAVIGATION_CANCELLED)?e:Promise.reject(e))}function S(e,t,n){l.list().forEach(o=>b(()=>o(e,t,n)))}function C(e,t,n,o,s){const i=g(e,t);if(i)return i;const l=t===ia,a=Tc?history.state:{};n&&(o||l?r.replace(e.fullPath,Oc({scroll:l&&a&&a.scroll},s)):r.push(e.fullPath,s)),c.value=e,N(e,t,n,l),R()}let x;function w(){x||(x=r.listen((e,t,n)=>{if(!L.listening)return;const o=d(e),s=v(o,L.currentRoute.value);if(s)return void _(Oc(s,{replace:!0,force:!0}),o).catch(Nc);a=o;const i=c.value;var l,u;Tc&&(l=ha(i.fullPath,n.delta),u=pa(),ga.set(l,u)),E(o,i).catch(e=>ba(e,va.NAVIGATION_ABORTED|va.NAVIGATION_CANCELLED)?e:ba(e,va.NAVIGATION_GUARD_REDIRECT)?(_(Oc(h(e.to),{force:!0}),o).then(e=>{ba(e,va.NAVIGATION_ABORTED|va.NAVIGATION_DUPLICATED)&&!n.delta&&n.type===la.pop&&r.go(-1,!1)}).catch(Nc),Promise.reject()):(n.delta&&r.go(-n.delta,!1),O(e,o,i))).then(e=>{(e=e||C(o,i,!1))&&(n.delta&&!ba(e,va.NAVIGATION_CANCELLED)?r.go(-n.delta,!1):n.type===la.pop&&ba(e,va.NAVIGATION_ABORTED|va.NAVIGATION_DUPLICATED)&&r.go(-1,!1)),S(o,i,e)}).catch(Nc)}))}let A,T=Oa(),k=Oa();function O(e,t,n){R(e);const o=k.list();return o.length&&o.forEach(o=>o(e,t,n)),Promise.reject(e)}function R(e){return A||(A=!e,w(),T.list().forEach(([t,n])=>e?n(e):t()),T.reset()),e}function N(t,n,o,r){const{scrollBehavior:s}=e;if(!Tc||!s)return Promise.resolve();const i=!o&&function(e){const t=ga.get(e);return ga.delete(e),t}(ha(t.fullPath,0))||(r||!o)&&history.state&&history.state.scroll||null;return an().then(()=>s(t,n,i)).then(e=>e&&da(e)).catch(e=>O(e,t,n))}const P=e=>r.go(e);let I;const D=new Set,L={currentRoute:c,listening:!0,addRoute:function(e,n){let o,r;return ma(e)?(o=t.getRecordMatcher(e),r=n):r=e,t.addRoute(r,o)},removeRoute:function(e){const n=t.getRecordMatcher(e);n&&t.removeRoute(n)},clearRoutes:t.clearRoutes,hasRoute:function(e){return!!t.getRecordMatcher(e)},getRoutes:function(){return t.getRoutes().map(e=>e.record)},resolve:d,options:e,push:m,replace:function(e){return m(Oc(h(e),{replace:!0}))},go:P,back:()=>P(-1),forward:()=>P(1),beforeEach:s.add,beforeResolve:i.add,afterEach:l.add,onError:k.add,isReady:function(){return A&&c.value!==ia?Promise.resolve():new Promise((e,t)=>{T.add([e,t])})},install(e){e.component("RouterLink",ou),e.component("RouterView",lu),e.config.globalProperties.$router=L,Object.defineProperty(e.config.globalProperties,"$route",{enumerable:!0,get:()=>Dt(c)}),Tc&&!I&&c.value===ia&&(I=!0,m(r.location).catch(e=>{}));const t={};for(const o in ia)Object.defineProperty(t,o,{get:()=>c.value[o],enumerable:!0});e.provide(Aa,L),e.provide(Ta,vt(t)),e.provide(ka,c);const n=e.unmount;D.add(e),e.unmount=function(){D.delete(e),D.size<1&&(a=ia,x&&x(),x=null,c.value=ia,I=!1,A=!1),n()}}};function M(e){return e.reduce((e,t)=>e.then(()=>b(t)),Promise.resolve())}return L}function au(){return An(Aa)}function uu(e){return An(Ta)}export{au as $,Ki as A,Ls as B,vs as C,ms as D,At as E,gs as F,$o as G,W as H,ec as I,Dt as J,xt as K,wt as L,jt as M,U as N,As as O,Ps as P,Es as Q,Fs as R,sc as S,Wn as T,wc as U,Ac as V,Is as W,Sn as X,Vs as Y,Ts as Z,X as _,_t as a,Qo as a0,Jo as a1,Wl as a2,uu as a3,ql as a4,cu as a5,La as a6,er as a7,zo as a8,To as a9,pc as aa,Bo as b,ui as c,Fo as d,mt as e,Oo as f,zs as g,Ro as h,An as i,Ms as j,co as k,Cn as l,fi as m,an as n,Vo as o,wn as p,tr as q,Rt as r,$s as s,$t as t,ks as u,Nt as v,Pn as w,Rn as x,Ri as y,Cl as z};
@@ -5,12 +5,12 @@
5
5
  <link rel="icon" href="/favicon.ico">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
7
  <title>CC-TOOL - ClaudeCode增强工作助手</title>
8
- <script type="module" crossorigin src="/assets/index-DOsR4qc6.js"></script>
9
- <link rel="modulepreload" crossorigin href="/assets/vue-vendor-hRp8vsrL.js">
10
- <link rel="modulepreload" crossorigin href="/assets/vendors-Bd5vxA1-.js">
11
- <link rel="modulepreload" crossorigin href="/assets/icons-BkBtk3H1.js">
12
- <link rel="modulepreload" crossorigin href="/assets/naive-ui-D-gb0WfN.js">
13
- <link rel="stylesheet" crossorigin href="/assets/index-Cgq2DyzS.css">
8
+ <script type="module" crossorigin src="/assets/index-k9b43kTe.js"></script>
9
+ <link rel="modulepreload" crossorigin href="/assets/vue-vendor-CEeI-Azr.js">
10
+ <link rel="modulepreload" crossorigin href="/assets/vendors-CzcvkTIS.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/icons-BALJo7bE.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/naive-ui-sh0u_0bf.js">
13
+ <link rel="stylesheet" crossorigin href="/assets/index-CcYz-Mcz.css">
14
14
  </head>
15
15
  <body>
16
16
  <div id="app"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adversity/coding-tool-x",
3
- "version": "2.4.2",
3
+ "version": "2.5.0",
4
4
  "description": "Vibe Coding 增强工作助手 - 智能会话管理、动态渠道切换、全局搜索、实时监控",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -47,6 +47,7 @@
47
47
  "dependencies": {
48
48
  "@iarna/toml": "^2.2.5",
49
49
  "@lydell/node-pty": "^1.1.0",
50
+ "@xterm/headless": "^6.0.0",
50
51
  "adm-zip": "^0.5.16",
51
52
  "cc-tool-web": "file:src/web",
52
53
  "chalk": "^4.1.2",
@@ -71,4 +72,4 @@
71
72
  "url": "https://github.com/ZeaoZhang/coding-tool/issues"
72
73
  },
73
74
  "homepage": "https://github.com/ZeaoZhang/coding-tool#readme"
74
- }
75
+ }
@@ -0,0 +1,36 @@
1
+ const chalk = require('chalk');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
5
+
6
+ const SECURITY_FILE = path.join(os.homedir(), '.claude', 'cc-tool', 'security.json');
7
+
8
+ function showSecurityHelp() {
9
+ console.log(chalk.yellow('\n🔐 安全设置命令:'));
10
+ console.log(' ctx security reset 关闭访问密码(删除安全配置文件)');
11
+ console.log('');
12
+ }
13
+
14
+ async function handleSecurityReset() {
15
+ console.log(chalk.cyan('\n🔐 安全设置 - 关闭访问密码\n'));
16
+
17
+ if (!fs.existsSync(SECURITY_FILE)) {
18
+ console.log(chalk.yellow('⚠️ 未检测到安全配置文件'));
19
+ console.log(chalk.gray(`路径: ${SECURITY_FILE}\n`));
20
+ return;
21
+ }
22
+
23
+ try {
24
+ fs.unlinkSync(SECURITY_FILE);
25
+ console.log(chalk.green('✅ 访问密码已关闭'));
26
+ console.log(chalk.gray(`已删除: ${SECURITY_FILE}\n`));
27
+ } catch (error) {
28
+ console.error(chalk.red('❌ 关闭密码失败:'), error.message);
29
+ console.log(chalk.gray(`路径: ${SECURITY_FILE}\n`));
30
+ }
31
+ }
32
+
33
+ module.exports = {
34
+ showSecurityHelp,
35
+ handleSecurityReset
36
+ };
package/src/index.js CHANGED
@@ -10,8 +10,6 @@ const { showMainMenu } = require('./ui/menu');
10
10
  const { handleList } = require('./commands/list');
11
11
  const { handleSearch } = require('./commands/search');
12
12
  const { switchProject } = require('./commands/switch');
13
- const { handleUI } = require('./commands/ui');
14
- const { handleProxyStart, handleProxyStop, handleProxyStatus } = require('./commands/proxy');
15
13
  const { resetConfig } = require('./reset-config');
16
14
  const { handleChannelManagement, handleAddChannel, handleChannelStatus } = require('./commands/channels');
17
15
  const { handleToggleProxy } = require('./commands/toggle-proxy');
@@ -77,6 +75,7 @@ function showHelp() {
77
75
  console.log(chalk.yellow('🛠️ 其他命令:'));
78
76
  console.log(' ctx doctor 系统诊断');
79
77
  console.log(' ctx reset 重置配置');
78
+ console.log(' ctx security reset 关闭访问密码');
80
79
  console.log(' ctx --version, -v 显示版本');
81
80
  console.log(' ctx --help, -h 显示帮助\n');
82
81
 
@@ -136,6 +135,19 @@ async function main() {
136
135
  return;
137
136
  }
138
137
 
138
+ // security 命令 - 安全设置
139
+ if (args[0] === 'security') {
140
+ const { showSecurityHelp, handleSecurityReset } = require('./commands/security');
141
+ const subCommand = args[1] || 'help';
142
+
143
+ if (subCommand === 'reset' || subCommand === 'disable' || subCommand === 'off') {
144
+ await handleSecurityReset();
145
+ } else {
146
+ showSecurityHelp();
147
+ }
148
+ return;
149
+ }
150
+
139
151
  // start 命令 - 启动服务(后台)
140
152
  if (args[0] === 'start') {
141
153
  await handleStart();
@@ -171,6 +183,7 @@ async function main() {
171
183
  await handleRestart();
172
184
  } else {
173
185
  // 默认前台运行
186
+ const { handleUI } = require('./commands/ui');
174
187
  await handleUI();
175
188
  }
176
189
  return;
@@ -252,6 +265,7 @@ async function main() {
252
265
 
253
266
  // 代理命令
254
267
  if (args[0] === 'proxy') {
268
+ const { handleProxyStart, handleProxyStop, handleProxyStatus } = require('./commands/proxy');
255
269
  const subCommand = args[1] || 'start';
256
270
 
257
271
  switch (subCommand) {
@@ -342,9 +356,11 @@ async function main() {
342
356
  await handleAddChannel();
343
357
  break;
344
358
 
345
- case 'ui':
359
+ case 'ui': {
360
+ const { handleUI } = require('./commands/ui');
346
361
  await handleUI();
347
362
  break;
363
+ }
348
364
 
349
365
  case 'port-config':
350
366
  await handlePortConfig();
@@ -0,0 +1,53 @@
1
+ const express = require('express');
2
+ const router = express.Router();
3
+ const {
4
+ getSecurityStatus,
5
+ verifySecurityPassword,
6
+ setSecurityPassword
7
+ } = require('../services/security-config');
8
+
9
+ router.get('/', (req, res) => {
10
+ try {
11
+ const status = getSecurityStatus();
12
+ res.json({ success: true, ...status });
13
+ } catch (error) {
14
+ console.error('Error getting security status:', error);
15
+ res.status(500).json({ error: error.message });
16
+ }
17
+ });
18
+
19
+ router.post('/verify', (req, res) => {
20
+ try {
21
+ const { password } = req.body;
22
+ if (typeof password !== 'string' || !password) {
23
+ return res.status(400).json({ error: '请输入密码' });
24
+ }
25
+
26
+ const result = verifySecurityPassword(password);
27
+ if (result.reason === 'not_set') {
28
+ return res.status(400).json({ error: '尚未设置访问密码' });
29
+ }
30
+ if (!result.ok) {
31
+ return res.status(401).json({ error: '密码错误' });
32
+ }
33
+
34
+ res.json({ success: true });
35
+ } catch (error) {
36
+ console.error('Error verifying security password:', error);
37
+ res.status(500).json({ error: error.message });
38
+ }
39
+ });
40
+
41
+ router.post('/password', (req, res) => {
42
+ try {
43
+ const { currentPassword, newPassword } = req.body || {};
44
+ const result = setSecurityPassword({ currentPassword, newPassword });
45
+ res.json({ success: true, ...result });
46
+ } catch (error) {
47
+ const status = error.code === 'INVALID_PASSWORD' ? 401 : 400;
48
+ console.error('Error setting security password:', error);
49
+ res.status(status).json({ error: error.message });
50
+ }
51
+ });
52
+
53
+ module.exports = router;
@@ -9,6 +9,7 @@ const path = require('path');
9
9
  const fs = require('fs');
10
10
 
11
11
  const { ptyManager } = require('../services/pty-manager');
12
+ const { getWebTerminalShellConfig } = require('../services/terminal-config');
12
13
  const {
13
14
  loadTerminalCommands,
14
15
  saveTerminalCommands,
@@ -171,13 +172,16 @@ router.post('/create', (req, res) => {
171
172
  // 获取启动命令
172
173
  const startCommand = getCommandForChannel(channel, sessionId, workDir);
173
174
 
175
+ const shellConfig = getWebTerminalShellConfig();
176
+
174
177
  // 创建终端
175
178
  const terminal = ptyManager.create({
176
179
  cwd: workDir,
177
180
  channel,
178
181
  sessionId,
179
182
  projectName,
180
- startCommand
183
+ startCommand,
184
+ ...shellConfig
181
185
  });
182
186
 
183
187
  res.json({
@@ -109,6 +109,7 @@ async function startServer(port) {
109
109
  app.use('/api/aliases', require('./api/aliases')());
110
110
  app.use('/api/favorites', require('./api/favorites'));
111
111
  app.use('/api/ui-config', require('./api/ui-config'));
112
+ app.use('/api/security', require('./api/security'));
112
113
  app.use('/api/channels', require('./api/channels'));
113
114
  app.use('/api/proxy', require('./api/proxy'));
114
115
  app.use('/api/codex/proxy', require('./api/codex-proxy'));
@@ -8,8 +8,158 @@ const path = require('path');
8
8
  const permissionTemplatesService = require('./permission-templates-service');
9
9
  const configTemplatesService = require('./config-templates-service');
10
10
  const channelsService = require('./channels');
11
+ const { AgentsService } = require('./agents-service');
12
+ const { CommandsService } = require('./commands-service');
13
+ const { RulesService } = require('./rules-service');
14
+ const { SkillService } = require('./skill-service');
11
15
 
12
16
  const CONFIG_VERSION = '1.0.0';
17
+ const SKILL_FILE_ENCODING = 'base64';
18
+ const SKILL_IGNORE_DIRS = new Set(['.git']);
19
+ const SKILL_IGNORE_FILES = new Set(['.DS_Store']);
20
+
21
+ function ensureDir(dirPath) {
22
+ if (!fs.existsSync(dirPath)) {
23
+ fs.mkdirSync(dirPath, { recursive: true });
24
+ }
25
+ }
26
+
27
+ function resolveSafePath(baseDir, relativePath) {
28
+ if (!relativePath || typeof relativePath !== 'string') return null;
29
+ const normalized = path.normalize(relativePath);
30
+ if (path.isAbsolute(normalized)) return null;
31
+ const resolved = path.resolve(baseDir, normalized);
32
+ const relative = path.relative(baseDir, resolved);
33
+ if (relative.startsWith('..') || path.isAbsolute(relative)) return null;
34
+ return resolved;
35
+ }
36
+
37
+ function buildAgentContent(agent) {
38
+ const lines = ['---'];
39
+ if (agent.name) lines.push(`name: ${agent.name}`);
40
+ if (agent.description) lines.push(`description: "${agent.description}"`);
41
+ if (agent.tools) lines.push(`tools: ${agent.tools}`);
42
+ if (agent.model) lines.push(`model: ${agent.model}`);
43
+ if (agent.permissionMode) lines.push(`permissionMode: ${agent.permissionMode}`);
44
+ if (agent.skills) lines.push(`skills: ${agent.skills}`);
45
+ lines.push('---');
46
+ const body = agent.systemPrompt || '';
47
+ return `${lines.join('\n')}\n\n${body}`;
48
+ }
49
+
50
+ function buildCommandContent(command) {
51
+ const frontmatter = {};
52
+ if (command.description) frontmatter.description = command.description;
53
+ if (command.allowedTools) frontmatter['allowed-tools'] = command.allowedTools;
54
+ if (command.argumentHint) frontmatter['argument-hint'] = command.argumentHint;
55
+
56
+ const lines = [];
57
+ if (Object.keys(frontmatter).length > 0) {
58
+ lines.push('---');
59
+ if (frontmatter.description) {
60
+ lines.push(`description: "${frontmatter.description}"`);
61
+ }
62
+ if (frontmatter['allowed-tools']) {
63
+ lines.push(`allowed-tools: ${frontmatter['allowed-tools']}`);
64
+ }
65
+ if (frontmatter['argument-hint']) {
66
+ lines.push(`argument-hint: ${frontmatter['argument-hint']}`);
67
+ }
68
+ lines.push('---');
69
+ lines.push('');
70
+ }
71
+
72
+ const body = command.body || '';
73
+ return `${lines.join('\n')}${body}`;
74
+ }
75
+
76
+ function buildRuleContent(rule) {
77
+ const lines = [];
78
+ if (rule.paths) {
79
+ lines.push('---');
80
+ lines.push(`paths: ${rule.paths}`);
81
+ lines.push('---');
82
+ lines.push('');
83
+ }
84
+ const body = rule.body || '';
85
+ return `${lines.join('\n')}${body}`;
86
+ }
87
+
88
+ function collectSkillFiles(baseDir) {
89
+ const files = [];
90
+ const stack = [baseDir];
91
+
92
+ while (stack.length > 0) {
93
+ const currentDir = stack.pop();
94
+ let entries = [];
95
+ try {
96
+ entries = fs.readdirSync(currentDir, { withFileTypes: true });
97
+ } catch (err) {
98
+ continue;
99
+ }
100
+
101
+ for (const entry of entries) {
102
+ if (entry.isDirectory()) {
103
+ if (SKILL_IGNORE_DIRS.has(entry.name)) {
104
+ continue;
105
+ }
106
+ stack.push(path.join(currentDir, entry.name));
107
+ } else if (entry.isFile()) {
108
+ if (SKILL_IGNORE_FILES.has(entry.name)) {
109
+ continue;
110
+ }
111
+ const fullPath = path.join(currentDir, entry.name);
112
+ const relativePath = path.relative(baseDir, fullPath);
113
+ try {
114
+ const content = fs.readFileSync(fullPath);
115
+ files.push({
116
+ path: relativePath,
117
+ encoding: SKILL_FILE_ENCODING,
118
+ content: content.toString(SKILL_FILE_ENCODING)
119
+ });
120
+ } catch (err) {
121
+ continue;
122
+ }
123
+ }
124
+ }
125
+ }
126
+
127
+ files.sort((a, b) => a.path.localeCompare(b.path));
128
+ return files;
129
+ }
130
+
131
+ function exportSkillsSnapshot() {
132
+ const skillService = new SkillService();
133
+ const installedSkills = skillService.getInstalledSkills();
134
+ const baseDir = skillService.installDir;
135
+
136
+ return installedSkills.map((skill) => {
137
+ const directory = skill.directory;
138
+ const skillDir = resolveSafePath(baseDir, directory);
139
+ if (!skillDir || !fs.existsSync(skillDir)) {
140
+ return null;
141
+ }
142
+ return {
143
+ directory,
144
+ name: skill.name || directory,
145
+ description: skill.description || '',
146
+ files: collectSkillFiles(skillDir)
147
+ };
148
+ }).filter(Boolean);
149
+ }
150
+
151
+ function writeTextFile(baseDir, relativePath, content, overwrite) {
152
+ if (!content && content !== '') {
153
+ return 'failed';
154
+ }
155
+ const targetPath = resolveSafePath(baseDir, relativePath);
156
+ if (!targetPath) return 'failed';
157
+ if (fs.existsSync(targetPath) && !overwrite) return 'skipped';
158
+
159
+ ensureDir(path.dirname(targetPath));
160
+ fs.writeFileSync(targetPath, content, 'utf8');
161
+ return 'success';
162
+ }
13
163
 
14
164
  /**
15
165
  * 导出所有配置为JSON
@@ -38,20 +188,49 @@ function exportAllConfigs() {
38
188
  const favorites = favoritesService.loadFavorites();
39
189
 
40
190
  // 获取 Agents 配置
41
- const agentsService = require('./agents-service');
42
- const agents = agentsService.getAllAgents();
191
+ const agentsService = new AgentsService();
192
+ const { agents: rawAgents } = agentsService.listAgents();
193
+ const agents = rawAgents.map(agent => ({
194
+ fileName: agent.fileName,
195
+ name: agent.name,
196
+ description: agent.description,
197
+ tools: agent.tools,
198
+ model: agent.model,
199
+ permissionMode: agent.permissionMode,
200
+ skills: agent.skills,
201
+ path: agent.path,
202
+ systemPrompt: agent.systemPrompt,
203
+ fullContent: agent.fullContent
204
+ }));
43
205
 
44
206
  // 获取 Skills 配置
45
- const skillService = require('./skill-service');
46
- const skills = skillService.getAllSkills();
207
+ const skills = exportSkillsSnapshot();
47
208
 
48
209
  // 获取 Commands 配置
49
- const commandsService = require('./commands-service');
50
- const commands = commandsService.getAllCommands();
210
+ const commandsService = new CommandsService();
211
+ const { commands: rawCommands } = commandsService.listCommands();
212
+ const commands = rawCommands.map(command => ({
213
+ name: command.name,
214
+ namespace: command.namespace,
215
+ description: command.description,
216
+ allowedTools: command.allowedTools,
217
+ argumentHint: command.argumentHint,
218
+ path: command.path,
219
+ body: command.body,
220
+ fullContent: command.fullContent
221
+ }));
51
222
 
52
223
  // 获取 Rules 配置
53
- const rulesService = require('./rules-service');
54
- const rules = rulesService.getAllRules();
224
+ const rulesService = new RulesService();
225
+ const { rules: rawRules } = rulesService.listRules();
226
+ const rules = rawRules.map(rule => ({
227
+ fileName: rule.fileName,
228
+ directory: rule.directory,
229
+ paths: rule.paths,
230
+ path: rule.path,
231
+ body: rule.body,
232
+ fullContent: rule.fullContent
233
+ }));
55
234
 
56
235
  // 获取 MCP 配置
57
236
  const mcpService = require('./mcp-service');
@@ -251,15 +430,24 @@ function importConfigs(importData, options = {}) {
251
430
  }
252
431
 
253
432
  // 导入 Agents
254
- if (agents && agents.length > 0 && overwrite) {
433
+ if (agents && agents.length > 0) {
255
434
  try {
256
- const agentsService = require('./agents-service');
435
+ const agentsService = new AgentsService();
436
+ const baseDir = agentsService.userAgentsDir;
437
+
257
438
  for (const agent of agents) {
258
- try {
259
- agentsService.saveAgent(agent);
439
+ const relativePath = agent.path || agent.fileName || agent.name;
440
+ const filePath = relativePath && relativePath.endsWith('.md')
441
+ ? relativePath
442
+ : (relativePath ? `${relativePath}.md` : null);
443
+ const content = agent.fullContent || agent.content || buildAgentContent(agent);
444
+
445
+ const status = filePath ? writeTextFile(baseDir, filePath, content, overwrite) : 'failed';
446
+ if (status === 'success') {
260
447
  results.agents.success++;
261
- } catch (err) {
262
- console.error(`[ConfigImport] 导入 Agent 失败: ${agent.name}`, err);
448
+ } else if (status === 'skipped') {
449
+ results.agents.skipped++;
450
+ } else {
263
451
  results.agents.failed++;
264
452
  }
265
453
  }
@@ -269,16 +457,55 @@ function importConfigs(importData, options = {}) {
269
457
  }
270
458
 
271
459
  // 导入 Skills
272
- if (skills && skills.length > 0 && overwrite) {
460
+ if (skills && skills.length > 0) {
273
461
  try {
274
- const skillService = require('./skill-service');
462
+ const skillService = new SkillService();
463
+ const baseDir = skillService.installDir;
464
+ ensureDir(baseDir);
465
+
275
466
  for (const skill of skills) {
276
- try {
277
- skillService.saveSkill(skill);
278
- results.skills.success++;
279
- } catch (err) {
280
- console.error(`[ConfigImport] 导入 Skill 失败: ${skill.name}`, err);
467
+ const directory = skill.directory;
468
+ const skillDir = resolveSafePath(baseDir, directory);
469
+ if (!skillDir) {
470
+ results.skills.failed++;
471
+ continue;
472
+ }
473
+
474
+ if (fs.existsSync(skillDir)) {
475
+ if (!overwrite) {
476
+ results.skills.skipped++;
477
+ continue;
478
+ }
479
+ fs.rmSync(skillDir, { recursive: true, force: true });
480
+ }
481
+
482
+ ensureDir(skillDir);
483
+ const files = Array.isArray(skill.files) ? skill.files : [];
484
+ let failed = false;
485
+
486
+ for (const file of files) {
487
+ const filePath = resolveSafePath(skillDir, file.path);
488
+ if (!filePath) {
489
+ failed = true;
490
+ break;
491
+ }
492
+ ensureDir(path.dirname(filePath));
493
+ try {
494
+ if (file.encoding === SKILL_FILE_ENCODING) {
495
+ fs.writeFileSync(filePath, Buffer.from(file.content || '', SKILL_FILE_ENCODING));
496
+ } else {
497
+ fs.writeFileSync(filePath, file.content || '', file.encoding || 'utf8');
498
+ }
499
+ } catch (err) {
500
+ failed = true;
501
+ break;
502
+ }
503
+ }
504
+
505
+ if (failed || files.length === 0) {
281
506
  results.skills.failed++;
507
+ } else {
508
+ results.skills.success++;
282
509
  }
283
510
  }
284
511
  } catch (err) {
@@ -287,15 +514,25 @@ function importConfigs(importData, options = {}) {
287
514
  }
288
515
 
289
516
  // 导入 Commands
290
- if (commands && commands.length > 0 && overwrite) {
517
+ if (commands && commands.length > 0) {
291
518
  try {
292
- const commandsService = require('./commands-service');
519
+ const commandsService = new CommandsService();
520
+ const baseDir = commandsService.userCommandsDir;
521
+
293
522
  for (const command of commands) {
294
- try {
295
- commandsService.saveCommand(command);
523
+ const relativePath = command.path || (
524
+ command.namespace
525
+ ? path.join(command.namespace, `${command.name}.md`)
526
+ : `${command.name}.md`
527
+ );
528
+ const content = command.fullContent || command.content || buildCommandContent(command);
529
+
530
+ const status = relativePath ? writeTextFile(baseDir, relativePath, content, overwrite) : 'failed';
531
+ if (status === 'success') {
296
532
  results.commands.success++;
297
- } catch (err) {
298
- console.error(`[ConfigImport] 导入 Command 失败: ${command.name}`, err);
533
+ } else if (status === 'skipped') {
534
+ results.commands.skipped++;
535
+ } else {
299
536
  results.commands.failed++;
300
537
  }
301
538
  }
@@ -305,15 +542,25 @@ function importConfigs(importData, options = {}) {
305
542
  }
306
543
 
307
544
  // 导入 Rules
308
- if (rules && rules.length > 0 && overwrite) {
545
+ if (rules && rules.length > 0) {
309
546
  try {
310
- const rulesService = require('./rules-service');
547
+ const rulesService = new RulesService();
548
+ const baseDir = rulesService.userRulesDir;
549
+
311
550
  for (const rule of rules) {
312
- try {
313
- rulesService.saveRule(rule);
551
+ const relativePath = rule.path || (
552
+ rule.directory
553
+ ? path.join(rule.directory, `${rule.fileName || rule.name}.md`)
554
+ : `${rule.fileName || rule.name}.md`
555
+ );
556
+ const content = rule.fullContent || rule.content || buildRuleContent(rule);
557
+
558
+ const status = relativePath ? writeTextFile(baseDir, relativePath, content, overwrite) : 'failed';
559
+ if (status === 'success') {
314
560
  results.rules.success++;
315
- } catch (err) {
316
- console.error(`[ConfigImport] 导入 Rule 失败: ${rule.name}`, err);
561
+ } else if (status === 'skipped') {
562
+ results.rules.skipped++;
563
+ } else {
317
564
  results.rules.failed++;
318
565
  }
319
566
  }