@coze-arch/cli 0.0.5-alpha.5dd55b → 0.0.5-alpha.6339fe
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/lib/__templates__/nuxt-vue/nuxt.config.ts +13 -0
- package/lib/__templates__/taro/eslint.config.mjs +2 -8
- package/lib/__templates__/taro/package.json +1 -1
- package/lib/__templates__/taro/pnpm-lock.yaml +5 -5
- package/lib/__templates__/taro/src/app.tsx +1 -6
- package/lib/__templates__/taro/src/components/ui/accordion.tsx +1 -1
- package/lib/__templates__/taro/src/components/ui/breadcrumb.tsx +1 -1
- package/lib/__templates__/taro/src/components/ui/calendar.tsx +4 -4
- package/lib/__templates__/taro/src/components/ui/carousel.tsx +2 -2
- package/lib/__templates__/taro/src/components/ui/command.tsx +1 -1
- package/lib/__templates__/taro/src/components/ui/context-menu.tsx +3 -3
- package/lib/__templates__/taro/src/components/ui/dialog.tsx +1 -1
- package/lib/__templates__/taro/src/components/ui/dropdown-menu.tsx +3 -3
- package/lib/__templates__/taro/src/components/ui/input-otp.tsx +1 -1
- package/lib/__templates__/taro/src/components/ui/menubar.tsx +3 -3
- package/lib/__templates__/taro/src/components/ui/navigation-menu.tsx +0 -2
- package/lib/__templates__/taro/src/components/ui/pagination.tsx +3 -3
- package/lib/__templates__/taro/src/components/ui/resizable.tsx +1 -1
- package/lib/__templates__/taro/src/components/ui/select.tsx +4 -4
- package/lib/__templates__/taro/src/components/ui/sheet.tsx +1 -1
- package/lib/__templates__/taro/src/components/ui/toast.tsx +1 -1
- package/lib/cli.js +968 -122
- package/package.json +2 -1
- package/lib/__templates__/taro/components.md +0 -1686
package/lib/cli.js
CHANGED
|
@@ -15,6 +15,7 @@ var fs$1 = require('fs/promises');
|
|
|
15
15
|
var os = require('os');
|
|
16
16
|
var jsYaml = require('js-yaml');
|
|
17
17
|
var toml = require('@iarna/toml');
|
|
18
|
+
var fastGlob = require('fast-glob');
|
|
18
19
|
var child_process = require('child_process');
|
|
19
20
|
var addFormats = require('ajv-formats');
|
|
20
21
|
var Ajv = require('ajv');
|
|
@@ -1490,7 +1491,7 @@ var browserClient = createBaseClient();
|
|
|
1490
1491
|
|
|
1491
1492
|
|
|
1492
1493
|
|
|
1493
|
-
const log$
|
|
1494
|
+
const log$6 = debug('slardar:transport');
|
|
1494
1495
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
1495
1496
|
const noop = () => {};
|
|
1496
1497
|
|
|
@@ -1510,22 +1511,22 @@ const noop = () => {};
|
|
|
1510
1511
|
function makeRequest(options) {
|
|
1511
1512
|
const { url, method, data, success = noop, fail = noop, getResponseText = noop } = options;
|
|
1512
1513
|
|
|
1513
|
-
log$
|
|
1514
|
+
log$6('Making %s request to %s', method, url);
|
|
1514
1515
|
if (data) {
|
|
1515
|
-
log$
|
|
1516
|
+
log$6('Request data: %s', data.slice(0, 200));
|
|
1516
1517
|
}
|
|
1517
1518
|
|
|
1518
1519
|
// 检查 URL 是否有效
|
|
1519
1520
|
if (!url || typeof url !== 'string') {
|
|
1520
1521
|
const error = new Error(`Invalid URL: ${url}`);
|
|
1521
|
-
log$
|
|
1522
|
+
log$6('Invalid URL provided: %o', url);
|
|
1522
1523
|
fail(error);
|
|
1523
1524
|
return;
|
|
1524
1525
|
}
|
|
1525
1526
|
|
|
1526
1527
|
try {
|
|
1527
1528
|
const urlObj = new URL(url);
|
|
1528
|
-
log$
|
|
1529
|
+
log$6('Parsed URL - protocol: %s, hostname: %s, port: %s, path: %s',
|
|
1529
1530
|
urlObj.protocol, urlObj.hostname, urlObj.port, urlObj.pathname);
|
|
1530
1531
|
|
|
1531
1532
|
const isHttps = urlObj.protocol === 'https:';
|
|
@@ -1543,34 +1544,34 @@ function makeRequest(options) {
|
|
|
1543
1544
|
},
|
|
1544
1545
|
},
|
|
1545
1546
|
res => {
|
|
1546
|
-
log$
|
|
1547
|
+
log$6('Response callback triggered: status=%s', res.statusCode);
|
|
1547
1548
|
let responseText = '';
|
|
1548
1549
|
|
|
1549
1550
|
res.on('data', chunk => {
|
|
1550
|
-
log$
|
|
1551
|
+
log$6('Response data chunk received: %s bytes', chunk.length);
|
|
1551
1552
|
responseText += chunk.toString();
|
|
1552
1553
|
});
|
|
1553
1554
|
|
|
1554
1555
|
res.on('end', () => {
|
|
1555
|
-
log$
|
|
1556
|
-
log$
|
|
1556
|
+
log$6('Response end event fired');
|
|
1557
|
+
log$6('Response received: status=%s, body=%s', res.statusCode, responseText.slice(0, 200));
|
|
1557
1558
|
getResponseText(responseText);
|
|
1558
1559
|
|
|
1559
1560
|
try {
|
|
1560
1561
|
if (res.statusCode && res.statusCode >= 400) {
|
|
1561
|
-
log$
|
|
1562
|
+
log$6('Request failed with status %s: %s', res.statusCode, responseText);
|
|
1562
1563
|
fail(new Error(responseText || res.statusMessage || 'Request failed'));
|
|
1563
1564
|
} else if (responseText) {
|
|
1564
1565
|
// eslint-disable-next-line no-restricted-syntax -- Parsing trusted Slardar API responses
|
|
1565
1566
|
const result = JSON.parse(responseText);
|
|
1566
|
-
log$
|
|
1567
|
+
log$6('Request succeeded');
|
|
1567
1568
|
success(result);
|
|
1568
1569
|
} else {
|
|
1569
|
-
log$
|
|
1570
|
+
log$6('Request succeeded with empty response');
|
|
1570
1571
|
success({});
|
|
1571
1572
|
}
|
|
1572
1573
|
} catch (e) {
|
|
1573
|
-
log$
|
|
1574
|
+
log$6('Failed to parse response: %s', (e ).message);
|
|
1574
1575
|
fail(e );
|
|
1575
1576
|
}
|
|
1576
1577
|
});
|
|
@@ -1578,12 +1579,12 @@ function makeRequest(options) {
|
|
|
1578
1579
|
);
|
|
1579
1580
|
|
|
1580
1581
|
req.on('error', err => {
|
|
1581
|
-
log$
|
|
1582
|
+
log$6('Request error: %s', err.message);
|
|
1582
1583
|
fail(err);
|
|
1583
1584
|
});
|
|
1584
1585
|
|
|
1585
1586
|
req.on('timeout', () => {
|
|
1586
|
-
log$
|
|
1587
|
+
log$6('Request timeout');
|
|
1587
1588
|
req.destroy();
|
|
1588
1589
|
fail(new Error('Request timeout'));
|
|
1589
1590
|
});
|
|
@@ -1594,7 +1595,7 @@ function makeRequest(options) {
|
|
|
1594
1595
|
|
|
1595
1596
|
req.end();
|
|
1596
1597
|
} catch (e) {
|
|
1597
|
-
log$
|
|
1598
|
+
log$6('Exception during request: %s', (e ).message);
|
|
1598
1599
|
fail(e );
|
|
1599
1600
|
}
|
|
1600
1601
|
}
|
|
@@ -1605,14 +1606,14 @@ function makeRequest(options) {
|
|
|
1605
1606
|
function createNodeTransport() {
|
|
1606
1607
|
return {
|
|
1607
1608
|
get(options) {
|
|
1608
|
-
log$
|
|
1609
|
+
log$6('Transport GET called: %s', options.url);
|
|
1609
1610
|
makeRequest({
|
|
1610
1611
|
method: 'GET',
|
|
1611
1612
|
...options,
|
|
1612
1613
|
});
|
|
1613
1614
|
},
|
|
1614
1615
|
post({ url, data }) {
|
|
1615
|
-
log$
|
|
1616
|
+
log$6('Transport POST called: %s', url);
|
|
1616
1617
|
makeRequest({
|
|
1617
1618
|
method: 'POST',
|
|
1618
1619
|
url,
|
|
@@ -1633,7 +1634,7 @@ function _nullishCoalesce$3(lhs, rhsFn) { if (lhs != null) { return lhs; } else
|
|
|
1633
1634
|
|
|
1634
1635
|
// 创建 debug 实例
|
|
1635
1636
|
// 使用方式: DEBUG=slardar:* your-cli-command
|
|
1636
|
-
const log$
|
|
1637
|
+
const log$5 = debug('slardar:reporter');
|
|
1637
1638
|
|
|
1638
1639
|
/**
|
|
1639
1640
|
* Slardar CLI Reporter
|
|
@@ -1658,12 +1659,12 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
|
|
|
1658
1659
|
*/
|
|
1659
1660
|
setup(config) {
|
|
1660
1661
|
if (this.initialized) {
|
|
1661
|
-
log$
|
|
1662
|
+
log$5('Already initialized, skipping setup');
|
|
1662
1663
|
return;
|
|
1663
1664
|
}
|
|
1664
1665
|
|
|
1665
1666
|
try {
|
|
1666
|
-
log$
|
|
1667
|
+
log$5('Initializing Slardar with config:', {
|
|
1667
1668
|
bid: config.bid,
|
|
1668
1669
|
release: config.release,
|
|
1669
1670
|
env: config.env,
|
|
@@ -1696,7 +1697,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
|
|
|
1696
1697
|
|
|
1697
1698
|
// 添加 send 钩子来追踪事件上报
|
|
1698
1699
|
this.client.on('send', (ev) => {
|
|
1699
|
-
log$
|
|
1700
|
+
log$5(
|
|
1700
1701
|
'send hook called for event: %s',
|
|
1701
1702
|
(_optionalChain$6([ev, 'optionalAccess', _ => _.ev_type]) ) || 'unknown',
|
|
1702
1703
|
);
|
|
@@ -1704,9 +1705,9 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
|
|
|
1704
1705
|
|
|
1705
1706
|
this.client.start();
|
|
1706
1707
|
this.initialized = true;
|
|
1707
|
-
log$
|
|
1708
|
+
log$5('Slardar initialized successfully');
|
|
1708
1709
|
} catch (error) {
|
|
1709
|
-
log$
|
|
1710
|
+
log$5('Failed to initialize:', error);
|
|
1710
1711
|
}
|
|
1711
1712
|
}
|
|
1712
1713
|
|
|
@@ -1715,7 +1716,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
|
|
|
1715
1716
|
*/
|
|
1716
1717
|
ensureInitialized() {
|
|
1717
1718
|
if (!this.initialized) {
|
|
1718
|
-
log$
|
|
1719
|
+
log$5('Not initialized, call setup() first');
|
|
1719
1720
|
return false;
|
|
1720
1721
|
}
|
|
1721
1722
|
return true;
|
|
@@ -1737,7 +1738,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
|
|
|
1737
1738
|
}
|
|
1738
1739
|
|
|
1739
1740
|
try {
|
|
1740
|
-
log$
|
|
1741
|
+
log$5('Sending event:', { name, metrics, categories });
|
|
1741
1742
|
|
|
1742
1743
|
// 过滤掉 undefined 值以满足 Slardar 类型要求
|
|
1743
1744
|
const cleanMetrics = metrics
|
|
@@ -1762,7 +1763,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
|
|
|
1762
1763
|
categories: cleanCategories ,
|
|
1763
1764
|
})]);
|
|
1764
1765
|
} catch (error) {
|
|
1765
|
-
log$
|
|
1766
|
+
log$5('Failed to send event:', error);
|
|
1766
1767
|
}
|
|
1767
1768
|
}
|
|
1768
1769
|
|
|
@@ -1782,7 +1783,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
|
|
|
1782
1783
|
}
|
|
1783
1784
|
|
|
1784
1785
|
try {
|
|
1785
|
-
log$
|
|
1786
|
+
log$5('Sending log:', { level, message, extra });
|
|
1786
1787
|
// 使用 sendEvent 发送日志事件
|
|
1787
1788
|
this.sendEvent('cli_log', undefined, {
|
|
1788
1789
|
level,
|
|
@@ -1790,7 +1791,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
|
|
|
1790
1791
|
...extra,
|
|
1791
1792
|
});
|
|
1792
1793
|
} catch (error) {
|
|
1793
|
-
log$
|
|
1794
|
+
log$5('Failed to send log:', error);
|
|
1794
1795
|
}
|
|
1795
1796
|
}
|
|
1796
1797
|
|
|
@@ -1824,7 +1825,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
|
|
|
1824
1825
|
},
|
|
1825
1826
|
};
|
|
1826
1827
|
|
|
1827
|
-
log$
|
|
1828
|
+
log$5('Reporting JS error:', {
|
|
1828
1829
|
name: error.name,
|
|
1829
1830
|
message: error.message.slice(0, 100),
|
|
1830
1831
|
stack: _optionalChain$6([error, 'access', _5 => _5.stack, 'optionalAccess', _6 => _6.slice, 'call', _7 => _7(0, 200)]),
|
|
@@ -1834,9 +1835,9 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
|
|
|
1834
1835
|
|
|
1835
1836
|
// 使用 Slardar 的 js_error 事件类型,这样会显示在 JS 错误总览页面
|
|
1836
1837
|
this.client.report(errorEvent);
|
|
1837
|
-
log$
|
|
1838
|
+
log$5('JS error reported successfully');
|
|
1838
1839
|
} catch (err) {
|
|
1839
|
-
log$
|
|
1840
|
+
log$5('Failed to report error:', err);
|
|
1840
1841
|
}
|
|
1841
1842
|
}
|
|
1842
1843
|
|
|
@@ -1857,7 +1858,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
|
|
|
1857
1858
|
if (!this.ensureInitialized()) {
|
|
1858
1859
|
return;
|
|
1859
1860
|
}
|
|
1860
|
-
log$
|
|
1861
|
+
log$5('Merging context:', context);
|
|
1861
1862
|
_optionalChain$6([this, 'access', _12 => _12.client, 'access', _13 => _13.context, 'optionalAccess', _14 => _14.merge, 'call', _15 => _15(context)]);
|
|
1862
1863
|
}
|
|
1863
1864
|
|
|
@@ -1894,7 +1895,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
|
|
|
1894
1895
|
}
|
|
1895
1896
|
|
|
1896
1897
|
try {
|
|
1897
|
-
log$
|
|
1898
|
+
log$5('Updating config:', config);
|
|
1898
1899
|
this.client.config({
|
|
1899
1900
|
userId: config.userId,
|
|
1900
1901
|
release: config.release,
|
|
@@ -1902,7 +1903,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
|
|
|
1902
1903
|
env: config.env,
|
|
1903
1904
|
});
|
|
1904
1905
|
} catch (error) {
|
|
1905
|
-
log$
|
|
1906
|
+
log$5('Failed to update config:', error);
|
|
1906
1907
|
}
|
|
1907
1908
|
}
|
|
1908
1909
|
|
|
@@ -1914,11 +1915,11 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
|
|
|
1914
1915
|
if (!this.ensureInitialized()) {
|
|
1915
1916
|
return;
|
|
1916
1917
|
}
|
|
1917
|
-
log$
|
|
1918
|
+
log$5('Flushing Slardar data...');
|
|
1918
1919
|
_optionalChain$6([this, 'access', _24 => _24.client, 'access', _25 => _25.getSender, 'optionalCall', _26 => _26(), 'optionalAccess', _27 => _27.flush, 'call', _28 => _28()]);
|
|
1919
|
-
log$
|
|
1920
|
+
log$5('Waiting %dms for events to be sent...', waitMs);
|
|
1920
1921
|
await new Promise(resolve => setTimeout(resolve, waitMs));
|
|
1921
|
-
log$
|
|
1922
|
+
log$5('Slardar data flushed');
|
|
1922
1923
|
}
|
|
1923
1924
|
|
|
1924
1925
|
/**
|
|
@@ -2105,7 +2106,7 @@ const EventBuilder = {
|
|
|
2105
2106
|
};
|
|
2106
2107
|
|
|
2107
2108
|
var name = "@coze-arch/cli";
|
|
2108
|
-
var version = "0.0.5-alpha.
|
|
2109
|
+
var version = "0.0.5-alpha.6339fe";
|
|
2109
2110
|
var description = "coze coding devtools cli";
|
|
2110
2111
|
var license = "MIT";
|
|
2111
2112
|
var author = "fanwenjie.fe@bytedance.com";
|
|
@@ -2145,6 +2146,7 @@ var dependencies = {
|
|
|
2145
2146
|
commander: "~12.1.0",
|
|
2146
2147
|
debug: "^4.3.7",
|
|
2147
2148
|
ejs: "^3.1.10",
|
|
2149
|
+
"fast-glob": "^3.3.3",
|
|
2148
2150
|
"js-yaml": "^4.1.0",
|
|
2149
2151
|
minimist: "^1.2.5",
|
|
2150
2152
|
shelljs: "^0.10.0"
|
|
@@ -2209,7 +2211,7 @@ function _optionalChain$4(ops) { let lastAccessLHS = undefined; let value = ops[
|
|
|
2209
2211
|
* Slardar 监控初始化和上报
|
|
2210
2212
|
*/
|
|
2211
2213
|
|
|
2212
|
-
const log = debug('slardar:cli');
|
|
2214
|
+
const log$4 = debug('slardar:cli');
|
|
2213
2215
|
|
|
2214
2216
|
/**
|
|
2215
2217
|
* 安全执行函数包装器
|
|
@@ -2222,18 +2224,18 @@ function safeRun(
|
|
|
2222
2224
|
) {
|
|
2223
2225
|
return ((...args) => {
|
|
2224
2226
|
try {
|
|
2225
|
-
log('Calling Slardar function: %s', name);
|
|
2227
|
+
log$4('Calling Slardar function: %s', name);
|
|
2226
2228
|
const result = fn(...args);
|
|
2227
2229
|
|
|
2228
2230
|
// 如果是 Promise,处理异步错误
|
|
2229
2231
|
if (result instanceof Promise) {
|
|
2230
2232
|
return result
|
|
2231
2233
|
.then(res => {
|
|
2232
|
-
log('Slardar function %s completed', name);
|
|
2234
|
+
log$4('Slardar function %s completed', name);
|
|
2233
2235
|
return res;
|
|
2234
2236
|
})
|
|
2235
2237
|
.catch(error => {
|
|
2236
|
-
log(
|
|
2238
|
+
log$4(
|
|
2237
2239
|
'Slardar function %s failed: %s',
|
|
2238
2240
|
name,
|
|
2239
2241
|
(error ).message,
|
|
@@ -2242,11 +2244,11 @@ function safeRun(
|
|
|
2242
2244
|
});
|
|
2243
2245
|
}
|
|
2244
2246
|
|
|
2245
|
-
log('Slardar function %s completed', name);
|
|
2247
|
+
log$4('Slardar function %s completed', name);
|
|
2246
2248
|
return result;
|
|
2247
2249
|
} catch (error) {
|
|
2248
2250
|
// Slardar 上报失败不应影响 CLI 正常运行,但要记录错误
|
|
2249
|
-
log('Slardar function %s failed: %s', name, (error ).message);
|
|
2251
|
+
log$4('Slardar function %s failed: %s', name, (error ).message);
|
|
2250
2252
|
}
|
|
2251
2253
|
}) ;
|
|
2252
2254
|
}
|
|
@@ -2810,6 +2812,76 @@ const registerCommand$4 = program => {
|
|
|
2810
2812
|
});
|
|
2811
2813
|
};
|
|
2812
2814
|
|
|
2815
|
+
// ABOUTME: Temporary paths utility for Coze CLI
|
|
2816
|
+
// ABOUTME: Provides centralized management of temporary directories and files
|
|
2817
|
+
|
|
2818
|
+
|
|
2819
|
+
/**
|
|
2820
|
+
* Base Coze directory in user's home
|
|
2821
|
+
* Used for storing CLI-related temporary files, logs, and cache
|
|
2822
|
+
* Default: ~/.coze
|
|
2823
|
+
*/
|
|
2824
|
+
const COZE_HOME_DIR = '.coze';
|
|
2825
|
+
|
|
2826
|
+
/**
|
|
2827
|
+
* Logs directory name
|
|
2828
|
+
* Default: .coze-logs
|
|
2829
|
+
*/
|
|
2830
|
+
const LOGS_DIR = '.coze-logs';
|
|
2831
|
+
|
|
2832
|
+
/**
|
|
2833
|
+
* Get the Coze home directory path
|
|
2834
|
+
* Can be customized via COZE_HOME environment variable
|
|
2835
|
+
*
|
|
2836
|
+
* @returns Absolute path to Coze home directory (default: ~/.coze)
|
|
2837
|
+
*/
|
|
2838
|
+
const getCozeHome = () =>
|
|
2839
|
+
process.env.COZE_HOME || path.join(os.homedir(), COZE_HOME_DIR);
|
|
2840
|
+
|
|
2841
|
+
/**
|
|
2842
|
+
* Get the logs directory path
|
|
2843
|
+
* Can be customized via COZE_LOG_DIR environment variable
|
|
2844
|
+
*
|
|
2845
|
+
* @returns Absolute path to logs directory (default: ~/.coze-logs)
|
|
2846
|
+
*/
|
|
2847
|
+
const getCozeLogsDir = () =>
|
|
2848
|
+
process.env.COZE_LOG_DIR || path.join(os.homedir(), LOGS_DIR);
|
|
2849
|
+
|
|
2850
|
+
/**
|
|
2851
|
+
* Get path for a specific file/directory within Coze home
|
|
2852
|
+
*
|
|
2853
|
+
* @param relativePath - Relative path within Coze home directory
|
|
2854
|
+
* @returns Absolute path to the file/directory
|
|
2855
|
+
*
|
|
2856
|
+
* @example
|
|
2857
|
+
* ```ts
|
|
2858
|
+
* // Get routes file path
|
|
2859
|
+
* const routesPath = getCozeFilePath('routes.json');
|
|
2860
|
+
* // Returns: ~/.coze/routes.json
|
|
2861
|
+
*
|
|
2862
|
+
* // Get cache directory
|
|
2863
|
+
* const cacheDir = getCozeFilePath('cache');
|
|
2864
|
+
* // Returns: ~/.coze/cache
|
|
2865
|
+
* ```
|
|
2866
|
+
*/
|
|
2867
|
+
const getCozeFilePath = (relativePath) =>
|
|
2868
|
+
path.join(getCozeHome(), relativePath);
|
|
2869
|
+
|
|
2870
|
+
/**
|
|
2871
|
+
* Get path for a log file
|
|
2872
|
+
*
|
|
2873
|
+
* @param filename - Log file name
|
|
2874
|
+
* @returns Absolute path to the log file
|
|
2875
|
+
*
|
|
2876
|
+
* @example
|
|
2877
|
+
* ```ts
|
|
2878
|
+
* const devLog = getCozeLogPath('dev.log');
|
|
2879
|
+
* // Returns: ~/.coze-logs/dev.log
|
|
2880
|
+
* ```
|
|
2881
|
+
*/
|
|
2882
|
+
const getCozeLogPath = (filename) =>
|
|
2883
|
+
path.join(getCozeLogsDir(), filename);
|
|
2884
|
+
|
|
2813
2885
|
// ABOUTME: This file implements the update command for coze CLI
|
|
2814
2886
|
// ABOUTME: It wraps pnpm update/install to update package dependencies with logging support
|
|
2815
2887
|
|
|
@@ -2820,29 +2892,22 @@ const registerCommand$4 = program => {
|
|
|
2820
2892
|
*/
|
|
2821
2893
|
const LOG_FILE_NAME$1 = 'update.log';
|
|
2822
2894
|
|
|
2823
|
-
/**
|
|
2824
|
-
* 获取日志目录
|
|
2825
|
-
* 优先使用环境变量 COZE_LOG_DIR,否则使用 ~/.coze-logs
|
|
2826
|
-
*/
|
|
2827
|
-
const getLogDir$1 = () =>
|
|
2828
|
-
process.env.COZE_LOG_DIR || path.join(os.homedir(), '.coze-logs');
|
|
2829
|
-
|
|
2830
2895
|
/**
|
|
2831
2896
|
* 解析日志文件路径
|
|
2832
2897
|
* - 如果是绝对路径,直接使用
|
|
2833
|
-
* - 如果是相对路径,基于
|
|
2834
|
-
* -
|
|
2898
|
+
* - 如果是相对路径,基于 logs 目录 + 相对路径
|
|
2899
|
+
* - 如果为空,使用默认日志文件路径
|
|
2835
2900
|
*/
|
|
2836
2901
|
const resolveLogFilePath$1 = (logFile) => {
|
|
2837
2902
|
if (!logFile) {
|
|
2838
|
-
return
|
|
2903
|
+
return getCozeLogPath(LOG_FILE_NAME$1);
|
|
2839
2904
|
}
|
|
2840
2905
|
|
|
2841
2906
|
if (path.isAbsolute(logFile)) {
|
|
2842
2907
|
return logFile;
|
|
2843
2908
|
}
|
|
2844
2909
|
|
|
2845
|
-
return
|
|
2910
|
+
return getCozeLogPath(logFile);
|
|
2846
2911
|
};
|
|
2847
2912
|
|
|
2848
2913
|
/**
|
|
@@ -3016,6 +3081,7 @@ const handleUpdateError = (
|
|
|
3016
3081
|
/**
|
|
3017
3082
|
* 执行 update 命令的内部实现
|
|
3018
3083
|
*/
|
|
3084
|
+
// eslint-disable-next-line max-lines-per-function
|
|
3019
3085
|
const executeUpdate = (
|
|
3020
3086
|
packageName,
|
|
3021
3087
|
options
|
|
@@ -3629,35 +3695,805 @@ const registerCommand$2 = program => {
|
|
|
3629
3695
|
});
|
|
3630
3696
|
};
|
|
3631
3697
|
|
|
3632
|
-
|
|
3698
|
+
// ABOUTME: Nuxt route scanner
|
|
3699
|
+
// ABOUTME: Scans Nuxt file-based routing structure to extract page and server routes
|
|
3700
|
+
|
|
3701
|
+
|
|
3702
|
+
|
|
3703
|
+
|
|
3704
|
+
const log$3 = debug('coze:route-scanner:nuxt');
|
|
3705
|
+
|
|
3633
3706
|
/**
|
|
3634
|
-
*
|
|
3707
|
+
* Convert Nuxt file path to route path
|
|
3708
|
+
* Examples:
|
|
3709
|
+
* - app/pages/index.vue -> /
|
|
3710
|
+
* - pages/index.vue -> /
|
|
3711
|
+
* - app/pages/blog/index.vue -> /blog
|
|
3712
|
+
* - pages/blog/[id].vue -> /blog/[id]
|
|
3713
|
+
* - server/api/users.ts -> /api/users
|
|
3714
|
+
* - server/routes/webhook.ts -> /webhook
|
|
3635
3715
|
*/
|
|
3636
|
-
const
|
|
3716
|
+
const nuxtFilePathToRoute = (
|
|
3717
|
+
filePath,
|
|
3718
|
+
type,
|
|
3719
|
+
) => {
|
|
3720
|
+
let route;
|
|
3721
|
+
|
|
3722
|
+
if (type === 'page') {
|
|
3723
|
+
// Remove pages prefix (supports both app/pages/ and pages/) and .vue extension
|
|
3724
|
+
route = filePath
|
|
3725
|
+
.replace(/^app\/pages\//, '')
|
|
3726
|
+
.replace(/^pages\//, '')
|
|
3727
|
+
.replace(/\.vue$/, '')
|
|
3728
|
+
.replace(/\/index$/, ''); // Remove trailing /index
|
|
3729
|
+
|
|
3730
|
+
// Handle index.vue at root (becomes empty string)
|
|
3731
|
+
if (route === 'index') {
|
|
3732
|
+
return '/';
|
|
3733
|
+
}
|
|
3734
|
+
} else {
|
|
3735
|
+
// API routes
|
|
3736
|
+
if (filePath.startsWith('server/api/')) {
|
|
3737
|
+
route = `/api/${filePath
|
|
3738
|
+
.replace(/^server\/api\//, '')
|
|
3739
|
+
.replace(/\.(ts|js)$/, '')}`;
|
|
3740
|
+
} else {
|
|
3741
|
+
// server/routes
|
|
3742
|
+
route = `/${filePath
|
|
3743
|
+
.replace(/^server\/routes\//, '')
|
|
3744
|
+
.replace(/\.(ts|js)$/, '')}`;
|
|
3745
|
+
}
|
|
3746
|
+
}
|
|
3747
|
+
|
|
3748
|
+
// Handle root route
|
|
3749
|
+
if (route === '' || route === '/') {
|
|
3750
|
+
return '/';
|
|
3751
|
+
}
|
|
3752
|
+
|
|
3753
|
+
// Ensure leading slash
|
|
3754
|
+
if (!route.startsWith('/')) {
|
|
3755
|
+
route = `/${route}`;
|
|
3756
|
+
}
|
|
3757
|
+
|
|
3758
|
+
return route;
|
|
3759
|
+
};
|
|
3637
3760
|
|
|
3638
3761
|
/**
|
|
3639
|
-
*
|
|
3640
|
-
*
|
|
3762
|
+
* Normalize Nuxt route path to standard format
|
|
3763
|
+
* Converts Nuxt dynamic segments to standard format:
|
|
3764
|
+
* - [id] -> :id
|
|
3765
|
+
* - [...slug] -> :slug*
|
|
3641
3766
|
*/
|
|
3642
|
-
const
|
|
3643
|
-
|
|
3767
|
+
const normalizeRoutePath$1 = (routePath) =>
|
|
3768
|
+
routePath
|
|
3769
|
+
.replace(/\[\.\.\.(\w+)\]/g, ':$1*') // [...slug] -> :slug*
|
|
3770
|
+
.replace(/\[(\w+)\]/g, ':$1'); // [id] -> :id
|
|
3771
|
+
/**
|
|
3772
|
+
* Extract dynamic parameter names from route path
|
|
3773
|
+
*/
|
|
3774
|
+
const extractParams$1 = (routePath) => {
|
|
3775
|
+
const params = [];
|
|
3776
|
+
const patterns = [
|
|
3777
|
+
/\[\.\.\.(\w+)\]/g, // [...slug]
|
|
3778
|
+
/\[(\w+)\]/g, // [id]
|
|
3779
|
+
];
|
|
3780
|
+
|
|
3781
|
+
patterns.forEach(pattern => {
|
|
3782
|
+
const matches = routePath.matchAll(pattern);
|
|
3783
|
+
for (const match of matches) {
|
|
3784
|
+
params.push(match[1]);
|
|
3785
|
+
}
|
|
3786
|
+
});
|
|
3787
|
+
|
|
3788
|
+
return params;
|
|
3789
|
+
};
|
|
3790
|
+
|
|
3791
|
+
/**
|
|
3792
|
+
* Scan Nuxt routes from pages and server directories
|
|
3793
|
+
*
|
|
3794
|
+
* Scans for:
|
|
3795
|
+
* - app/pages/**\/*.vue OR pages/**\/*.vue - Page routes (both structures supported)
|
|
3796
|
+
* - server/api/**\/*.{ts,js} - API routes
|
|
3797
|
+
* - server/routes/**\/*.{ts,js} - Server routes
|
|
3798
|
+
*
|
|
3799
|
+
* Excludes:
|
|
3800
|
+
* - app/layouts/, layouts/ - Layout components (NOT routes)
|
|
3801
|
+
* - app.vue, error.vue - Special files (NOT regular routes)
|
|
3802
|
+
*
|
|
3803
|
+
* @param cwd - Current working directory
|
|
3804
|
+
* @returns List of detected routes
|
|
3805
|
+
*/
|
|
3806
|
+
const scanNuxtRoutes = async (cwd) => {
|
|
3807
|
+
log$3('Scanning Nuxt routes in:', cwd);
|
|
3808
|
+
const routes = [];
|
|
3809
|
+
|
|
3810
|
+
// Scan page routes - support both app/pages/ and pages/ directories
|
|
3811
|
+
const pageFiles = await fastGlob.glob(['{app/,}pages/**/*.vue'], {
|
|
3812
|
+
cwd,
|
|
3813
|
+
ignore: [
|
|
3814
|
+
'**/node_modules/**',
|
|
3815
|
+
'**/.nuxt/**',
|
|
3816
|
+
'**/dist/**',
|
|
3817
|
+
'**/.output/**',
|
|
3818
|
+
// Exclude layouts directory (not routes)
|
|
3819
|
+
'**/layouts/**',
|
|
3820
|
+
'app/layouts/**',
|
|
3821
|
+
// Exclude special files
|
|
3822
|
+
'app.vue',
|
|
3823
|
+
'error.vue',
|
|
3824
|
+
],
|
|
3825
|
+
onlyFiles: true,
|
|
3826
|
+
followSymbolicLinks: false,
|
|
3827
|
+
});
|
|
3828
|
+
|
|
3829
|
+
log$3('Found %d page files', pageFiles.length);
|
|
3830
|
+
|
|
3831
|
+
routes.push(
|
|
3832
|
+
...pageFiles.map(file => {
|
|
3833
|
+
const routePath = nuxtFilePathToRoute(file, 'page');
|
|
3834
|
+
const isDynamic = routePath.includes('[');
|
|
3835
|
+
const params = extractParams$1(routePath);
|
|
3836
|
+
|
|
3837
|
+
return {
|
|
3838
|
+
path: normalizeRoutePath$1(routePath),
|
|
3839
|
+
rawPath: routePath,
|
|
3840
|
+
dynamic: isDynamic,
|
|
3841
|
+
params,
|
|
3842
|
+
type: 'page' ,
|
|
3843
|
+
file,
|
|
3844
|
+
framework: 'nuxt' ,
|
|
3845
|
+
};
|
|
3846
|
+
}),
|
|
3847
|
+
);
|
|
3848
|
+
|
|
3849
|
+
// Scan API routes
|
|
3850
|
+
const apiFiles = await fastGlob.glob('server/api/**/*.{ts,js}', {
|
|
3851
|
+
cwd,
|
|
3852
|
+
ignore: ['**/node_modules/**', '**/dist/**', '**/.output/**'],
|
|
3853
|
+
onlyFiles: true,
|
|
3854
|
+
followSymbolicLinks: false,
|
|
3855
|
+
});
|
|
3856
|
+
|
|
3857
|
+
log$3('Found %d API files', apiFiles.length);
|
|
3858
|
+
|
|
3859
|
+
routes.push(
|
|
3860
|
+
...apiFiles.map(file => {
|
|
3861
|
+
const routePath = nuxtFilePathToRoute(file, 'api');
|
|
3862
|
+
const isDynamic = routePath.includes('[');
|
|
3863
|
+
const params = extractParams$1(routePath);
|
|
3864
|
+
|
|
3865
|
+
return {
|
|
3866
|
+
path: normalizeRoutePath$1(routePath),
|
|
3867
|
+
rawPath: routePath,
|
|
3868
|
+
dynamic: isDynamic,
|
|
3869
|
+
params,
|
|
3870
|
+
type: 'api' ,
|
|
3871
|
+
file,
|
|
3872
|
+
framework: 'nuxt' ,
|
|
3873
|
+
};
|
|
3874
|
+
}),
|
|
3875
|
+
);
|
|
3876
|
+
|
|
3877
|
+
// Scan server routes
|
|
3878
|
+
const serverRouteFiles = await fastGlob.glob('server/routes/**/*.{ts,js}', {
|
|
3879
|
+
cwd,
|
|
3880
|
+
ignore: ['**/node_modules/**', '**/dist/**', '**/.output/**'],
|
|
3881
|
+
onlyFiles: true,
|
|
3882
|
+
followSymbolicLinks: false,
|
|
3883
|
+
});
|
|
3884
|
+
|
|
3885
|
+
log$3('Found %d server route files', serverRouteFiles.length);
|
|
3886
|
+
|
|
3887
|
+
routes.push(
|
|
3888
|
+
...serverRouteFiles.map(file => {
|
|
3889
|
+
const routePath = nuxtFilePathToRoute(file, 'api');
|
|
3890
|
+
const isDynamic = routePath.includes('[');
|
|
3891
|
+
const params = extractParams$1(routePath);
|
|
3892
|
+
|
|
3893
|
+
return {
|
|
3894
|
+
path: normalizeRoutePath$1(routePath),
|
|
3895
|
+
rawPath: routePath,
|
|
3896
|
+
dynamic: isDynamic,
|
|
3897
|
+
params,
|
|
3898
|
+
type: 'api' ,
|
|
3899
|
+
file,
|
|
3900
|
+
framework: 'nuxt' ,
|
|
3901
|
+
};
|
|
3902
|
+
}),
|
|
3903
|
+
);
|
|
3904
|
+
|
|
3905
|
+
log$3('Total routes found: %d', routes.length);
|
|
3906
|
+
return routes;
|
|
3907
|
+
};
|
|
3908
|
+
|
|
3909
|
+
// ABOUTME: Next.js route scanner
|
|
3910
|
+
// ABOUTME: Scans Next.js App Router file structure to extract routes
|
|
3911
|
+
|
|
3912
|
+
|
|
3913
|
+
|
|
3914
|
+
|
|
3915
|
+
const log$2 = debug('coze:route-scanner:nextjs');
|
|
3916
|
+
|
|
3917
|
+
/**
|
|
3918
|
+
* Convert Next.js file path to route path
|
|
3919
|
+
* Examples:
|
|
3920
|
+
* - src/app/page.tsx -> /
|
|
3921
|
+
* - src/app/blog/page.tsx -> /blog
|
|
3922
|
+
* - src/app/blog/[id]/page.tsx -> /blog/[id]
|
|
3923
|
+
* - src/app/api/users/route.ts -> /api/users
|
|
3924
|
+
*/
|
|
3925
|
+
const filePathToRoute = (filePath) => {
|
|
3926
|
+
// Remove src/app prefix and file extension
|
|
3927
|
+
let route = filePath
|
|
3928
|
+
.replace(/^src\/app/, '')
|
|
3929
|
+
.replace(/\/(page|route|layout)\.(tsx?|jsx?)$/, '');
|
|
3930
|
+
|
|
3931
|
+
// Handle root route
|
|
3932
|
+
if (route === '' || route === '/') {
|
|
3933
|
+
return '/';
|
|
3934
|
+
}
|
|
3935
|
+
|
|
3936
|
+
// Ensure leading slash
|
|
3937
|
+
if (!route.startsWith('/')) {
|
|
3938
|
+
route = `/${route}`;
|
|
3939
|
+
}
|
|
3940
|
+
|
|
3941
|
+
return route;
|
|
3942
|
+
};
|
|
3943
|
+
|
|
3944
|
+
/**
|
|
3945
|
+
* Normalize route path to standard format
|
|
3946
|
+
* Converts Next.js dynamic segments to standard format:
|
|
3947
|
+
* - [id] -> :id
|
|
3948
|
+
* - [...slug] -> :slug*
|
|
3949
|
+
* - [[...slug]] -> :slug*?
|
|
3950
|
+
*/
|
|
3951
|
+
const normalizeRoutePath = (routePath) =>
|
|
3952
|
+
routePath
|
|
3953
|
+
.replace(/\[\[\.\.\.(\w+)\]\]/g, ':$1*?') // [[...slug]] -> :slug*?
|
|
3954
|
+
.replace(/\[\.\.\.(\w+)\]/g, ':$1*') // [...slug] -> :slug*
|
|
3955
|
+
.replace(/\[(\w+)\]/g, ':$1'); // [id] -> :id
|
|
3956
|
+
/**
|
|
3957
|
+
* Extract dynamic parameter names from route path
|
|
3958
|
+
* Note: Uses Set to avoid duplicates when patterns overlap (e.g., [[...slug]])
|
|
3959
|
+
*/
|
|
3960
|
+
const extractParams = (routePath) => {
|
|
3961
|
+
const paramsSet = new Set();
|
|
3962
|
+
const patterns = [
|
|
3963
|
+
/\[\[\.\.\.(\w+)\]\]/g, // [[...slug]]
|
|
3964
|
+
/\[\.\.\.(\w+)\]/g, // [...slug]
|
|
3965
|
+
/\[(\w+)\]/g, // [id]
|
|
3966
|
+
];
|
|
3967
|
+
|
|
3968
|
+
patterns.forEach(pattern => {
|
|
3969
|
+
const matches = routePath.matchAll(pattern);
|
|
3970
|
+
for (const match of matches) {
|
|
3971
|
+
paramsSet.add(match[1]);
|
|
3972
|
+
}
|
|
3973
|
+
});
|
|
3974
|
+
|
|
3975
|
+
return Array.from(paramsSet);
|
|
3976
|
+
};
|
|
3977
|
+
|
|
3978
|
+
/**
|
|
3979
|
+
* Determine route type based on file name
|
|
3980
|
+
*/
|
|
3981
|
+
const getRouteType = (filePath) => {
|
|
3982
|
+
if (filePath.includes('/route.')) {
|
|
3983
|
+
return 'api';
|
|
3984
|
+
}
|
|
3985
|
+
return 'page';
|
|
3986
|
+
};
|
|
3987
|
+
|
|
3988
|
+
/**
|
|
3989
|
+
* Scan Next.js routes from src/app directory
|
|
3990
|
+
*
|
|
3991
|
+
* Scans for:
|
|
3992
|
+
* - page.tsx/jsx/ts/js - Page routes
|
|
3993
|
+
* - route.ts/js - API routes
|
|
3994
|
+
*
|
|
3995
|
+
* Note: layout.tsx, loading.tsx, error.tsx are NOT routes, they are UI components
|
|
3996
|
+
*
|
|
3997
|
+
* @param cwd - Current working directory
|
|
3998
|
+
* @returns List of detected routes
|
|
3999
|
+
*/
|
|
4000
|
+
const scanNextjsRoutes = async (cwd) => {
|
|
4001
|
+
log$2('Scanning Next.js routes in:', cwd);
|
|
4002
|
+
|
|
4003
|
+
// Scan for page and route files only (NOT layout, loading, error, etc.)
|
|
4004
|
+
const files = await fastGlob.glob('src/app/**/{page,route}.{tsx,ts,jsx,js}', {
|
|
4005
|
+
cwd,
|
|
4006
|
+
ignore: [
|
|
4007
|
+
'**/node_modules/**',
|
|
4008
|
+
'**/.next/**',
|
|
4009
|
+
'**/dist/**',
|
|
4010
|
+
'**/build/**',
|
|
4011
|
+
'**/.turbo/**',
|
|
4012
|
+
],
|
|
4013
|
+
onlyFiles: true,
|
|
4014
|
+
followSymbolicLinks: false,
|
|
4015
|
+
});
|
|
4016
|
+
|
|
4017
|
+
log$2('Found %d files', files.length);
|
|
4018
|
+
|
|
4019
|
+
return files.map(file => {
|
|
4020
|
+
log$2('Processing file:', file);
|
|
4021
|
+
const routePath = filePathToRoute(file);
|
|
4022
|
+
const isDynamic = routePath.includes('[');
|
|
4023
|
+
const params = extractParams(routePath);
|
|
4024
|
+
|
|
4025
|
+
return {
|
|
4026
|
+
path: normalizeRoutePath(routePath),
|
|
4027
|
+
rawPath: routePath,
|
|
4028
|
+
dynamic: isDynamic,
|
|
4029
|
+
params,
|
|
4030
|
+
type: getRouteType(file),
|
|
4031
|
+
file,
|
|
4032
|
+
framework: 'nextjs',
|
|
4033
|
+
};
|
|
4034
|
+
});
|
|
4035
|
+
};
|
|
4036
|
+
|
|
4037
|
+
// ABOUTME: Route manifest file writer
|
|
4038
|
+
// ABOUTME: Writes route data to JSON file with proper formatting and directory creation
|
|
4039
|
+
|
|
4040
|
+
|
|
4041
|
+
|
|
4042
|
+
|
|
4043
|
+
/**
|
|
4044
|
+
* Calculate route statistics
|
|
4045
|
+
*/
|
|
4046
|
+
const calculateStats = (routes) => {
|
|
4047
|
+
const dynamic = routes.filter(r => r.dynamic).length;
|
|
4048
|
+
const staticCount = routes.length - dynamic;
|
|
4049
|
+
|
|
4050
|
+
return {
|
|
4051
|
+
total: routes.length,
|
|
4052
|
+
dynamic,
|
|
4053
|
+
static: staticCount,
|
|
4054
|
+
};
|
|
4055
|
+
};
|
|
4056
|
+
|
|
4057
|
+
/**
|
|
4058
|
+
* Resolve output file path
|
|
4059
|
+
* - Relative path: resolve based on cwd
|
|
4060
|
+
* - Absolute path: use as-is
|
|
4061
|
+
*/
|
|
4062
|
+
const resolveOutputPath = (cwd, outputPath) =>
|
|
4063
|
+
path.isAbsolute(outputPath) ? outputPath : path.join(cwd, outputPath);
|
|
4064
|
+
|
|
4065
|
+
/**
|
|
4066
|
+
* Ensure parent directory exists
|
|
4067
|
+
* Handles edge cases like existing files with same name
|
|
4068
|
+
*/
|
|
4069
|
+
const ensureDir$1 = (filePath) => {
|
|
4070
|
+
const dir = path.dirname(filePath);
|
|
4071
|
+
|
|
4072
|
+
// If directory already exists, verify it's actually a directory
|
|
4073
|
+
if (fs.existsSync(dir)) {
|
|
4074
|
+
const stats = fs.statSync(dir);
|
|
4075
|
+
if (!stats.isDirectory()) {
|
|
4076
|
+
throw new Error(`Path exists but is not a directory: ${dir}`);
|
|
4077
|
+
}
|
|
4078
|
+
return; // Directory exists and is valid
|
|
4079
|
+
}
|
|
4080
|
+
|
|
4081
|
+
// Create directory with recursive option (equivalent to mkdir -p)
|
|
4082
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
4083
|
+
};
|
|
4084
|
+
|
|
4085
|
+
// JSON.stringify indent size
|
|
4086
|
+
const JSON_INDENT = 2;
|
|
4087
|
+
|
|
4088
|
+
/**
|
|
4089
|
+
* Write route manifest to JSON file
|
|
4090
|
+
*
|
|
4091
|
+
* @param cwd - Current working directory (not used when outputPath is absolute)
|
|
4092
|
+
* @param routes - List of routes to write
|
|
4093
|
+
* @param templateType - Framework type
|
|
4094
|
+
* @param outputPath - Output file path (absolute or relative to cwd)
|
|
4095
|
+
*/
|
|
4096
|
+
const writeRoutesFile = (
|
|
4097
|
+
cwd,
|
|
4098
|
+
routes,
|
|
4099
|
+
templateType,
|
|
4100
|
+
outputPath,
|
|
4101
|
+
) => {
|
|
4102
|
+
try {
|
|
4103
|
+
const resolvedPath = resolveOutputPath(cwd, outputPath);
|
|
4104
|
+
|
|
4105
|
+
// Ensure parent directory exists
|
|
4106
|
+
ensureDir$1(resolvedPath);
|
|
4107
|
+
|
|
4108
|
+
// Build manifest
|
|
4109
|
+
const manifest = {
|
|
4110
|
+
framework: templateType,
|
|
4111
|
+
generatedAt: new Date().toISOString(),
|
|
4112
|
+
routes,
|
|
4113
|
+
stats: calculateStats(routes),
|
|
4114
|
+
};
|
|
4115
|
+
|
|
4116
|
+
// Write to file with pretty formatting
|
|
4117
|
+
fs.writeFileSync(
|
|
4118
|
+
resolvedPath,
|
|
4119
|
+
JSON.stringify(manifest, null, JSON_INDENT),
|
|
4120
|
+
'utf-8',
|
|
4121
|
+
);
|
|
4122
|
+
} catch (error) {
|
|
4123
|
+
// Wrap error with context for better debugging
|
|
4124
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4125
|
+
throw new Error(`Failed to write routes file: ${errorMessage}`);
|
|
4126
|
+
}
|
|
4127
|
+
};
|
|
4128
|
+
|
|
4129
|
+
/**
|
|
4130
|
+
* Get the absolute path of the output file
|
|
4131
|
+
* Useful for logging and testing
|
|
4132
|
+
*/
|
|
4133
|
+
const getOutputFilePath = (cwd, outputPath) =>
|
|
4134
|
+
resolveOutputPath(cwd, outputPath);
|
|
4135
|
+
|
|
4136
|
+
// ABOUTME: Template type detection logic
|
|
4137
|
+
// ABOUTME: Detects framework type by checking config files and package.json dependencies
|
|
4138
|
+
|
|
4139
|
+
|
|
4140
|
+
|
|
4141
|
+
|
|
4142
|
+
const log$1 = debug('coze:route-scanner:detect');
|
|
4143
|
+
|
|
4144
|
+
/**
|
|
4145
|
+
* Check if any of the specified files exist
|
|
4146
|
+
*/
|
|
4147
|
+
const hasFile = (cwd, ...files) =>
|
|
4148
|
+
files.some(file => fs.existsSync(path.join(cwd, file)));
|
|
4149
|
+
|
|
4150
|
+
/**
|
|
4151
|
+
* Detect template type by checking config files and package.json dependencies
|
|
4152
|
+
*
|
|
4153
|
+
* Detection rules (priority order):
|
|
4154
|
+
* 1. Next.js (highest) - has `next` dependency + next.config.{js,mjs,ts}
|
|
4155
|
+
* 2. Nuxt - has `nuxt` dependency + nuxt.config.{ts,js,mjs}
|
|
4156
|
+
* 3. Vite (lowest) - has `vite` + `express` dependencies + vite.config.{ts,js,mjs}
|
|
4157
|
+
*
|
|
4158
|
+
* @param cwd - Current working directory
|
|
4159
|
+
* @returns Template type or null if detection fails
|
|
4160
|
+
*/
|
|
4161
|
+
const detectTemplate = (cwd) => {
|
|
4162
|
+
log$1('Detecting template type in:', cwd);
|
|
4163
|
+
|
|
4164
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
4165
|
+
|
|
4166
|
+
if (!fs.existsSync(pkgPath)) {
|
|
4167
|
+
log$1('package.json not found');
|
|
4168
|
+
return null;
|
|
4169
|
+
}
|
|
4170
|
+
|
|
4171
|
+
try {
|
|
4172
|
+
const pkgContent = fs.readFileSync(pkgPath, 'utf-8');
|
|
4173
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
4174
|
+
const pkg = JSON.parse(pkgContent)
|
|
4175
|
+
|
|
4176
|
+
|
|
4177
|
+
;
|
|
4178
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
4179
|
+
log$1('Dependencies found:', Object.keys(deps).join(', '));
|
|
4180
|
+
|
|
4181
|
+
// 1. Next.js - highest priority
|
|
4182
|
+
const hasNextDep = !!deps.next;
|
|
4183
|
+
const hasNextConfig = hasFile(
|
|
4184
|
+
cwd,
|
|
4185
|
+
'next.config.js',
|
|
4186
|
+
'next.config.mjs',
|
|
4187
|
+
'next.config.ts',
|
|
4188
|
+
);
|
|
4189
|
+
log$1('Next.js check - dependency:', hasNextDep, 'config:', hasNextConfig);
|
|
4190
|
+
|
|
4191
|
+
if (hasNextDep && hasNextConfig) {
|
|
4192
|
+
log$1('✓ Detected: nextjs');
|
|
4193
|
+
return 'nextjs';
|
|
4194
|
+
}
|
|
4195
|
+
|
|
4196
|
+
// 2. Nuxt - second priority
|
|
4197
|
+
const hasNuxtDep = !!deps.nuxt;
|
|
4198
|
+
const hasNuxtConfig = hasFile(
|
|
4199
|
+
cwd,
|
|
4200
|
+
'nuxt.config.ts',
|
|
4201
|
+
'nuxt.config.js',
|
|
4202
|
+
'nuxt.config.mjs',
|
|
4203
|
+
);
|
|
4204
|
+
log$1('Nuxt check - dependency:', hasNuxtDep, 'config:', hasNuxtConfig);
|
|
4205
|
+
|
|
4206
|
+
if (hasNuxtDep && hasNuxtConfig) {
|
|
4207
|
+
log$1('✓ Detected: nuxt');
|
|
4208
|
+
return 'nuxt';
|
|
4209
|
+
}
|
|
4210
|
+
|
|
4211
|
+
// 3. Vite - lowest priority (requires both vite and express)
|
|
4212
|
+
const hasViteDep = !!deps.vite;
|
|
4213
|
+
const hasExpressDep = !!deps.express;
|
|
4214
|
+
const hasViteConfig = hasFile(
|
|
4215
|
+
cwd,
|
|
4216
|
+
'vite.config.ts',
|
|
4217
|
+
'vite.config.js',
|
|
4218
|
+
'vite.config.mjs',
|
|
4219
|
+
);
|
|
4220
|
+
log$1(
|
|
4221
|
+
'Vite check - vite dep:',
|
|
4222
|
+
hasViteDep,
|
|
4223
|
+
'express dep:',
|
|
4224
|
+
hasExpressDep,
|
|
4225
|
+
'config:',
|
|
4226
|
+
hasViteConfig,
|
|
4227
|
+
);
|
|
4228
|
+
|
|
4229
|
+
if (hasViteDep && hasExpressDep && hasViteConfig) {
|
|
4230
|
+
log$1('✓ Detected: vite');
|
|
4231
|
+
return 'vite';
|
|
4232
|
+
}
|
|
4233
|
+
|
|
4234
|
+
log$1('✗ No template detected');
|
|
4235
|
+
return null;
|
|
4236
|
+
} catch (error) {
|
|
4237
|
+
// Invalid package.json or other errors
|
|
4238
|
+
log$1('Error during detection:', error);
|
|
4239
|
+
return null;
|
|
4240
|
+
}
|
|
4241
|
+
};
|
|
4242
|
+
|
|
4243
|
+
// ABOUTME: Route scanner main entry point
|
|
4244
|
+
// ABOUTME: Orchestrates template detection, route scanning, and polling-based updates
|
|
4245
|
+
|
|
4246
|
+
|
|
4247
|
+
const log = debug('coze:route-scanner:main');
|
|
4248
|
+
|
|
4249
|
+
// Polling interval in milliseconds (500ms to balance responsiveness and performance)
|
|
4250
|
+
const POLLING_INTERVAL_MS = 500;
|
|
4251
|
+
|
|
4252
|
+
// Store polling interval for cleanup
|
|
4253
|
+
let pollingInterval = null;
|
|
4254
|
+
let previousRoutesHash = null;
|
|
4255
|
+
|
|
4256
|
+
/**
|
|
4257
|
+
* Scan routes based on template type
|
|
4258
|
+
*/
|
|
4259
|
+
const scanRoutes = async (
|
|
4260
|
+
cwd,
|
|
4261
|
+
templateType,
|
|
4262
|
+
) => {
|
|
4263
|
+
switch (templateType) {
|
|
4264
|
+
case 'nextjs':
|
|
4265
|
+
return scanNextjsRoutes(cwd);
|
|
4266
|
+
case 'nuxt':
|
|
4267
|
+
return scanNuxtRoutes(cwd);
|
|
4268
|
+
case 'vite':
|
|
4269
|
+
return [];
|
|
4270
|
+
default:
|
|
4271
|
+
return [];
|
|
4272
|
+
}
|
|
4273
|
+
};
|
|
4274
|
+
|
|
4275
|
+
/**
|
|
4276
|
+
* Generate a simple hash for routes to detect changes
|
|
4277
|
+
*/
|
|
4278
|
+
const hashRoutes = (routes) =>
|
|
4279
|
+
routes
|
|
4280
|
+
.map(r => `${r.file}:${r.type}`)
|
|
4281
|
+
.sort()
|
|
4282
|
+
.join('|');
|
|
4283
|
+
|
|
4284
|
+
/**
|
|
4285
|
+
* Detect and validate template type
|
|
4286
|
+
* @returns Template type or null if invalid/unsupported
|
|
4287
|
+
*/
|
|
4288
|
+
const detectAndValidateTemplate = (cwd) => {
|
|
4289
|
+
log('Detecting template type');
|
|
4290
|
+
const templateType = detectTemplate(cwd);
|
|
4291
|
+
|
|
4292
|
+
if (!templateType) {
|
|
4293
|
+
log('No template type detected');
|
|
4294
|
+
logger.warn('Unable to detect template type, skipping route scanning');
|
|
4295
|
+
return null;
|
|
4296
|
+
}
|
|
4297
|
+
|
|
4298
|
+
log('Template detected:', templateType);
|
|
4299
|
+
|
|
4300
|
+
if (templateType === 'vite') {
|
|
4301
|
+
log('Skipping Vite template - not supported');
|
|
4302
|
+
return null;
|
|
4303
|
+
}
|
|
4304
|
+
|
|
4305
|
+
return templateType;
|
|
4306
|
+
};
|
|
4307
|
+
|
|
4308
|
+
/**
|
|
4309
|
+
* Perform initial route scan and write to file
|
|
4310
|
+
*/
|
|
4311
|
+
const performInitialScan = async (
|
|
4312
|
+
cwd,
|
|
4313
|
+
templateType,
|
|
4314
|
+
outputPath,
|
|
4315
|
+
) => {
|
|
4316
|
+
log('Starting route scanning');
|
|
4317
|
+
log('Performing initial scan');
|
|
4318
|
+
const routes = await scanRoutes(cwd, templateType);
|
|
4319
|
+
log('Initial scan found %d routes', routes.length);
|
|
4320
|
+
|
|
4321
|
+
log('Writing routes to file:', outputPath);
|
|
4322
|
+
writeRoutesFile(cwd, routes, templateType, outputPath);
|
|
4323
|
+
|
|
4324
|
+
const outputFilePath = getOutputFilePath(cwd, outputPath);
|
|
4325
|
+
log('Routes written to: %s (%d routes)', outputFilePath, routes.length);
|
|
4326
|
+
|
|
4327
|
+
return routes;
|
|
4328
|
+
};
|
|
4329
|
+
|
|
4330
|
+
/**
|
|
4331
|
+
* Setup polling interval to detect route changes
|
|
4332
|
+
*/
|
|
4333
|
+
const setupPolling = (
|
|
4334
|
+
cwd,
|
|
4335
|
+
templateType,
|
|
4336
|
+
outputPath,
|
|
4337
|
+
initialRoutes,
|
|
4338
|
+
) => {
|
|
4339
|
+
previousRoutesHash = hashRoutes(initialRoutes);
|
|
4340
|
+
log('Starting periodic route scanning (every 500ms)');
|
|
4341
|
+
log('About to call setInterval...');
|
|
4342
|
+
|
|
4343
|
+
pollingInterval = setInterval(async () => {
|
|
4344
|
+
try {
|
|
4345
|
+
log('Polling cycle started...');
|
|
4346
|
+
const updatedRoutes = await scanRoutes(cwd, templateType);
|
|
4347
|
+
const newHash = hashRoutes(updatedRoutes);
|
|
4348
|
+
log('Scanned %d routes, hash: %s vs %s', updatedRoutes.length, newHash, previousRoutesHash);
|
|
4349
|
+
|
|
4350
|
+
if (newHash !== previousRoutesHash) {
|
|
4351
|
+
log('Routes changed, updating file');
|
|
4352
|
+
writeRoutesFile(cwd, updatedRoutes, templateType, outputPath);
|
|
4353
|
+
previousRoutesHash = newHash;
|
|
4354
|
+
log('Routes updated (%d routes)', updatedRoutes.length);
|
|
4355
|
+
logger.info(`🔄 Routes updated (${updatedRoutes.length} routes)`);
|
|
4356
|
+
}
|
|
4357
|
+
} catch (pollingError) {
|
|
4358
|
+
log('Polling error:', pollingError);
|
|
4359
|
+
}
|
|
4360
|
+
}, POLLING_INTERVAL_MS);
|
|
4361
|
+
|
|
4362
|
+
log('setInterval called, returned interval ID:', pollingInterval);
|
|
4363
|
+
log('pollingInterval type:', typeof pollingInterval);
|
|
4364
|
+
log('Route polling started (checking every %dms)', POLLING_INTERVAL_MS);
|
|
4365
|
+
|
|
4366
|
+
// Test if interval is actually working by logging after 1 second
|
|
4367
|
+
setTimeout(() => {
|
|
4368
|
+
log('setTimeout test fired after 1 second - event loop is working');
|
|
4369
|
+
}, 1000);
|
|
4370
|
+
};
|
|
4371
|
+
|
|
4372
|
+
/**
|
|
4373
|
+
* Register cleanup handlers for process termination signals
|
|
4374
|
+
* Note: Do NOT listen to 'exit' event because the CLI parent process
|
|
4375
|
+
* exits normally after spawning the dev server child process
|
|
4376
|
+
*/
|
|
4377
|
+
const registerCleanupHandlers = () => {
|
|
4378
|
+
const cleanup = () => {
|
|
4379
|
+
if (pollingInterval) {
|
|
4380
|
+
log('Cleaning up polling interval on process termination');
|
|
4381
|
+
clearInterval(pollingInterval);
|
|
4382
|
+
pollingInterval = null;
|
|
4383
|
+
previousRoutesHash = null;
|
|
4384
|
+
}
|
|
4385
|
+
};
|
|
4386
|
+
|
|
4387
|
+
// Only handle termination signals, not normal exit
|
|
4388
|
+
process.on('SIGINT', cleanup);
|
|
4389
|
+
process.on('SIGTERM', cleanup);
|
|
4390
|
+
};
|
|
4391
|
+
|
|
4392
|
+
/**
|
|
4393
|
+
* Clean up existing polling interval
|
|
4394
|
+
*/
|
|
4395
|
+
const cleanupExistingInterval = () => {
|
|
4396
|
+
if (pollingInterval) {
|
|
4397
|
+
log('Clearing existing polling interval before starting new one');
|
|
4398
|
+
clearInterval(pollingInterval);
|
|
4399
|
+
pollingInterval = null;
|
|
4400
|
+
previousRoutesHash = null;
|
|
4401
|
+
}
|
|
4402
|
+
};
|
|
4403
|
+
|
|
4404
|
+
/**
|
|
4405
|
+
* Start route scanning and polling
|
|
4406
|
+
*
|
|
4407
|
+
* Workflow:
|
|
4408
|
+
* 1. Detect template type (Next.js/Nuxt/Vite)
|
|
4409
|
+
* 2. If Vite, skip scanning (too simple, not worth resources)
|
|
4410
|
+
* 3. Perform initial route scan
|
|
4411
|
+
* 4. Write routes to JSON file
|
|
4412
|
+
* 5. Start periodic polling (every 500ms) to detect route changes
|
|
4413
|
+
*
|
|
4414
|
+
* Note: Uses polling instead of file watching to avoid EMFILE errors
|
|
4415
|
+
*
|
|
4416
|
+
* @param cwd - Current working directory
|
|
4417
|
+
* @param options - Scanning options (output path, etc.)
|
|
4418
|
+
*/
|
|
4419
|
+
const startRouteScanning = async (
|
|
4420
|
+
cwd,
|
|
4421
|
+
options = {},
|
|
4422
|
+
) => {
|
|
4423
|
+
cleanupExistingInterval();
|
|
4424
|
+
|
|
4425
|
+
try {
|
|
4426
|
+
log('startRouteScanning called with cwd:', cwd, 'options:', options);
|
|
4427
|
+
// Default output to ~/.coze/routes.json (user home), can be overridden via options or env var
|
|
4428
|
+
// Using user home avoids conflict with project .coze config file
|
|
4429
|
+
const defaultOutputPath =
|
|
4430
|
+
process.env.COZE_ROUTES_OUTPUT || getCozeFilePath('routes.json');
|
|
4431
|
+
const { outputPath = defaultOutputPath } = options;
|
|
4432
|
+
|
|
4433
|
+
// Step 1: Detect and validate template
|
|
4434
|
+
const templateType = detectAndValidateTemplate(cwd);
|
|
4435
|
+
if (!templateType) {
|
|
4436
|
+
return;
|
|
4437
|
+
}
|
|
4438
|
+
|
|
4439
|
+
// Step 2: Perform initial scan
|
|
4440
|
+
const routes = await performInitialScan(cwd, templateType, outputPath);
|
|
4441
|
+
|
|
4442
|
+
// Step 3: Check if polling is enabled
|
|
4443
|
+
const enablePolling = process.env.COZE_ROUTES_WATCH !== 'false';
|
|
4444
|
+
if (!enablePolling) {
|
|
4445
|
+
log('Route polling disabled via COZE_ROUTES_WATCH=false');
|
|
4446
|
+
return;
|
|
4447
|
+
}
|
|
4448
|
+
|
|
4449
|
+
// Step 4: Setup polling and cleanup handlers
|
|
4450
|
+
log('About to call setupPolling...');
|
|
4451
|
+
setupPolling(cwd, templateType, outputPath, routes);
|
|
4452
|
+
log('setupPolling completed');
|
|
4453
|
+
|
|
4454
|
+
log('About to call registerCleanupHandlers...');
|
|
4455
|
+
registerCleanupHandlers();
|
|
4456
|
+
log('registerCleanupHandlers completed');
|
|
4457
|
+
|
|
4458
|
+
log('startRouteScanning function about to return');
|
|
4459
|
+
} catch (error) {
|
|
4460
|
+
log('ERROR CAUGHT in startRouteScanning:', error);
|
|
4461
|
+
cleanupExistingInterval();
|
|
4462
|
+
|
|
4463
|
+
// Silently handle all errors - route scanning should never break dev server
|
|
4464
|
+
log('Route scanning error:', error);
|
|
4465
|
+
logger.warn(
|
|
4466
|
+
'⚠️ Route scanning skipped due to error (dev server continues normally)',
|
|
4467
|
+
);
|
|
4468
|
+
|
|
4469
|
+
if (process.env.DEBUG) {
|
|
4470
|
+
logger.warn(error instanceof Error ? error.message : String(error));
|
|
4471
|
+
}
|
|
4472
|
+
}
|
|
4473
|
+
};
|
|
4474
|
+
|
|
4475
|
+
function _nullishCoalesce$1(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
4476
|
+
/**
|
|
4477
|
+
* 日志文件名常量
|
|
4478
|
+
*/
|
|
4479
|
+
const LOG_FILE_NAME = 'dev.log';
|
|
3644
4480
|
|
|
3645
4481
|
/**
|
|
3646
4482
|
* 解析日志文件路径
|
|
3647
4483
|
* - 如果是绝对路径,直接使用
|
|
3648
|
-
* - 如果是相对路径,基于
|
|
3649
|
-
* -
|
|
4484
|
+
* - 如果是相对路径,基于 logs 目录 + 相对路径
|
|
4485
|
+
* - 如果为空,使用默认日志文件路径
|
|
3650
4486
|
*/
|
|
3651
4487
|
const resolveLogFilePath = (logFile) => {
|
|
3652
4488
|
if (!logFile) {
|
|
3653
|
-
return
|
|
4489
|
+
return getCozeLogPath(LOG_FILE_NAME);
|
|
3654
4490
|
}
|
|
3655
4491
|
|
|
3656
4492
|
if (path.isAbsolute(logFile)) {
|
|
3657
4493
|
return logFile;
|
|
3658
4494
|
}
|
|
3659
4495
|
|
|
3660
|
-
return
|
|
4496
|
+
return getCozeLogPath(logFile);
|
|
3661
4497
|
};
|
|
3662
4498
|
|
|
3663
4499
|
/**
|
|
@@ -3703,15 +4539,21 @@ const executeRun = async (
|
|
|
3703
4539
|
logger.info('');
|
|
3704
4540
|
}
|
|
3705
4541
|
|
|
3706
|
-
// 2.
|
|
4542
|
+
// 2. 启动路由扫描(仅在 dev 模式)
|
|
4543
|
+
// Note: startRouteScanning handles all errors internally and never throws
|
|
4544
|
+
if (commandName === 'dev') {
|
|
4545
|
+
await startRouteScanning(process.cwd());
|
|
4546
|
+
}
|
|
4547
|
+
|
|
4548
|
+
// 3. 加载 .coze 配置
|
|
3707
4549
|
const config = await loadCozeConfig();
|
|
3708
4550
|
const commandArgs = getCommandConfig(config, commandName);
|
|
3709
4551
|
|
|
3710
|
-
//
|
|
4552
|
+
// 4. 准备日志
|
|
3711
4553
|
const logFilePath = resolveLogFilePath(options.logFile);
|
|
3712
4554
|
const logStream = createLogStream(logFilePath);
|
|
3713
4555
|
|
|
3714
|
-
//
|
|
4556
|
+
// 5. 执行命令
|
|
3715
4557
|
const commandString = commandArgs.join(' ');
|
|
3716
4558
|
|
|
3717
4559
|
logger.info(`Executing: ${commandString}`);
|
|
@@ -3738,72 +4580,76 @@ const executeRun = async (
|
|
|
3738
4580
|
logStream.write(data);
|
|
3739
4581
|
})]);
|
|
3740
4582
|
|
|
3741
|
-
|
|
3742
|
-
|
|
4583
|
+
// Wait for child process to complete
|
|
4584
|
+
await new Promise((resolve, reject) => {
|
|
4585
|
+
childProcess.on('close', (code, signal) => {
|
|
4586
|
+
logStream.end();
|
|
4587
|
+
|
|
4588
|
+
if (code !== 0) {
|
|
4589
|
+
const errorMessage = `Command exited with code ${_nullishCoalesce$1(code, () => ( 'unknown'))}${signal ? ` and signal ${signal}` : ''}`;
|
|
4590
|
+
logger.error(errorMessage);
|
|
4591
|
+
logger.error(`Check log file for details: ${logFilePath}`);
|
|
4592
|
+
|
|
4593
|
+
// 上报命令失败
|
|
4594
|
+
reportError(new Error(errorMessage), {
|
|
4595
|
+
command: commandName,
|
|
4596
|
+
exitCode: String(_nullishCoalesce$1(code, () => ( 'unknown'))),
|
|
4597
|
+
signal: _nullishCoalesce$1(signal, () => ( 'none')),
|
|
4598
|
+
logFile: logFilePath,
|
|
4599
|
+
});
|
|
4600
|
+
reportCommandComplete(commandName, false, Date.now() - cmdStartTime, {
|
|
4601
|
+
args: JSON.stringify(options),
|
|
4602
|
+
errorCode: _nullishCoalesce$1(code, () => ( 1)),
|
|
4603
|
+
errorMessage,
|
|
4604
|
+
});
|
|
4605
|
+
flushSlardar()
|
|
4606
|
+
.then(() => {
|
|
4607
|
+
process.exit(code || 1);
|
|
4608
|
+
})
|
|
4609
|
+
.catch(() => {
|
|
4610
|
+
// Catch any errors in the promise chain to prevent unhandled rejections
|
|
4611
|
+
process.exit(code || 1);
|
|
4612
|
+
});
|
|
4613
|
+
} else {
|
|
4614
|
+
logger.success('Command completed successfully');
|
|
4615
|
+
logger.info(`Log file: ${logFilePath}`);
|
|
4616
|
+
|
|
4617
|
+
// 上报命令成功
|
|
4618
|
+
reportCommandComplete(commandName, true, Date.now() - cmdStartTime, {
|
|
4619
|
+
args: JSON.stringify(options),
|
|
4620
|
+
});
|
|
4621
|
+
// flush 由 main 函数统一处理
|
|
4622
|
+
resolve();
|
|
4623
|
+
}
|
|
4624
|
+
});
|
|
3743
4625
|
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
logger.error(
|
|
3747
|
-
|
|
4626
|
+
childProcess.on('error', (error) => {
|
|
4627
|
+
logger.error('Failed to execute command:');
|
|
4628
|
+
logger.error(`Error: ${error.message}`);
|
|
4629
|
+
if (error.stack) {
|
|
4630
|
+
logger.error(`Stack trace:\n${error.stack}`);
|
|
4631
|
+
}
|
|
4632
|
+
logStream.end();
|
|
3748
4633
|
|
|
3749
|
-
//
|
|
3750
|
-
reportError(
|
|
4634
|
+
// 上报错误
|
|
4635
|
+
reportError(error, {
|
|
3751
4636
|
command: commandName,
|
|
3752
|
-
|
|
3753
|
-
signal: _nullishCoalesce$1(signal, () => ( 'none')),
|
|
3754
|
-
logFile: logFilePath,
|
|
4637
|
+
type: 'child_process_error',
|
|
3755
4638
|
});
|
|
3756
4639
|
reportCommandComplete(commandName, false, Date.now() - cmdStartTime, {
|
|
3757
4640
|
args: JSON.stringify(options),
|
|
3758
|
-
errorCode:
|
|
3759
|
-
errorMessage,
|
|
4641
|
+
errorCode: 1,
|
|
4642
|
+
errorMessage: error.message,
|
|
3760
4643
|
});
|
|
3761
4644
|
flushSlardar()
|
|
3762
4645
|
.then(() => {
|
|
3763
|
-
process.exit(
|
|
4646
|
+
process.exit(1);
|
|
3764
4647
|
})
|
|
3765
4648
|
.catch(() => {
|
|
3766
4649
|
// Catch any errors in the promise chain to prevent unhandled rejections
|
|
3767
|
-
process.exit(
|
|
4650
|
+
process.exit(1);
|
|
3768
4651
|
});
|
|
3769
|
-
} else {
|
|
3770
|
-
logger.success('Command completed successfully');
|
|
3771
|
-
logger.info(`Log file: ${logFilePath}`);
|
|
3772
|
-
|
|
3773
|
-
// 上报命令成功
|
|
3774
|
-
reportCommandComplete(commandName, true, Date.now() - cmdStartTime, {
|
|
3775
|
-
args: JSON.stringify(options),
|
|
3776
|
-
});
|
|
3777
|
-
// flush 由 main 函数统一处理
|
|
3778
|
-
}
|
|
3779
|
-
});
|
|
3780
|
-
|
|
3781
|
-
childProcess.on('error', (error) => {
|
|
3782
|
-
logger.error('Failed to execute command:');
|
|
3783
|
-
logger.error(`Error: ${error.message}`);
|
|
3784
|
-
if (error.stack) {
|
|
3785
|
-
logger.error(`Stack trace:\n${error.stack}`);
|
|
3786
|
-
}
|
|
3787
|
-
logStream.end();
|
|
3788
|
-
|
|
3789
|
-
// 上报错误
|
|
3790
|
-
reportError(error, {
|
|
3791
|
-
command: commandName,
|
|
3792
|
-
type: 'child_process_error',
|
|
3793
4652
|
});
|
|
3794
|
-
reportCommandComplete(commandName, false, Date.now() - cmdStartTime, {
|
|
3795
|
-
args: JSON.stringify(options),
|
|
3796
|
-
errorCode: 1,
|
|
3797
|
-
errorMessage: error.message,
|
|
3798
|
-
});
|
|
3799
|
-
flushSlardar()
|
|
3800
|
-
.then(() => {
|
|
3801
|
-
process.exit(1);
|
|
3802
|
-
})
|
|
3803
|
-
.catch(() => {
|
|
3804
|
-
// Catch any errors in the promise chain to prevent unhandled rejections
|
|
3805
|
-
process.exit(1);
|
|
3806
|
-
});
|
|
3807
4653
|
});
|
|
3808
4654
|
} catch (error) {
|
|
3809
4655
|
const err = error instanceof Error ? error : new Error(String(error));
|