@moneko/core 4.12.2-beta.0 → 4.12.3
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/hooks/ai-eslint.sh +80 -44
- package/hooks/ai-stylelint.sh +3 -2
- package/lib/config.mjs +1 -1
- package/package.json +1 -1
package/hooks/ai-eslint.sh
CHANGED
|
@@ -1,66 +1,102 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Shared AI Agent ESLint fix Stop hook.
|
|
4
|
+
# Used by both Claude Code (project .claude/settings.json) and Codex
|
|
5
|
+
# (project .codex/config.toml). Runs the project's own `npx mo eslint <file> --fix`
|
|
6
|
+
# over the files the Agent just created/modified/untracked, then blocks the
|
|
7
|
+
# Agent Stop until the remaining ESLint errors are fixed.
|
|
8
|
+
#
|
|
9
|
+
# Exit codes:
|
|
10
|
+
# 0 no target files, or all errors were auto-fixed
|
|
11
|
+
# 2 at least one file still has ESLint errors after --fix (blocks Stop)
|
|
2
12
|
set -u
|
|
3
13
|
|
|
14
|
+
# ---------------------------------------------------------------------------
|
|
15
|
+
# Recursion guard. Both Claude Code and Codex pass a JSON payload on stdin for
|
|
16
|
+
# Stop hooks. When a Stop hook blocks (exit 2), the platform starts a follow-up
|
|
17
|
+
# turn and sets `stop_hook_active` to true in that payload. We must not block
|
|
18
|
+
# again on the follow-up turn, otherwise the Agent loops forever.
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
4
20
|
if [ ! -t 0 ]; then
|
|
5
|
-
hook_input
|
|
6
|
-
|
|
7
|
-
exit 0
|
|
8
|
-
|
|
21
|
+
hook_input="$(cat 2>/dev/null || true)"
|
|
22
|
+
case "$hook_input" in
|
|
23
|
+
*'"stop_hook_active"':*'true'*) exit 0 ;;
|
|
24
|
+
esac
|
|
9
25
|
fi
|
|
10
26
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
cd "$repo_root" || exit 2
|
|
27
|
+
# Locate the repository root so this works from any subdirectory.
|
|
28
|
+
root="$(git rev-parse --show-toplevel 2>/dev/null)" || exit 0
|
|
29
|
+
cd "$root" || exit 0
|
|
17
30
|
|
|
18
31
|
if ! command -v npx >/dev/null 2>&1; then
|
|
19
|
-
printf 'AI ESLint hook: npx is unavailable; install
|
|
32
|
+
printf '%s\n' 'AI ESLint stop hook: npx is unavailable; install the existing project dependencies before retrying. No dependency was installed.' >&2
|
|
20
33
|
exit 2
|
|
21
34
|
fi
|
|
22
35
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
while IFS= read -r -d '' record; do
|
|
29
|
-
xy=${record:0:2}
|
|
30
|
-
path=${record:3}
|
|
36
|
+
if ! npx --no-install mo --version >/dev/null 2>&1; then
|
|
37
|
+
printf '%s\n' 'AI ESLint stop hook: project command "mo" is unavailable; install the existing project dependencies before retrying. No dependency was installed.' >&2
|
|
38
|
+
exit 2
|
|
39
|
+
fi
|
|
31
40
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
# ---------------------------------------------------------------------------
|
|
42
|
+
# Collect target files from NUL-separated porcelain v1 output. This keeps
|
|
43
|
+
# spaces / CJK / other characters intact and correctly consumes the second
|
|
44
|
+
# NUL-terminated path of rename/copy records.
|
|
45
|
+
# ---------------------------------------------------------------------------
|
|
46
|
+
targets=()
|
|
47
|
+
while IFS= read -r -d '' entry; do
|
|
48
|
+
x="${entry:0:1}" # index status: ' ', M, A, D, R, C, U, ?
|
|
49
|
+
y="${entry:1:1}" # worktree status: ' ', M, D, U, ?
|
|
50
|
+
path="${entry:3}" # skip the "XY " prefix and preserve the full path
|
|
38
51
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
*) should_lint=0 ;;
|
|
45
|
-
esac
|
|
46
|
-
;;
|
|
47
|
-
esac
|
|
52
|
+
# Rename (R) / copy (C) records carry a second NUL-terminated source path.
|
|
53
|
+
# Consume it so the next status record is not misaligned.
|
|
54
|
+
if [ "$x" = R ] || [ "$x" = C ]; then
|
|
55
|
+
IFS= read -r -d '' _src || true
|
|
56
|
+
fi
|
|
48
57
|
|
|
49
|
-
|
|
50
|
-
[
|
|
58
|
+
# Deleted files are never processed.
|
|
59
|
+
if [ "$x" = D ] || [ "$y" = D ]; then
|
|
60
|
+
continue
|
|
61
|
+
fi
|
|
51
62
|
|
|
52
|
-
|
|
53
|
-
if
|
|
54
|
-
|
|
63
|
+
# Pure rename/copy (no added or modified content) is not processed.
|
|
64
|
+
if { [ "$x" = R ] || [ "$x" = C ]; } && [ "$y" != M ]; then
|
|
65
|
+
continue
|
|
55
66
|
fi
|
|
56
|
-
|
|
57
|
-
|
|
67
|
+
|
|
68
|
+
# Process: modified (staged or working-tree), added, or untracked.
|
|
69
|
+
if [ "$x" = M ] || [ "$y" = M ] || [ "$x" = A ] || { [ "$x" = '?' ] && [ "$y" = '?' ]; }; then
|
|
70
|
+
targets+=("$path")
|
|
58
71
|
fi
|
|
59
72
|
done < <(git status --porcelain=v1 -z --untracked-files=all)
|
|
60
73
|
|
|
61
|
-
|
|
62
|
-
|
|
74
|
+
# ---------------------------------------------------------------------------
|
|
75
|
+
# Run the project's own linter one file at a time. A failed file must not stop
|
|
76
|
+
# the remaining files; collect all output and report it once at the end.
|
|
77
|
+
# ---------------------------------------------------------------------------
|
|
78
|
+
failed=0
|
|
79
|
+
collected=""
|
|
80
|
+
for file in "${targets[@]:-}"; do
|
|
81
|
+
# Skip paths that no longer exist on disk.
|
|
82
|
+
[ -e "$file" ] || continue
|
|
83
|
+
|
|
84
|
+
out="$(npx mo eslint "$file" --fix 2>&1)"
|
|
85
|
+
rc=$?
|
|
86
|
+
if [ "$rc" -ne 0 ]; then
|
|
87
|
+
failed=1
|
|
88
|
+
collected+="${out}"$'\n'
|
|
89
|
+
fi
|
|
90
|
+
done
|
|
91
|
+
|
|
92
|
+
if [ "$failed" -ne 0 ]; then
|
|
93
|
+
{
|
|
94
|
+
[ -n "$collected" ] && printf '%s\n' "$collected"
|
|
95
|
+
printf '%s\n' '============================================================'
|
|
96
|
+
printf '%s\n' 'AI ESLint stop hook: 以上文件在 --fix 后仍存在 ESLint error。'
|
|
97
|
+
printf '%s\n' '请继续修复剩余的 ESLint 问题后再结束当前任务。'
|
|
98
|
+
} >&2
|
|
63
99
|
exit 2
|
|
64
100
|
fi
|
|
65
101
|
|
|
66
|
-
exit 0
|
|
102
|
+
exit 0
|
package/hooks/ai-stylelint.sh
CHANGED
|
@@ -20,9 +20,10 @@ if ! command -v npx >/dev/null 2>&1; then
|
|
|
20
20
|
exit 2
|
|
21
21
|
fi
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
output=$(npx mo stylelint src 2>&1) || {
|
|
24
|
+
printf '%s\n' "$output" >&2
|
|
24
25
|
printf '\nAI Stylelint hook: 请 Agent 继续修复剩余 Stylelint 问题。\n' >&2
|
|
25
26
|
exit 2
|
|
26
|
-
|
|
27
|
+
}
|
|
27
28
|
|
|
28
29
|
exit 0
|
package/lib/config.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{sep as e}from"node:path";import o from"node:process";import{merge as t}from"webpack-merge";import{CUSTOMCONFIG as n}from"./commom/custom-config.mjs";import s from"./commom/paths.mjs";import{join as i}from"./commom/posix.mjs";import r from"./commom/setup-env.mjs";import a from"./options/jsx-dom-expressions.mjs";import m from"./options/split-chunk.mjs";import{getConfigWithTypescript as l,isFunction as p,node_modules as c,resolveProgram as u}from"./utils/index.mjs";import{initDts as d}from"./vm/dts.mjs";import{APPTYPE as f,FRAMEWORK as h,frameworkVersion as g,isBuild as v,isCI as x,isDev as b,isLibrary as j,isMobile as C,isReact as P,jsxImportSource as k,mainDirectory as w,NODE_ENV as O,PACKAGENAME as y}from"./process-env.mjs";let S=[/(app|vm|docs|example):[a-zA-Z_0-9]/,"@moneko","neko-ui",".cache/http/data","@element-plus","ant-design-vue","element-plus","element-ui","ng-zorro-antd","@mui","@du","@fontsource","@fortawesome","font-pingfang-sc","font-pingfang-tc","katex","react-markdown-editor-lite","react-photo-view","schema-design","monaco-editor","codemirror-json-schema"];export async function getConfig(e){let t=l(e).default;return(p(t)?await t(o):t)??{}}let I=await r(O,f,h,[],v,n),[z,F]=await Promise.all([getConfig(s.configPath),getConfig(s.customConfigPath)]),M={mode:O,strict:!1,devtool:!1,seo:!1,bundleAnalyzer:!1,polyfill:!1,entry:{},minifier:(!!x||!b)&&{},sourceMap:{filename:"[file].map",publicPath:"",namespace:y,moduleFilenameTemplate:"moneko://[namespace]/[resource-path]?[loaders]",fallbackModuleFilenameTemplate:"moneko://[namespace]/[resource-path]?[loaders]"},env:I,basename:"/",publicPath:"auto",rem:{designSize:C?375:1920},fallbackCompPath:null,modifyVars:{},prefixCls:"n",alias:Object.assign({"@":u(w)},P&&g<18?{"react/package.json":c("react/package.json"),"react/jsx-runtime":c("react/jsx-runtime.js"),"react/jsx-dev-runtime":c("react/jsx-dev-runtime.js")}:{}),moduleRules:[],prefixJsLoader:[],cssModules:[],cssModuleDefinition:!0,importOnDemand:{},proxy:{},devServer:{host:"localhost",port:3e3,open:!0},htmlPluginOption:{title:y.toLocaleUpperCase(),favicon:"https://h5static.dewucdn.com/node-common/718d5e10-576d-8b14-b0b1-e4c58c3b3f40.webp"},copy:{},routerMode:"browser",fixBrowserRouter:!1,plugins:[],resolvePlugins:[],overrideResolve:!1,splitChunk:m,runtimeChunk:"single",moduleFederation:[],rulesInclude:{css:S,js:S,media:S,font:S,wasm:[]},mdx:{jsx:!1,development:b,jsxImportSource:k,providerImportSource:`@moneko/${h}/mdx`},jsxDomExpressions:a,bar:{name:"Client",nameColor:"68",msgColor:"242",barBgColor:"15",barColor:"69",quiet:x},normalizeCss:!0,externalsPresets:{},buildHttp:void 0,virtualModule:{},cssExtract:{},externals:["@swc/core"],lazyCompilation:!1,performance:!1,refresh:"solid"!==h,bundleId:"com.moneko.bid",bundles:[],stylelint:{},eslint:{lintDirtyModulesOnly:!1},minChunkSize:1e3,compression:!1,manifest:{filename:"site.webmanifest"},corepack:!0,reactJsxRuntime:"automatic"};j&&(M.alias=Object.assign(M.alias,{"@pkg":s.componentsPath,[y]:s.componentsPath}));let A=M;if(A=t(A,z,F),"true"===o.env.CODESPACES&&A.devServer.https&&(A.devServer.https=!1),!1===A.devServer.https&&"darwin"===o.platform&&(A.devServer.open=!1),A.htmlPluginOption&&(A.htmlPluginOption.tags||(A.htmlPluginOption.tags=[]),A.fixBrowserRouter&&A.htmlPluginOption.tags.push({textContent:"(function(l) {if (l.search[1] === '/' ) {var decoded = l.search.slice(1).split('&').map(function(s) {return s.replace(/~and~/g, '&')}).join('?');window.history.replaceState(null, null,l.pathname.slice(0, -1) + decoded + l.hash);}}(window.location))"}),A.manifest)){let o=A.manifest.publicPath??A.htmlPluginOption.publicPath??A.publicPath??"/";A.htmlPluginOption.tags.push({href:i("auto"===o?"/":o,A.manifest.filename).replaceAll(e,"/"),tag:"link",rel:"manifest"})}export const CONFIG=A;export const PUBLICPATH="auto"===CONFIG.publicPath?"":CONFIG.publicPath;d(CONFIG);
|
|
1
|
+
import{sep as e}from"node:path";import o from"node:process";import{merge as t}from"webpack-merge";import{CUSTOMCONFIG as n}from"./commom/custom-config.mjs";import s from"./commom/paths.mjs";import{join as i}from"./commom/posix.mjs";import r from"./commom/setup-env.mjs";import a from"./options/jsx-dom-expressions.mjs";import m from"./options/split-chunk.mjs";import{getConfigWithTypescript as l,isFunction as p,node_modules as c,resolveProgram as u}from"./utils/index.mjs";import{initDts as d}from"./vm/dts.mjs";import{APPTYPE as f,FRAMEWORK as h,frameworkVersion as g,isBuild as v,isCI as x,isDev as b,isLibrary as j,isMobile as C,isReact as P,jsxImportSource as k,mainDirectory as w,NODE_ENV as O,PACKAGENAME as y}from"./process-env.mjs";let S=[/(app|vm|docs|example):[a-zA-Z_0-9]/,"@moneko","neko-ui",".cache/http/data","@element-plus","@ant-design","ant-design-vue","element-plus","element-ui","ng-zorro-antd","@mui","@du","@fontsource","@fortawesome","font-pingfang-sc","font-pingfang-tc","katex","react-markdown-editor-lite","react-photo-view","schema-design","monaco-editor","codemirror-json-schema"];export async function getConfig(e){let t=l(e).default;return(p(t)?await t(o):t)??{}}let I=await r(O,f,h,[],v,n),[z,F]=await Promise.all([getConfig(s.configPath),getConfig(s.customConfigPath)]),M={mode:O,strict:!1,devtool:!1,seo:!1,bundleAnalyzer:!1,polyfill:!1,entry:{},minifier:(!!x||!b)&&{},sourceMap:{filename:"[file].map",publicPath:"",namespace:y,moduleFilenameTemplate:"moneko://[namespace]/[resource-path]?[loaders]",fallbackModuleFilenameTemplate:"moneko://[namespace]/[resource-path]?[loaders]"},env:I,basename:"/",publicPath:"auto",rem:{designSize:C?375:1920},fallbackCompPath:null,modifyVars:{},prefixCls:"n",alias:Object.assign({"@":u(w)},P&&g<18?{"react/package.json":c("react/package.json"),"react/jsx-runtime":c("react/jsx-runtime.js"),"react/jsx-dev-runtime":c("react/jsx-dev-runtime.js")}:{}),moduleRules:[],prefixJsLoader:[],cssModules:[],cssModuleDefinition:!0,importOnDemand:{},proxy:{},devServer:{host:"localhost",port:3e3,open:!0},htmlPluginOption:{title:y.toLocaleUpperCase(),favicon:"https://h5static.dewucdn.com/node-common/718d5e10-576d-8b14-b0b1-e4c58c3b3f40.webp"},copy:{},routerMode:"browser",fixBrowserRouter:!1,plugins:[],resolvePlugins:[],overrideResolve:!1,splitChunk:m,runtimeChunk:"single",moduleFederation:[],rulesInclude:{css:S,js:S,media:S,font:S,wasm:[]},mdx:{jsx:!1,development:b,jsxImportSource:k,providerImportSource:`@moneko/${h}/mdx`},jsxDomExpressions:a,bar:{name:"Client",nameColor:"68",msgColor:"242",barBgColor:"15",barColor:"69",quiet:x},normalizeCss:!0,externalsPresets:{},buildHttp:void 0,virtualModule:{},cssExtract:{},externals:["@swc/core"],lazyCompilation:!1,performance:!1,refresh:"solid"!==h,bundleId:"com.moneko.bid",bundles:[],stylelint:{},eslint:{lintDirtyModulesOnly:!1},minChunkSize:1e3,compression:!1,manifest:{filename:"site.webmanifest"},corepack:!0,reactJsxRuntime:"automatic"};j&&(M.alias=Object.assign(M.alias,{"@pkg":s.componentsPath,[y]:s.componentsPath}));let A=M;if(A=t(A,z,F),"true"===o.env.CODESPACES&&A.devServer.https&&(A.devServer.https=!1),!1===A.devServer.https&&"darwin"===o.platform&&(A.devServer.open=!1),A.htmlPluginOption&&(A.htmlPluginOption.tags||(A.htmlPluginOption.tags=[]),A.fixBrowserRouter&&A.htmlPluginOption.tags.push({textContent:"(function(l) {if (l.search[1] === '/' ) {var decoded = l.search.slice(1).split('&').map(function(s) {return s.replace(/~and~/g, '&')}).join('?');window.history.replaceState(null, null,l.pathname.slice(0, -1) + decoded + l.hash);}}(window.location))"}),A.manifest)){let o=A.manifest.publicPath??A.htmlPluginOption.publicPath??A.publicPath??"/";A.htmlPluginOption.tags.push({href:i("auto"===o?"/":o,A.manifest.filename).replaceAll(e,"/"),tag:"link",rel:"manifest"})}export const CONFIG=A;export const PUBLICPATH="auto"===CONFIG.publicPath?"":CONFIG.publicPath;d(CONFIG);
|