@adversity/coding-tool-x 2.4.2 → 2.5.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.
@@ -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-DZjidyED.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-CvHZsWbE.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.1",
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",
@@ -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();
@@ -4,23 +4,74 @@
4
4
 
5
5
  const express = require('express');
6
6
  const configExportService = require('../services/config-export-service');
7
+ const AdmZip = require('adm-zip');
7
8
 
8
9
  const router = express.Router();
9
10
 
11
+ function parseConfigZip(buffer) {
12
+ const zip = new AdmZip(buffer);
13
+ const entry = zip.getEntry('config.json');
14
+ if (!entry) {
15
+ throw new Error('配置包缺少 config.json');
16
+ }
17
+ const content = entry.getData().toString('utf8');
18
+ return JSON.parse(content);
19
+ }
20
+
21
+ function buildPreviewSummary(data) {
22
+ return {
23
+ version: data.version,
24
+ exportedAt: data.exportedAt,
25
+ counts: {
26
+ permissionTemplates: (data.data.permissionTemplates || []).length,
27
+ configTemplates: (data.data.configTemplates || []).length,
28
+ channels: (data.data.channels || []).length
29
+ },
30
+ items: {
31
+ permissionTemplates: (data.data.permissionTemplates || []).map(t => ({
32
+ id: t.id,
33
+ name: t.name,
34
+ description: t.description
35
+ })),
36
+ configTemplates: (data.data.configTemplates || []).map(t => ({
37
+ id: t.id,
38
+ name: t.name,
39
+ description: t.description
40
+ })),
41
+ channels: (data.data.channels || []).map(c => ({
42
+ id: c.id,
43
+ name: c.name,
44
+ type: c.type
45
+ }))
46
+ }
47
+ };
48
+ }
49
+
10
50
  /**
11
51
  * 导出所有配置
12
52
  * GET /api/config-export
13
53
  */
14
54
  router.get('/', (req, res) => {
15
55
  try {
16
- const result = configExportService.exportAllConfigs();
56
+ const format = (req.query.format || 'json').toLowerCase();
57
+ const result = format === 'zip'
58
+ ? configExportService.exportAllConfigsZip()
59
+ : configExportService.exportAllConfigs();
17
60
 
18
61
  if (result.success) {
19
- // 设置响应头,触发文件下载
20
- const filename = `ctx-config-${new Date().toISOString().split('T')[0]}.json`;
21
- res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
22
- res.setHeader('Content-Type', 'application/json');
23
- res.json(result.data);
62
+ if (format === 'zip') {
63
+ // 设置响应头,触发文件下载
64
+ const filename = result.filename || `ctx-config-${new Date().toISOString().split('T')[0]}.zip`;
65
+ res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
66
+ res.setHeader('Content-Type', 'application/zip');
67
+ res.send(result.data);
68
+ } else {
69
+ // 设置响应头,触发文件下载
70
+ const filename = `ctx-config-${new Date().toISOString().split('T')[0]}.json`;
71
+ res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
72
+ res.setHeader('Content-Type', 'application/json');
73
+ res.json(result.data);
74
+ }
24
75
  } else {
25
76
  res.status(500).json({
26
77
  success: false,
@@ -64,6 +115,34 @@ router.post('/import', (req, res) => {
64
115
  }
65
116
  });
66
117
 
118
+ /**
119
+ * 导入 ZIP 配置
120
+ * POST /api/config-export/import-zip
121
+ */
122
+ router.post('/import-zip', express.raw({ type: ['application/zip', 'application/octet-stream'], limit: '100mb' }), (req, res) => {
123
+ try {
124
+ const overwrite = req.query.overwrite === 'true';
125
+ const buffer = req.body;
126
+
127
+ if (!Buffer.isBuffer(buffer) || buffer.length === 0) {
128
+ return res.status(400).json({
129
+ success: false,
130
+ message: '缺少 ZIP 文件内容'
131
+ });
132
+ }
133
+
134
+ const data = parseConfigZip(buffer);
135
+ const result = configExportService.importConfigs(data, { overwrite });
136
+ res.json(result);
137
+ } catch (err) {
138
+ console.error('[ConfigExport API] 导入 ZIP 失败:', err);
139
+ res.status(500).json({
140
+ success: false,
141
+ message: err.message
142
+ });
143
+ }
144
+ });
145
+
67
146
  /**
68
147
  * 预览导入配置(不实际导入)
69
148
  * POST /api/config-export/preview
@@ -79,32 +158,7 @@ router.post('/preview', (req, res) => {
79
158
  });
80
159
  }
81
160
 
82
- const summary = {
83
- version: data.version,
84
- exportedAt: data.exportedAt,
85
- counts: {
86
- permissionTemplates: (data.data.permissionTemplates || []).length,
87
- configTemplates: (data.data.configTemplates || []).length,
88
- channels: (data.data.channels || []).length
89
- },
90
- items: {
91
- permissionTemplates: (data.data.permissionTemplates || []).map(t => ({
92
- id: t.id,
93
- name: t.name,
94
- description: t.description
95
- })),
96
- configTemplates: (data.data.configTemplates || []).map(t => ({
97
- id: t.id,
98
- name: t.name,
99
- description: t.description
100
- })),
101
- channels: (data.data.channels || []).map(c => ({
102
- id: c.id,
103
- name: c.name,
104
- type: c.type
105
- }))
106
- }
107
- };
161
+ const summary = buildPreviewSummary(data);
108
162
 
109
163
  res.json({
110
164
  success: true,
@@ -119,4 +173,40 @@ router.post('/preview', (req, res) => {
119
173
  }
120
174
  });
121
175
 
176
+ /**
177
+ * 预览 ZIP 导入配置(不实际导入)
178
+ * POST /api/config-export/preview-zip
179
+ */
180
+ router.post('/preview-zip', express.raw({ type: ['application/zip', 'application/octet-stream'], limit: '100mb' }), (req, res) => {
181
+ try {
182
+ const buffer = req.body;
183
+ if (!Buffer.isBuffer(buffer) || buffer.length === 0) {
184
+ return res.status(400).json({
185
+ success: false,
186
+ message: '缺少 ZIP 文件内容'
187
+ });
188
+ }
189
+
190
+ const data = parseConfigZip(buffer);
191
+ if (!data || !data.data) {
192
+ return res.status(400).json({
193
+ success: false,
194
+ message: '无效的导入数据格式'
195
+ });
196
+ }
197
+
198
+ const summary = buildPreviewSummary(data);
199
+ res.json({
200
+ success: true,
201
+ data: summary
202
+ });
203
+ } catch (err) {
204
+ console.error('[ConfigExport API] 预览 ZIP 失败:', err);
205
+ res.status(500).json({
206
+ success: false,
207
+ message: err.message
208
+ });
209
+ }
210
+ });
211
+
122
212
  module.exports = router;
@@ -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'));