@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.
- package/CHANGELOG.md +15 -0
- package/dist/web/assets/{icons-BkBtk3H1.js → icons-BALJo7bE.js} +1 -1
- package/dist/web/assets/{index-Cgq2DyzS.css → index-CcYz-Mcz.css} +3 -3
- package/dist/web/assets/index-k9b43kTe.js +14 -0
- package/dist/web/assets/{naive-ui-D-gb0WfN.js → naive-ui-sh0u_0bf.js} +1 -1
- package/dist/web/assets/{vendors-Bd5vxA1-.js → vendors-CzcvkTIS.js} +1 -1
- package/dist/web/assets/{vue-vendor-hRp8vsrL.js → vue-vendor-CEeI-Azr.js} +1 -1
- package/dist/web/index.html +6 -6
- package/package.json +3 -2
- package/src/commands/security.js +36 -0
- package/src/index.js +19 -3
- package/src/server/api/security.js +53 -0
- package/src/server/api/terminal.js +5 -1
- package/src/server/index.js +1 -0
- package/src/server/services/config-export-service.js +280 -33
- package/src/server/services/pty-manager.js +250 -28
- package/src/server/services/security-config.js +131 -0
- package/src/server/services/terminal-config.js +81 -1
- package/src/server/services/terminal-detector.js +76 -1
- package/src/server/websocket-server.js +14 -3
- package/dist/web/assets/index-DOsR4qc6.js +0 -14
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{S as t}from"./vue-vendor-
|
|
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{
|
|
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};
|
package/dist/web/index.html
CHANGED
|
@@ -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-
|
|
9
|
-
<link rel="modulepreload" crossorigin href="/assets/vue-vendor-
|
|
10
|
-
<link rel="modulepreload" crossorigin href="/assets/vendors-
|
|
11
|
-
<link rel="modulepreload" crossorigin href="/assets/icons-
|
|
12
|
-
<link rel="modulepreload" crossorigin href="/assets/naive-ui-
|
|
13
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
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.
|
|
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({
|
package/src/server/index.js
CHANGED
|
@@ -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 =
|
|
42
|
-
const agents = agentsService.
|
|
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
|
|
46
|
-
const skills = skillService.getAllSkills();
|
|
207
|
+
const skills = exportSkillsSnapshot();
|
|
47
208
|
|
|
48
209
|
// 获取 Commands 配置
|
|
49
|
-
const commandsService =
|
|
50
|
-
const commands = commandsService.
|
|
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 =
|
|
54
|
-
const rules = rulesService.
|
|
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
|
|
433
|
+
if (agents && agents.length > 0) {
|
|
255
434
|
try {
|
|
256
|
-
const agentsService =
|
|
435
|
+
const agentsService = new AgentsService();
|
|
436
|
+
const baseDir = agentsService.userAgentsDir;
|
|
437
|
+
|
|
257
438
|
for (const agent of agents) {
|
|
258
|
-
|
|
259
|
-
|
|
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
|
-
}
|
|
262
|
-
|
|
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
|
|
460
|
+
if (skills && skills.length > 0) {
|
|
273
461
|
try {
|
|
274
|
-
const skillService =
|
|
462
|
+
const skillService = new SkillService();
|
|
463
|
+
const baseDir = skillService.installDir;
|
|
464
|
+
ensureDir(baseDir);
|
|
465
|
+
|
|
275
466
|
for (const skill of skills) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
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
|
|
517
|
+
if (commands && commands.length > 0) {
|
|
291
518
|
try {
|
|
292
|
-
const commandsService =
|
|
519
|
+
const commandsService = new CommandsService();
|
|
520
|
+
const baseDir = commandsService.userCommandsDir;
|
|
521
|
+
|
|
293
522
|
for (const command of commands) {
|
|
294
|
-
|
|
295
|
-
|
|
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
|
-
}
|
|
298
|
-
|
|
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
|
|
545
|
+
if (rules && rules.length > 0) {
|
|
309
546
|
try {
|
|
310
|
-
const rulesService =
|
|
547
|
+
const rulesService = new RulesService();
|
|
548
|
+
const baseDir = rulesService.userRulesDir;
|
|
549
|
+
|
|
311
550
|
for (const rule of rules) {
|
|
312
|
-
|
|
313
|
-
|
|
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
|
-
}
|
|
316
|
-
|
|
561
|
+
} else if (status === 'skipped') {
|
|
562
|
+
results.rules.skipped++;
|
|
563
|
+
} else {
|
|
317
564
|
results.rules.failed++;
|
|
318
565
|
}
|
|
319
566
|
}
|