Compare commits

...

100 Commits

Author SHA1 Message Date
手瓜一十雪
c54f74609e Update version keys from 9.9.23-42744 to 9.9.25-42744
Renamed version keys in appid.json, napi2native.json, and packet.json from 9.9.23-42744(-x64) to 9.9.25-42744(-x64) to reflect the new version. Associated values remain unchanged.
2025-11-28 17:25:28 +08:00
手瓜一十雪
a2d7ac4878 Add support for new app and protocol versions
Updated appid.json, napi2native.json, and packet.json to include entries for versions 9.9.23-42744 and 6.9.86-42744, as well as their corresponding protocol mappings for x64 and arm64 architectures.
2025-11-26 19:43:14 +08:00
手瓜一十雪
fd0afa3b25 Add support for 9.9.23-42430-x64 in napi2native and packet
Updated napi2native.json and packet.json to include send and recv addresses for version 9.9.23-42430-x64, enabling compatibility with this new version.
2025-11-26 19:15:02 +08:00
手瓜一十雪
7685cc3dfc Prefix version numbers with 'v' in system info
Updated the display of current and latest version numbers in the system info component to include a 'v' prefix for consistency and clarity.
2025-11-25 23:10:10 +08:00
手瓜一十雪
f9c0b9d106 Remove leading 'v' from latest tag in getLatestTag
Updated the getLatestTag function to strip a leading 'v' character from the latest tag before returning it. This ensures tag values are returned without the 'v' prefix.
2025-11-25 23:09:53 +08:00
手瓜一十雪
d31f0a45b4 Fix version tag formatting and error handling
Update packet.ts to prefix napCatVersion with 'v' in the error message link. In vite-plugin-version.js, improve formatting of catch blocks, ensure returned tags do not include a leading 'v', and standardize fallback version to '0.0.0'.
2025-11-25 23:03:55 +08:00
huan-yp
7c701781a1 Fix URL formatting in error message for QQ version (#1396) 2025-11-25 12:59:37 +08:00
时瑾
3c612e03ff feat: close #1394 2025-11-24 12:47:04 +08:00
手瓜一十雪
f27db01145 Update onMSFSsoError signature with code and desc
The onMSFSsoError method now accepts a numeric code and a string description as parameters instead of a single unknown argument. This change clarifies the expected input for error handling.
2025-11-22 20:30:02 +08:00
手瓜一十雪
ae97cfba03 Refine types in storage clean listener and service
Updated method signatures in NodeIKernelStorageCleanListener and NodeIKernelStorageCleanService to use more specific types and parameter names. This improves type safety and code clarity, particularly for cache scanning and listener methods.
2025-11-22 19:57:18 +08:00
手瓜一十雪
162ddc1bf5 fix: #1392 & Remove update functionality from VersionInfo component
Eliminated the update button and related logic from the VersionInfo component in the about page. This includes removing the useRequest hook for updating, the toast notifications, and the Button component, simplifying the component to only display version information.
2025-11-22 18:31:42 +08:00
手瓜一十雪
afb6ef421a Add Passkey (WebAuthn) authentication support
Introduces Passkey (WebAuthn) registration and authentication to both backend and frontend. Backend adds new API endpoints, middleware exceptions, and a PasskeyHelper for credential management using @simplewebauthn/server. Frontend integrates @simplewebauthn/browser, updates login and config pages for Passkey registration and login flows, and adds related UI and controller methods.
2025-11-22 16:00:32 +08:00
手瓜一十雪
173a165c4b Add latest version check and update prompt to UI
Introduces backend and frontend logic to fetch the latest NapCat version tag from multiple sources, exposes a new API endpoint, and adds a UI prompt to notify users of new versions with an update button. Also includes minor code style improvements in dialog context.
2025-11-22 13:52:49 +08:00
手瓜一十雪
d525f9b03d Refactor and standardize share and message history APIs
Standardized field names (e.g., 'reverseOrder' to 'reverse_order', 'phoneNumber' to 'phone_number') and added new action names and classes for sharing contacts and group cards (SendArkShare, SendGroupArkShare). Deprecated old action names, updated API schemas and routes, and ensured backward compatibility for legacy fields. Updated frontend API definitions to match backend changes.
2025-11-22 13:14:46 +08:00
zeus-x99
f2ba789cc0 fix(webui-backend): 仅在启用 WebUI 时检测/更新默认密码 (#1387)
在初始化 WebUI 时,先判断  并直接返回,确保禁用状态下不再检测或更新默认密码 token。
2025-11-20 14:38:59 +08:00
手瓜一十雪
2cdc9bdc09 Add backend and frontend support for NapCat auto-update
Introduces backend API and router for updating NapCat, including update logic and pending update application on startup. Adds frontend integration with update button and request handling. Refactors system info component to remove legacy new version tip. Updates types and runtime to track working environment for update selection. Implements lazy loading for pty in unixTerminal to avoid early initialization.
2025-11-19 21:05:08 +08:00
手瓜一十雪
c123b34d5f Update ffmpeg addon binary for Darwin ARM64
Replaces the ffmpegAddon.darwin.arm64.node binary with a new version, likely to include bug fixes or performance improvements for ARM64 macOS systems.
2025-11-18 20:16:03 +08:00
手瓜一十雪
d25b43ebf2 Update ffmpeg native binaries for Linux
Replaces ffmpegAddon.linux.arm64.node and ffmpegAddon.linux.x64.node with new versions. This may include bug fixes, performance improvements, or compatibility updates for native ffmpeg functionality.
2025-11-18 17:36:09 +08:00
时瑾
8fe4a9e6ac 更新 Bug 反馈模板,增强对不当内容的说明和合规性要求 2025-11-16 15:55:25 +08:00
手瓜一十雪
09da80aad5 Remove unused dependencies from package.json
Deleted the 'dependencies' section from napcat-qrcode/package.json, removing references to napcat-core, napcat-common, napcat-onebot, and napcat-webui-backend. This streamlines the package configuration and may indicate these dependencies are no longer required.
2025-11-16 11:02:21 +08:00
手瓜一十雪
3d3f718fd5 Refactor interfaces and decouple backend dependencies
Introduced new interface definitions in napcat-common for logging, status, and subscription. Refactored napcat-webui-backend to use these interfaces, decoupling it from napcat-core and napcat-onebot. Moved OneBot config schema to backend and updated imports. Updated framework and shell to pass subscriptions to InitWebUi. Improved type safety and modularity across backend and shared packages.
2025-11-16 10:58:30 +08:00
手瓜一十雪
6068abdec0 Update VSCode settings for formatting and file nesting
Enhanced .vscode/settings.json with file nesting patterns, formatting preferences, auto-save behavior, and import specifier options for JavaScript and TypeScript. Removed old debug source map overrides to streamline workspace configuration.
2025-11-15 17:17:24 +08:00
手瓜一十雪
3957d7af5a Use environment variables for secret keys in dev and backend
Set fixed secret keys for JWT and WebUI in development environment via environment variables. Updated backend to use NAPCAT_WEBUI_SECRET_KEY and NAPCAT_WEBUI_JWT_SECRET_KEY from environment if available, improving configurability and security.
2025-11-15 17:00:52 +08:00
手瓜一十雪
a2837974fe Add VSCode launch and TailwindCSS config files
Added .vscode/launch.json for Node.js debugging and .vscode/tailwindcss.json for TailwindCSS directive support in VSCode. These files improve development workflow and editor integration.
2025-11-15 16:51:46 +08:00
手瓜一十雪
6f8edfe570 清理重复的 Vitest configuration file
Deleted vitest.config.ts, which contained test environment and path alias settings. This may indicate a change in testing strategy or migration away from Vitest.
2025-11-15 16:42:50 +08:00
手瓜一十雪
0b655db4dd Add test step to build workflow
Inserts 'pnpm test' into both build jobs in the GitHub Actions workflow to ensure tests are run during CI before building artifacts.
2025-11-15 16:25:06 +08:00
手瓜一十雪
d800466a30 Move inversify and reflect-metadata to napcat-core
Transferred 'inversify' and 'reflect-metadata' dependencies from the root package.json to packages/napcat-core/package.json to better scope dependencies and improve project organization.
2025-11-15 16:23:03 +08:00
手瓜一十雪
fa80441e36 Add ESLint config and update code style
Introduced a new eslint.config.js using neostandard and added related devDependencies. Updated codebase for consistent formatting, spacing, and function declarations. Minor refactoring and cleanup across multiple files to improve readability and maintain code style compliance.
2025-11-15 16:21:59 +08:00
手瓜一十雪
1990761ad6 Update main entry and tsconfig for JS support
Changed package.json main and exports to use index.js instead of index.cjs. Updated tsconfig.json to allow JavaScript files and expanded include patterns to support both JS and TS files.
2025-11-15 16:09:26 +08:00
手瓜一十雪
ef63812391 Add napcat-test package and Vitest setup
Introduces the napcat-test package with initial SHA-1 stream tests, configuration files, and scripts for running tests. Updates root package.json to include test commands and Vitest dependencies, and adds Vitest configuration at the root and package level for test environment setup.
2025-11-15 16:05:09 +08:00
手瓜一十雪
0f033b0ac8 Remove performance monitor module
Deleted performance-monitor.ts from napcat-common, removing the function statistics and reporting utility. This may indicate a refactor or replacement of performance monitoring functionality.
2025-11-15 15:13:56 +08:00
手瓜一十雪
9fdef3cde9 Revert "Update default model in release workflow"
This reverts commit d32ccc6eb5.
2025-11-15 14:56:34 +08:00
手瓜一十雪
20e8643193 Fix import paths for require_dlopen module
Updated import statements in prebuild-loader.ts and windowsPtyAgent.ts to use relative path './index' for require_dlopen. This resolves incorrect module resolution issues.
2025-11-15 14:43:08 +08:00
手瓜一十雪
8645ed4d9d Update tsconfig to include typeRoots and format paths
Added 'typeRoots' to specify custom type definitions directory and reformatted the 'paths' property for better readability. This improves TypeScript type resolution and project maintainability.
2025-11-15 14:40:06 +08:00
手瓜一十雪
c0b9817ff5 Add type checking to build workflow
Incorporates 'pnpm run typecheck' into the build steps for both frontend and shell jobs to ensure type safety during CI builds.
2025-11-15 14:01:11 +08:00
手瓜一十雪
b147e57c1c Refactor TypeScript configs to use shared base
Introduced tsconfig.base.json for shared TypeScript configuration and updated all package tsconfig.json files to extend from it, reducing duplication and improving maintainability. Also updated typecheck script in package.json and fixed import in prebuild-loader.ts.
2025-11-15 14:00:27 +08:00
手瓜一十雪
ad4a108781 feat: 大规模去耦合
Moved various helper, event, and utility files from napcat-common to napcat-core/helper for better modularity and separation of concerns. Updated imports across packages to reflect new file locations. Removed unused dependencies from napcat-common and added them to napcat-core where needed. Also consolidated type definitions and cleaned up tsconfig settings for improved compatibility.
2025-11-15 13:36:33 +08:00
手瓜一十雪
df824d77ae feat: 所有的类型检查 2025-11-15 12:57:19 +08:00
手瓜一十雪
19888d52dc Remove unused test utility files
Deleted test.ts and test2.ts from utils as they are no longer needed for the project.
2025-11-15 12:02:07 +08:00
手瓜一十雪
4dc8b3ed3b Refactor FileApi usage to obContext in OneBot
Replaced references to `core.apis.FileApi` with `obContext.apis.FileApi` across actions and message API to ensure consistent context usage. Added FileApi to the ApiListType and initialized it in NapCatOneBot11Adapter. This improves maintainability and context handling for file-related operations.
2025-11-15 11:20:01 +08:00
手瓜一十雪
8df54d5cd3 feat: 去core耦合onebot
Moved file element creation methods (for file, picture, video, and ptt) from napcat-core/apis/file.ts to a new OneBotFileApi class in napcat-onebot/api/file.ts. Updated package.json dependencies to remove unused packages and fix workspace references. This improves separation of concerns and modularity between core and onebot-specific logic.
2025-11-15 11:17:57 +08:00
手瓜一十雪
aa982b3071 Improve version folder selection in loadNapCat.cjs
Enhanced logic to handle multiple or missing version folders by selecting the most recently modified folder if more than one exists, and providing clearer error messages. Also updated .vscode/settings.json to add source map path overrides for additional packages.
2025-11-15 10:58:33 +08:00
手瓜一十雪
8e71dec63a Bind TypedEventEmitter to DI container and update usage
Added TypedEventEmitter to the dependency injection container and exposed it in ServiceBase. Updated OlPushService to use the injected event emitter instead of directly importing appEvent. Also performed minor code style improvements for consistency.
2025-11-15 10:48:59 +08:00
手瓜一十雪
31bb1e5dee Add emoji like event handling to core and onebot
Introduces a typed event emitter for app events in napcat-core, specifically for emoji like events in groups. OlPushService now emits 'event:emoji_like' when a group reaction is detected. napcat-onebot listens for this event and emits corresponding OneBot events. Refactors and adds missing type definitions and improves method formatting for consistency.
2025-11-15 10:45:02 +08:00
手瓜一十雪
75e1e8dd79 Improve error handling in release workflow
Enhances the OpenRouter API call step by adding error handling for both curl and jq failures. If the API call or response parsing fails, the workflow now falls back to using a default release note template.
2025-11-14 23:00:20 +08:00
手瓜一十雪
d32ccc6eb5 Update default model in release workflow
Changed the OPENROUTER_MODEL environment variable from 'kimi-k2-0905-turbo' to 'glm-4.6-turbo' in the release workflow configuration.
2025-11-14 22:45:17 +08:00
手瓜一十雪
7b3e94d568 Add raw response output to release workflow
Added echo statements to display the raw API response in the release workflow for improved debugging and visibility.
2025-11-14 22:35:58 +08:00
手瓜一十雪
5cfe479044 Refactor createListenerFunction type and usage
Simplifies the generic type signature of createListenerFunction and updates the way createEventFunction is called, removing unnecessary type parameters and using a direct function call with TypeScript ignore for type checking.
2025-11-14 22:24:50 +08:00
手瓜一十雪
f04ffa5dc6 Add service handler registration and DI support
Introduces dependency injection via Inversify and reflect-metadata, adds a service handler registry for packet handling, and updates core initialization to auto-register and bind service handlers. Also updates Vite configs and auto-include logic to support protocol service files.
2025-11-14 22:20:33 +08:00
手瓜一十雪
a2a73ce2dd Add dev build script and improve Vite config
Introduces a 'build:shell:dev' script for development builds and updates napcat-shell's Vite config to conditionally enable source maps in development mode. This enhances build flexibility for development and production environments.
2025-11-14 21:25:29 +08:00
手瓜一十雪
66d02eeb6a Enable source maps and improve debugging support
This commit enables source maps in napcat-shell's Vite config for better debugging, adds source map path overrides to VSCode settings, and updates nodeTest.ps1 to launch with the Node.js inspector. The autoIncludeTSPlugin transform now returns a source map for improved breakpoint support in VSCode. Also adds a sources.txt file listing project and dependency sources.
2025-11-14 21:21:49 +08:00
手瓜一十雪
b99c0ca437 Set fetch-depth to 0 in release workflow
Configures the checkout step in the release workflow to use fetch-depth: 0, ensuring the full git history is available for subsequent steps.
2025-11-14 20:06:01 +08:00
手瓜一十雪
019b90984d Add napcat-vite dependency and plugin integration
Added 'napcat-vite' as a workspace dependency in package.json and integrated its version plugin into the Vite configuration. This enables version management features provided by napcat-vite for the framework.
2025-11-14 19:54:33 +08:00
手瓜一十雪
5043a49779 feat: 装饰器与装饰器路由注册 2025-11-14 19:49:13 +08:00
手瓜一十雪
36aa08a8f5 Replace nap-proto-core with napcat-protobuf package
Switched all imports from '@napneko/nap-proto-core' to the new 'napcat-protobuf' package across napcat-core and related packages. Updated dependencies and references to support the new package structure, improving maintainability and workspace integration.
2025-11-14 16:19:26 +08:00
手瓜一十雪
8bc8df32f9 Update type declarations and remove ts-ignore comments
Added 'types' field to package.json and updated tsconfig.json to include .d.ts files for better type support in napcat-pty. Removed unnecessary @ts-ignore comments from terminal_manager.ts to improve code clarity.
2025-11-14 15:00:40 +08:00
手瓜一十雪
bc183ae002 Remove unnecessary ts-ignore comments and improve typings
Removed redundant // @ts-ignore comments from converter.ts and http-server.ts. Enhanced type safety in event.ts by refining generic parameters for createListenerFunction and createEventFunction.
2025-11-14 14:53:21 +08:00
手瓜一十雪
b85f9197e3 Remove unused path aliases from tsconfig files
Deleted redundant or unused path alias entries from tsconfig.json in napcat-core, napcat-onebot, and napcat-plugin packages to simplify TypeScript configuration and avoid confusion.
2025-11-14 14:37:43 +08:00
手瓜一十雪
c8fd66fa9b Refactor imports to use package names instead of aliases
Replaced all path alias imports (e.g., '@/napcat-core') with direct package imports (e.g., 'napcat-core/index') across napcat-common, napcat-core, and napcat-webui-backend. This improves compatibility with tooling and workspace resolution, and aligns with standard TypeScript/Node.js import practices.
2025-11-14 14:34:27 +08:00
手瓜一十雪
6e9f448a0c Add feature request issue template
Introduces a new GitHub issue template for submitting feature requests and improvement suggestions for NapCat. The template guides users to provide relevant version information, detailed descriptions, background, and expected outcomes.
2025-11-14 13:15:01 +08:00
手瓜一十雪
142016778f Rename workflow job to node-shell-docker
Changed the job name from 'trigger-napcat-release' to 'node-shell-docker' in the trigger-docker-publish.yml workflow for improved clarity.
2025-11-14 13:12:21 +08:00
手瓜一十雪
159fb8cd3a Rename workflow job from Build-LiteLoader to Build-Framework
Updated workflow job names and dependencies in auto-release.yml, build.yml, and release.yml from 'Build-LiteLoader' to 'Build-Framework' for clarity and consistency. Also updated bug report template to reference version location in WebUI instead of settings page.
2025-11-14 13:05:29 +08:00
手瓜一十雪
01c911e178 Add workflows to trigger NapCat release builds
Introduces two new GitHub Actions jobs: one to trigger NapCat AppImage builds and another for NapCat Linux Node Loader releases. Both jobs fetch the latest NapCat version tag and use fixed QQ AppImage URLs for x86_64 and arm64 architectures.
2025-11-14 13:02:16 +08:00
手瓜一十雪
8b3ea8dcef Add workflow to trigger framework Docker publish
Introduces a new job in the GitHub Actions workflow to trigger the docker-image publish workflow for the NapCat.Docker.Framework repository. This enables automated publishing of the framework Docker image alongside the existing NapCat-Docker image.
2025-11-14 12:48:46 +08:00
手瓜一十雪
fe8b270ab3 Add workflow to trigger Docker publish on release
Introduces a GitHub Actions workflow that triggers the NapCat-Docker docker-publish workflow when a release is published. This automates Docker image publishing upon new releases.
2025-11-14 12:44:26 +08:00
手瓜一十雪
f02ae5894f Update QQ x64 download URL in auto-release workflow
Replaces dynamic retrieval of the QQ x64 download URL with a static direct link in the auto-release GitHub Actions workflow. This change improves reliability by avoiding proxy and parsing steps.
2025-11-14 12:39:15 +08:00
手瓜一十雪
a6a0b408af Update QQ x64 download URL in release workflow
Changed the QQ x64 config JS URL to use a proxy service instead of the direct CDN link in the auto-release workflow. This may help bypass access restrictions or improve reliability.
2025-11-14 12:37:32 +08:00
手瓜一十雪
e9856ac80f Refactor version API to GetNapCatVersion endpoint
Replaces the PackageInfo API and related frontend usage with a dedicated GetNapCatVersion endpoint that returns only the NapCat version string. Updates backend handler, helper, types, router, and frontend components to use the new API for improved clarity and separation of concerns.
2025-11-14 12:10:57 +08:00
手瓜一十雪
f553f9dc8d fix: webui version 2025-11-14 11:51:23 +08:00
手瓜一十雪
5608638e9a Update OpenRouter API URL and model in workflow
Changed the OpenRouter API endpoint and model in the auto-release GitHub Actions workflow to use new values. This may reflect a migration to a different service or model for automated releases.
2025-11-13 21:02:28 +08:00
手瓜一十雪
a53c20767a Update artifact zipping to exclude parent folder
Changed the zip commands in the auto-release workflow to zip the contents of each artifact directory rather than the directory itself. This ensures the resulting zip files do not include an extra parent folder.
2025-11-13 20:59:31 +08:00
手瓜一十雪
a92bef5b33 Update release note prompt and workflow wording
Clarified instructions in release_note_prompt.txt to use the provided version number and updated the example version. Modified auto-release.yml to specify '当前真正的版本' in the user content for improved clarity.
2025-11-13 20:54:19 +08:00
手瓜一十雪
a9a3b6ec6e Copy QQNT.dll in auto-release workflow
Adds a step to copy QQNT.dll from napcat-develop to the output directory in the auto-release workflow. Ensures the DLL is included in release artifacts.
2025-11-13 20:51:29 +08:00
手瓜一十雪
20d41fff9e Update output directory and file copy paths in release workflow
Changed output directory from 'napcat' to 'NapCat.Shell.Windows.Node' and updated all related file copy and artifact upload paths to match. This aligns the workflow with the new directory structure and ensures correct packaging of release artifacts.
2025-11-13 20:45:51 +08:00
手瓜一十雪
0b4d7e1346 Remove unused dependencies from package.json
Deleted workspace dependencies from napcat-vite/package.json, likely because they are no longer required or managed elsewhere.
2025-11-13 20:09:44 +08:00
手瓜一十雪
46b9049a24 Update user content format in auto-release workflow
Changed the user content string in the auto-release workflow to use '当前版本' instead of 'TAG' for improved clarity in release notes.
2025-11-13 20:04:31 +08:00
手瓜一十雪
521f4dc365 Include Windows Node shell in release workflow
Adds NapCat.Shell.Windows.Node to the release process by updating dependencies, packaging steps, and release artifacts in auto-release.yml.
2025-11-13 20:02:42 +08:00
手瓜一十雪
04b507d749 Add debug output for OpenRouter request body
Prints the OpenRouter API request body in the workflow using jq for easier debugging and inspection of outgoing requests.
2025-11-13 19:59:36 +08:00
手瓜一十雪
5638127813 Add default prompt and update release workflow
Added .github/prompt/default.md with deployment instructions and download links. Updated auto-release.yml to copy NapCat.Shell directory contents instead of unzipping the archive.
2025-11-13 19:58:10 +08:00
手瓜一十雪
30a7797ba9 Reduce aria2c parallelism in auto-release workflow
Changed aria2c download options from 16 connections to 1 in the auto-release workflow. This may help avoid issues with rate limiting or unstable downloads from the Node.js distribution server.
2025-11-13 19:53:05 +08:00
手瓜一十雪
d09a82b1b8 Add Windows packaging workflow and NapCat entry files
Introduces a new GitHub Actions job to automate packaging NapCat for Windows, including downloading dependencies and assembling artifacts. Adds napcat.bat and index.js entry files for Windows distribution in packages/napcat-develop.
2025-11-13 19:48:15 +08:00
手瓜一十雪
85b5c881ba Add napcat-develop package and update scripts
Introduces the napcat-develop package with its own package.json and tsconfig.json. Updates build and dev scripts in the root package.json, modifies loadNapCat.cjs to adjust paths and output directories, and updates nodeTest.ps1 to use the correct script path.
2025-11-13 19:30:33 +08:00
手瓜一十雪
eebce222cf Update release note prompt formatting and examples
Changed the commit id placement in update items for clarity and added more example update entries to guide contributors in writing release notes.
2025-11-13 19:20:13 +08:00
手瓜一十雪
ec5ca5d89a Improve tag handling in auto-release workflow
Switches tag retrieval to use the GitHub API and sorts tags with jq for more reliable ordering. Adds explicit GITHUB_OWNER and GITHUB_REPO variables, improves previous tag selection logic, and ensures tags are fetched before generating release notes. Also adds more informative logging for debugging.
2025-11-13 19:16:12 +08:00
手瓜一十雪
31a7767ae4 Improve previous tag detection in auto-release workflow
Replaces 'git describe' with logic to find the previous tag by sorting all tags by creation date. This ensures accurate detection of the previous tag for release note generation and adds error handling if no previous tag is found.
2025-11-13 19:06:06 +08:00
手瓜一十雪
fec024334a Update release note prompt formatting instructions
Clarified that output must strictly follow the NapCat release note format and example. Updated constraints and replaced the example section with a real example for better guidance.
2025-11-13 19:03:28 +08:00
手瓜一十雪
2ad2af4d7c Trigger release workflow on tag push
Changed the workflow trigger from pushes to the main branch to pushes of any tag. This enables releases to be automatically created when a new tag is pushed.
2025-11-13 18:57:37 +08:00
手瓜一十雪
2a160d296f Remove tag trigger from auto-release workflow
The workflow will no longer be triggered by tag pushes, only by pushes to the main branch.
2025-11-13 18:57:20 +08:00
手瓜一十雪
e43f229e04 Update import paths to use direct module references
Changed import statements from alias-based paths (e.g., '@/napcat-common/store') to direct module references (e.g., 'napcat-common/src/store') in Proxy.ts, Status.ts, Data.ts, and SignToken.ts for improved compatibility and clarity.
2025-11-13 18:56:51 +08:00
手瓜一十雪
9158ebc136 Update workflow name to AI RELEASE NapCat
Renamed the GitHub Actions workflow from 'Build Action' to 'AI RELEASE NapCat' for improved clarity and identification.
2025-11-13 18:55:01 +08:00
手瓜一十雪
d758fe3a2b Improve release note generation in workflow
Enhances the release note generation step to compare commits between the previous and current tags, includes commit bodies and authors, and formats output for better readability. Also adds more robust extraction and output handling for the generated release notes.
2025-11-13 18:53:19 +08:00
手瓜一十雪
4abd0668a3 Refactor auto-release workflow for clarity and reliability
Renamed workflow, improved job and step naming, and streamlined artifact zipping and release note generation. Switched to using softprops/action-gh-release for release creation and asset upload, removed manual commit list preparation, and enhanced error handling for release note generation. Updated permissions and environment variables for consistency.
2025-11-13 18:46:48 +08:00
手瓜一十雪
0181700c3b feat: 自动化version打包 2025-11-13 18:31:55 +08:00
手瓜一十雪
6083e9cfcc feat: 以后仅维护napCatVersion 2025-11-13 16:14:31 +08:00
手瓜一十雪
5fec190c70 Remove package-lock.json
Deleted the package-lock.json file, possibly to reset dependency lock state or switch package managers. Ensure to regenerate lock file if needed for consistent dependency management.
2025-11-13 16:12:00 +08:00
手瓜一十雪
e1743ae5e4 Switch build and release workflows to npm install
Replaces pnpm install with npm install --omit=dev in both framework and shell build steps for build and release workflows. Removes package-lock.json after installation to avoid including it in artifacts.
2025-11-13 15:57:05 +08:00
手瓜一十雪
ded921c55e Update pnpm install flags in CI workflows
Replaces '--production' with '--prod --shamefully-hoist' in build and release GitHub Actions workflows to improve dependency installation compatibility.
2025-11-13 15:53:37 +08:00
手瓜一十雪
57e717e898 Update artifact paths in build and release workflows
Artifacts for NapCat.Framework and NapCat.Shell are now moved to 'framework-dist' and 'shell-dist' directories before upload. This change standardizes output locations and updates the upload paths accordingly in both build.yml and release.yml.
2025-11-13 15:49:11 +08:00
手瓜一十雪
55f21c6caa Install pnpm globally in build and release workflows
Added 'npm i -g pnpm' to both build and release GitHub Actions workflows to ensure pnpm is available before running installation and build commands.
2025-11-13 15:42:05 +08:00
手瓜一十雪
4360775eff refactor: 整体重构 (#1381)
* feat: pnpm new

* Refactor build and release workflows, update dependencies

Switch build scripts and workflows from npm to pnpm, update build and artifact paths, and simplify release workflow by removing version detection and changelog steps. Add new dependencies (silk-wasm, express, ws, node-pty-prebuilt-multiarch), update exports in package.json files, and add vite config for napcat-framework. Also, rename manifest.json for framework package and fix static asset copying in shell build config.
2025-11-13 15:39:42 +08:00
826 changed files with 5851 additions and 28994 deletions

View File

@@ -1,2 +0,0 @@
VITE_BUILD_TYPE = Production
VITE_BUILD_PLATFORM = Framework

View File

@@ -1,2 +0,0 @@
VITE_BUILD_TYPE = Production
VITE_BUILD_PLATFORM = Shell

View File

@@ -1,2 +0,0 @@
VITE_BUILD_TYPE = DEBUG
VITE_BUILD_PLATFORM = Shell

View File

@@ -1,2 +0,0 @@
VITE_BUILD_TYPE = Production
VITE_BUILD_PLATFORM = Universal

View File

@@ -1,6 +1,6 @@
name: Bug 反馈
description: 报告可能的 NapCat 异常行为
title: '[BUG] '
title: "[BUG] "
labels: bug
body:
- type: markdown
@@ -10,6 +10,10 @@ body:
在提交新的 Bug 反馈前,请确保您:
* 已经搜索了现有的 issues并且没有找到可以解决您问题的方法
* 不与现有的某一 issue 重复
* **不接受因发送不当内容而导致的问题报告**
- 包括但不限于:多媒体发送失败、转发消息失败、消息被拦截等因 18+ 内容、违规内容或触发风控的问题
- 提交 issue 前,请确认您发送的多媒体内容、链接、文本等均为正常合规内容,不会触发平台风控机制
- 因违规内容导致的问题,一律不予受理
- type: input
id: system-version
attributes:
@@ -30,7 +34,7 @@ body:
id: napcat-version
attributes:
label: NapCat 版本
description: 可在 LiteLoaderQQNT 的设置页或是 QQNT 的设置页侧栏中找到
description: 可在 WebUI 的「系统信息」页中找到
placeholder: 1.0.0
validations:
required: true

60
.github/ISSUE_TEMPLATE/feat_request.yml vendored Normal file
View File

@@ -0,0 +1,60 @@
name: Feat 请求
description: 提交新的 NapCat 功能或改进建议
title: '[FEAT] '
labels: enhancement
body:
- type: markdown
attributes:
value: |
欢迎来到 NapCat 的 Issue Tracker请填写以下表格来提交功能请求。
在提交新的功能请求前,请确保您:
* 已经搜索了现有的 issues并且没有找到类似的建议
* 不与现有的某一 issue 重复
- type: input
id: system-version
attributes:
label: 系统版本
description: 运行 QQNT 的系统版本
placeholder: Windows 11 24H2
validations:
required: true
- type: input
id: qqnt-version
attributes:
label: QQNT 版本
description: 可在 QQNT 的「关于」的设置页中找到
placeholder: 9.9.16-29927
validations:
required: true
- type: input
id: napcat-version
attributes:
label: NapCat 版本
description: 可在 WebUI 的「系统信息」页中找到
placeholder: 1.0.0
validations:
required: true
- type: textarea
id: feature-description
attributes:
label: 功能描述
description: 请详细描述你希望添加的功能或改进
validations:
required: true
- type: textarea
id: feature-reason
attributes:
label: 需求背景与理由
description: 请说明为什么需要这个功能,解决了什么问题
validations:
required: true
- type: textarea
id: feature-expected
attributes:
label: 期望的实现方式或效果
description: 请描述你期望的功能实现方式或最终效果
- type: textarea
id: other-info
attributes:
label: 其他补充信息
description: 你还想补充什么?

27
.github/prompt/default.md vendored Normal file
View File

@@ -0,0 +1,27 @@
# V?.?.?
[使用文档](https://napneko.github.io/)
## Windows 一键包
我们为提供了的轻量化一键部署方案
相对于普通需要安装QQ的方案,下面已内置QQ和Napcat 阅读使用文档参考
你可以下载
NapCat.Shell.Windows.OneKey.zip (无头)
启动后可自动化部署一键包,教程参考使用文档安装部分
## 警告
**注意QQ版本推荐使用 40768+ 版本 最低可以使用40768版本**
**默认WebUi密钥为随机密码 控制台查看**
**[9.9.22-40990 X64 Win](https://dldir1v6.qq.com/qqfile/qq/QQNT/2c9d3f6c/QQ9.9.22.40990_x64.exe)**
[LinuxX64 DEB 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_amd64.deb)
[LinuxX64 RPM 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_x86_64.rpm)
[LinuxArm64 DEB 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_arm64.deb)
[LinuxArm64 RPM 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_aarch64.rpm)
[MAC DMG 40990 ](https://dldir1v6.qq.com/qqfile/qq/QQNT/c6cb0f5d/QQ_v6.9.82.40990.dmg)
## 如果WinX64缺少运行库或者xxx.dll
[安装运行库](https://aka.ms/vs/17/release/vc_redist.x64.exe)
## 更新

60
.github/prompt/release_note_prompt.txt vendored Normal file
View File

@@ -0,0 +1,60 @@
注意:输出必须严格使用 NapCat 的发布说明格式,严格保证示例格式,并用简体中文。
格式规则:
1. 第一行:# V{TAG}
2. 第二行:[使用文档](https://napneko.github.io/)
3. 空行后,按下面的节顺序输出(存在则输出,不存在则省略该节):
## Windows 一键包
- 简短一句话介绍一键包用途
- 列出可下载的文件名(只列文件名,不写下载链接)
## 警告
- 如果有需要特别提醒的兼容/运行库/版本要求,写成加粗警告句
## 如果WinX64缺少运行库或者xxx.dll
- 常见运行库建议
## 更新
按数字序列列出主要变更项,每条尽量一句话
- 前缀短 commit id例如1. 修复 get_essence_msg_list 崩溃 (a1b2c3d)
- 保持 4-18 条要点
## 开发者注意
- 列出迁移/接口断裂/配置变更;若无则省略
额外约束:
- 语言简体中文,面向最终用户
下面为真实示例,请完全参考(第一行版本号必须使用用户提供的版本号,例如 v4.9.5
# V4.9.0
[使用文档](https://napneko.github.io/)
## Windows 一键包
我们为提供了的轻量化一键部署方案
相对于普通需要安装QQ的方案,下面已内置QQ和Napcat 阅读使用文档参考
你可以下载
NapCat.Shell.Windows.OneKey.zip (无头)
启动后可自动化部署一键包,教程参考使用文档安装部分
## 警告
**注意QQ版本推荐使用 40768+ 版本 最低可以使用40768版本**
**默认WebUi密钥为随机密码 控制台查看**
**[9.9.22-40990 X64 Win](https://dldir1v6.qq.com/qqfile/qq/QQNT/2c9d3f6c/QQ9.9.22.40990_x64.exe)**
[LinuxX64 DEB 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_amd64.deb)
[LinuxX64 RPM 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_x86_64.rpm)
[LinuxArm64 DEB 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_arm64.deb)
[LinuxArm64 RPM 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_aarch64.rpm)
[MAC DMG 40990 ](https://dldir1v6.qq.com/qqfile/qq/QQNT/c6cb0f5d/QQ_v6.9.82.40990.dmg)
## 如果WinX64缺少运行库或者xxx.dll
[安装运行库](https://aka.ms/vs/17/release/vc_redist.x64.exe)
## 更新
1. 修改了XXXXX
2. 新增了XXXX
3. 重构了XXXX

83
.github/workflows/auto-release.yml vendored Normal file
View File

@@ -0,0 +1,83 @@
name: Auto Release Docker
on:
release:
types: [published]
jobs:
shell-docker:
runs-on: ubuntu-latest
steps:
- name: Trigger NapCat-Docker docker-publish workflow
env:
GH_TOKEN: ${{ secrets.NAPCAT_BUILD }}
run: |
curl -X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GH_TOKEN" \
https://api.github.com/repos/NapNeko/NapCat-Docker/actions/workflows/docker-publish.yml/dispatches \
-d '{"ref":"main"}'
framework-docker:
runs-on: ubuntu-latest
steps:
- name: Trigger NapCat-Framework-Docker docker-publish workflow
env:
GH_TOKEN: ${{ secrets.NAPCAT_BUILD }}
run: |
curl -X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GH_TOKEN" \
https://api.github.com/repos/NapNeko/NapCat.Docker.Framework/actions/workflows/docker-image.yml/dispatches \
-d '{"ref":"main"}'
appimage-shell-docker:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Get Latest NapCat Version
id: get_version
run: |
# 获取当前仓库的最新 tag
latest_tag=$(git describe --tags $(git rev-list --tags --max-count=1))
# 输出调试信息
echo "Debug: Latest NapCat Version is ${latest_tag}"
echo "latest_tag=${latest_tag}" >> $GITHUB_ENV
- name: Trigger Release NapCat AppImage Workflow
env:
GH_TOKEN: ${{ secrets.NAPCAT_BUILD }}
NAPCAT_VERSION: ${{ env.latest_tag }}
QQ_VERSION_X86_64: 'https://dldir1v6.qq.com/qqfile/qq/QQNT/8015ff90/linuxqq_3.2.21-42086_x86_64.AppImage' # 写死 QQ 版本
QQ_VERSION_ARM64: 'https://dldir1v6.qq.com/qqfile/qq/QQNT/8015ff90/linuxqq_3.2.21-42086_arm64.AppImage' # 写死 QQ 版本
run: |
echo "Debug: Triggering Release NapCat AppImage with napcat_version=${NAPCAT_VERSION}, qq_version_x86_64=${QQ_VERSION_X86_64}, qq_version_arm64=${QQ_VERSION_ARM64}"
curl -X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GH_TOKEN" \
https://api.github.com/repos/NapNeko/NapCatAppImageBuild/actions/workflows/release.yml/dispatches \
-d "{\"ref\":\"main\",\"inputs\":{\"napcat_version\":\"${NAPCAT_VERSION}\",\"qq_version_x86_64\":\"${QQ_VERSION_X86_64}\",\"qq_version_arm64\":\"${QQ_VERSION_ARM64}\"}}"
node-shell-docker:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Get Latest NapCat Version
id: get_version
run: |
# 获取当前仓库的最新 tag
latest_tag=$(git describe --tags $(git rev-list --tags --max-count=1))
# 输出调试信息
echo "Debug: Latest NapCat Version is ${latest_tag}"
echo "latest_tag=${latest_tag}" >> $GITHUB_ENV
- name: Trigger Release NapCat AppImage Workflow
env:
GH_TOKEN: ${{ secrets.NAPCAT_BUILD }}
NAPCAT_VERSION: ${{ env.latest_tag }}
QQ_VERSION_X86_64: 'https://dldir1v6.qq.com/qqfile/qq/QQNT/8015ff90/linuxqq_3.2.21-42086_x86_64.AppImage' # 写死 QQ 版本
QQ_VERSION_ARM64: 'https://dldir1v6.qq.com/qqfile/qq/QQNT/8015ff90/linuxqq_3.2.21-42086_arm64.AppImage' # 写死 QQ 版本
run: |
echo "Debug: Triggering Release NapCat AppImage with napcat_version=${NAPCAT_VERSION}, qq_url_amd64=${QQ_VERSION_X86_64}, qq_url_arm64=${QQ_VERSION_ARM64}"
curl -X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GH_TOKEN" \
https://api.github.com/repos/NapNeko/NapCatLinuxNodeLoader/actions/workflows/release.yml/dispatches \
-d "{\"ref\":\"main\",\"inputs\":{\"napcat_version\":\"${NAPCAT_VERSION}\",\"qq_url_amd64\":\"${QQ_VERSION_X86_64}\",\"qq_url_arm64\":\"${QQ_VERSION_ARM64}\"}}"

View File

@@ -1,13 +1,14 @@
name: "Build Action"
name: Build NapCat Artifacts
on:
push:
pull_request:
workflow_dispatch:
push:
branches:
- main
permissions: write-all
jobs:
Build-LiteLoader:
Build-Framework:
runs-on: ubuntu-latest
steps:
- name: Clone Main Repository
@@ -18,14 +19,21 @@ jobs:
node-version: 20.x
- name: Build NapCat.Framework
run: |
npm i && cd napcat.webui && npm i && cd .. || exit 1
npm run build:framework && npm run depend || exit 1
rm package-lock.json
npm i -g pnpm
pnpm i
pnpm run typecheck || exit 1
pnpm test || exit 1
pnpm --filter napcat-webui-frontend run build || exit 1
pnpm run build:framework
mv packages/napcat-framework/dist framework-dist
cd framework-dist
npm install --omit=dev
rm ./package-lock.json || exit 0
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: NapCat.Framework
path: dist
path: framework-dist
Build-Shell:
runs-on: ubuntu-latest
steps:
@@ -37,11 +45,18 @@ jobs:
node-version: 20.x
- name: Build NapCat.Shell
run: |
npm i && cd napcat.webui && npm i && cd .. || exit 1
npm run build:shell && npm run depend || exit 1
rm package-lock.json
npm i -g pnpm
pnpm i
pnpm run typecheck || exit 1
pnpm test || exit 1
pnpm --filter napcat-webui-frontend run build || exit 1
pnpm run build:shell
mv packages/napcat-shell/dist shell-dist
cd shell-dist
npm install --omit=dev
rm ./package-lock.json || exit 0
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: NapCat.Shell
path: dist
path: shell-dist

View File

@@ -1,153 +1,274 @@
name: "Build Release"
name: Release NapCat
on:
workflow_dispatch:
push:
tags:
- "v*"
- '*'
permissions: write-all
env:
OPENROUTER_API_URL: https://91vip.futureppo.top/v1/chat/completions
OPENROUTER_MODEL: "kimi-k2-0905-turbo"
RELEASE_NAME: "NapCat"
jobs:
check-version:
Build-Framework:
runs-on: ubuntu-latest
steps:
- name: Clone Repository
- name: Clone Main Repository
uses: actions/checkout@v4
with:
ref: main
token: ${{ secrets.GITHUB_TOKEN }}
- name: Extract version from tag
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
- name: Use Node.js 20.X
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Build NapCat.Framework
run: |
npm i -g pnpm
pnpm i
pnpm --filter napcat-webui-frontend run build || exit 1
pnpm run build:framework
mv packages/napcat-framework/dist framework-dist
cd framework-dist
npm install --omit=dev
rm ./package-lock.json || exit 0
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: NapCat.Framework
path: framework-dist
- name: Check Version
run: |
ls
node ./script/checkVersion.cjs
sh ./checkVersion.sh
Build-LiteLoader:
needs: [check-version]
runs-on: ubuntu-latest
steps:
- name: Clone Main Repository
uses: actions/checkout@v4
with:
repository: 'NapNeko/NapCatQQ'
submodules: true
ref: main
token: ${{ secrets.NAPCAT_BUILD }}
- name: Use Node.js 20.X
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Build NuCat Framework
run: |
npm i
cd napcat.webui
npm i
cd ..
npm run build:framework
cd dist
npm i --omit=dev
cd ..
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: NapCat.Framework
path: dist
Build-Shell:
runs-on: ubuntu-latest
needs: [check-version]
steps:
- name: Clone Main Repository
uses: actions/checkout@v4
with:
repository: 'NapNeko/NapCatQQ'
submodules: true
ref: main
token: ${{ secrets.NAPCAT_BUILD }}
- name: Clone Main Repository
uses: actions/checkout@v4
- name: Use Node.js 20.X
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Build NapCat.Shell
run: |
npm i -g pnpm
pnpm i
pnpm --filter napcat-webui-frontend run build || exit 1
pnpm run build:shell
mv packages/napcat-shell/dist shell-dist
cd shell-dist
npm install --omit=dev
rm ./package-lock.json || exit 0
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: NapCat.Shell
path: shell-dist
Download-QNX64:
needs: Build-Shell
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js 20.X
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Build NuCat Shell
run: |
npm i
cd napcat.webui
npm i
cd ..
npm run build:shell
cd dist
npm i --omit=dev
cd ..
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
path: ./artifacts
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: NapCat.Shell
path: dist
- name: Setup tools
run: |
sudo apt update
sudo apt install -y aria2 unzip zip p7zip-full curl jq
- name: Download QQ x64, Node.js and Assemble NapCat.Shell.Windows.Node.zip
run: |
set -euo pipefail
TMPDIR=$(mktemp -d)
cd "$TMPDIR"
# -----------------------------
# 1) 下载 QQ x64
# -----------------------------
# JS_URL="https://cdn-go.cn/qq-web/im.qq.com_new/latest/rainbow/windowsConfig.js"
# JS_URL="https://slave.docadan488.workers.dev/proxy?url=https://cdn-go.cn/qq-web/im.qq.com_new/latest/rainbow/windowsConfig.js"
# NT_URL=$(curl -fsSL "$JS_URL" | grep -oP '"ntDownloadX64Url"\s*:\s*"\K[^"]+')
NT_URL="https://dldir1v6.qq.com/qqfile/qq/QQNT/eb263b35/QQ9.9.23.42086_x64.exe"
QQ_ZIP="$(basename "$NT_URL")"
aria2c -x16 -s16 -k1M -o "$QQ_ZIP" "$NT_URL"
QQ_EXTRACT="$TMPDIR/qq_extracted"
mkdir -p "$QQ_EXTRACT"
7z x -y -o"$QQ_EXTRACT" "$QQ_ZIP" >/dev/null
# -----------------------------
# 2) 下载 Node.js Windows x64 zip 22.11.0
# -----------------------------
NODE_VER="22.11.0"
NODE_URL="https://nodejs.org/dist/v$NODE_VER/node-v$NODE_VER-win-x64.zip"
NODE_ZIP="node-v$NODE_VER-win-x64.zip"
aria2c -x1 -s1 -k1M -o "$NODE_ZIP" "$NODE_URL"
NODE_EXTRACT="$TMPDIR/node_extracted"
mkdir -p "$NODE_EXTRACT"
unzip -q "$NODE_ZIP" -d "$NODE_EXTRACT"
# -----------------------------
# 3) 创建输出目录
# -----------------------------
OUT_DIR="$GITHUB_WORKSPACE/NapCat.Shell.Windows.Node"
mkdir -p "$OUT_DIR/NapCat.Shell.Windows.Node"
# -----------------------------
# 4) 解压 NapCat.Shell.zip 到 napcat
# -----------------------------
cp -a "$GITHUB_WORKSPACE/artifacts/NapCat.Shell/." "$OUT_DIR/napcat/"
# -----------------------------
# 5) 拷贝 QQ 文件到 NapCat.Shell.Windows.Node
# -----------------------------
QQ_TARGETS=("avif_convert.dll" "broadcast_ipc.dll" "config.json" "libglib-2.0-0.dll" "libgobject-2.0-0.dll" "libvips-42.dll" "ncnn.dll" "opencv.dll" "package.json" "QBar.dll" "wrapper.node")
for name in "${QQ_TARGETS[@]}"; do
find "$QQ_EXTRACT" -iname "$name" -exec cp -a {} "$OUT_DIR" \; || true
done
# -----------------------------
# 6) 拷贝仓库文件 napcat.bat 和 index.js
# -----------------------------
cp -a "$GITHUB_WORKSPACE/packages/napcat-develop/napcat.bat" "$OUT_DIR/" || true
cp -a "$GITHUB_WORKSPACE/packages/napcat-develop/index.js" "$OUT_DIR/" || true
cp -a "$GITHUB_WORKSPACE/packages/napcat-develop/QQNT.dll" "$OUT_DIR/" || true
# -----------------------------
# 7) 拷贝 Node.exe 到 NapCat.Shell.Windows.Node
# -----------------------------
cp -a "$NODE_EXTRACT/node-v$NODE_VER-win-x64/node.exe" "$OUT_DIR/" || true
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: NapCat.Shell.Windows.Node
path: NapCat.Shell.Windows.Node
release-napcat:
needs: [Build-LiteLoader,Build-Shell]
needs: [Build-Framework, Build-Shell, Download-QNX64]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Clone Main Repository
uses: actions/checkout@v4
with:
repository: 'NapNeko/NapCatQQ'
submodules: true
ref: main
token: ${{ secrets.NAPCAT_BUILD }}
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
path: ./artifacts
- name: Download All Artifact
uses: actions/download-artifact@v4
- name: Compress subdirectories
run: |
cd ./NapCat.Shell/
zip -q -r NapCat.Shell.zip *
cd ..
cd ./NapCat.Framework/
zip -q -r NapCat.Framework.zip *
cd ..
rm ./NapCat.Shell.zip -rf
rm ./NapCat.Framework.zip -rf
mv ./NapCat.Shell/NapCat.Shell.zip ./
mv ./NapCat.Framework/NapCat.Framework.zip ./
- name: Extract version from tag
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
- name: Clone Changes Log
run: curl -o CHANGELOG.md https://fastly.jsdelivr.net/gh/NapNeko/NapCatQQ@main/docs/changelogs/CHANGELOG.v${{ env.VERSION }}.md
- name: Create Release Draft and Upload Artifacts
uses: softprops/action-gh-release@v1
with:
name: NapCat V${{ env.VERSION }}
token: ${{ secrets.GITHUB_TOKEN }}
body_path: CHANGELOG.md
files: |
NapCat.Framework.zip
NapCat.Shell.zip
draft: true
build-docker:
needs: release-napcat
runs-on: ubuntu-latest
steps:
- name: Dispatch Docker Build
- name: Zip Artifacts
run: |
curl -X POST \
-H "Authorization: Bearer ${{ secrets.NAPCAT_BUILD }}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/NapNeko/NapCat-Docker/actions/workflows/docker-publish.yml/dispatches \
-d '{"ref": "main"}'
cd artifacts
[ -d NapCat.Framework ] && (cd NapCat.Framework && zip -qr ../../NapCat.Framework.zip .)
[ -d NapCat.Shell ] && (cd NapCat.Shell && zip -qr ../../NapCat.Shell.zip .)
[ -d NapCat.Shell.Windows.Node ] && (cd NapCat.Shell.Windows.Node && zip -qr ../../NapCat.Shell.Windows.Node.zip .)
cd ..
- name: Generate release note via OpenRouter
env:
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
OPENROUTER_API_URL: ${{ env.OPENROUTER_API_URL }}
OPENROUTER_MODEL: ${{ env.OPENROUTER_MODEL }}
GITHUB_OWNER: "NapNeKo" # 替换成你的 repo owner
GITHUB_REPO: "NapCatQQ" # 替换成你的 repo 名
run: |
set -euo pipefail
# 当前 tag
CURRENT_TAG="${GITHUB_REF#refs/tags/}"
echo "Current tag: $CURRENT_TAG"
# 从 GitHub API 获取 tag 列表
TAGS_JSON=$(curl -s "https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_REPO}/tags?per_page=100")
TAGS=( $(echo "$TAGS_JSON" | jq -r '.[].name' | sort -V) )
# 找到上一个 tag
PREV_TAG=""
for i in "${!TAGS[@]}"; do
if [ "${TAGS[$i]}" = "$CURRENT_TAG" ]; then
if [ $i -gt 0 ]; then
PREV_TAG="${TAGS[$((i-1))]}"
fi
break
fi
done
if [ -z "$PREV_TAG" ]; then
echo "❌ Could not find previous tag for $CURRENT_TAG, aborting."
exit 1
fi
echo "Previous tag: $PREV_TAG"
# 强制拉取上一个 tag 和当前 tag
git fetch origin "refs/tags/$PREV_TAG:refs/tags/$PREV_TAG" --force
git fetch origin "refs/tags/$CURRENT_TAG:refs/tags/$CURRENT_TAG" --force
# 获取 commit title + body + 作者,保留换行
COMMITS=$(git log --pretty=format:'%h %B (%an)' "$PREV_TAG".."$CURRENT_TAG" | sed 's/$/\\n/')
echo "Commit list from $PREV_TAG to $CURRENT_TAG:"
echo -e "$COMMITS"
# 读取 prompt
PROMPT_FILE=".github/prompt/release_note_prompt.txt"
SYSTEM_PROMPT=$(<"$PROMPT_FILE")
# 构建用户内容
USER_CONTENT="当前真正的版本: $CURRENT_TAG\n提交列表:\n$COMMITS"
# 构建请求 JSON
BODY=$(jq -n \
--arg system "$SYSTEM_PROMPT" \
--arg user "$USER_CONTENT" \
'{model: env.OPENROUTER_MODEL, messages:[{role:"system", content:$system},{role:"user", content:$user}], temperature:0.3, max_tokens:800}')
echo "=== OpenRouter request body ==="
echo "$BODY" | jq .
# 调用 OpenRouter
if RESPONSE=$(curl -s -X POST "$OPENROUTER_API_URL" \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d "$BODY"); then
echo "=== raw response ==="
echo "$RESPONSE"
echo "=== OpenRouter raw response ==="
if echo "$RESPONSE" | jq . >/dev/null 2>&1; then
echo "$RESPONSE" | jq .
else
echo "jq failed to parse response"
fi
# 提取生成内容
RELEASE_BODY=$(echo "$RESPONSE" | jq -r '.choices[0].message.content // .choices[0].text // ""' 2>/dev/null || echo "")
if [ -z "$RELEASE_BODY" ]; then
echo "❌ OpenRouter failed to generate release note, using default.md"
cp .github/prompt/default.md CHANGELOG.md
else
echo -e "$RELEASE_BODY" > CHANGELOG.md
fi
else
echo "❌ Curl failed, using default.md"
cp .github/prompt/default.md CHANGELOG.md
fi
echo "=== generated release note ==="
cat CHANGELOG.md
- name: Create Release Draft and Upload Artifacts
uses: softprops/action-gh-release@v1
with:
name: NapCat ${{ github.ref_name }}
token: ${{ secrets.GITHUB_TOKEN }}
body_path: CHANGELOG.md
files: |
NapCat.Shell.Windows.Node.zip
NapCat.Framework.zip
NapCat.Shell.zip
draft: true

2
.gitignore vendored
View File

@@ -16,4 +16,4 @@ checkVersion.sh
bun.lockb
tests/run/
guild1.db-wal
guild1.db-shm
guild1.db-shm

111
.vscode/launch.json vendored
View File

@@ -2,114 +2,11 @@
"version": "0.2.0",
"configurations": [
{
"type": "node",
"type": "node-terminal",
"request": "launch",
"name": "dev:shell",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"dev:shell"
]
},
{
"type": "node",
"request": "launch",
"name": "build:shell",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"build:shell"
]
},
{
"type": "node",
"request": "launch",
"name": "build:universal",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"build:universal"
]
},
{
"type": "node",
"request": "launch",
"name": "build:framework",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"build:framework"
]
},
{
"type": "node",
"request": "launch",
"name": "build:webui",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"build:webui"
]
},
{
"type": "node",
"request": "launch",
"name": "dev:universal",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"dev:universal"
]
},
{
"type": "node",
"request": "launch",
"name": "dev:framework",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"dev:framework"
]
},
{
"type": "node",
"request": "launch",
"name": "dev:webui",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"dev:webui"
]
},
{
"type": "node",
"request": "launch",
"name": "lint",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"lint"
]
},
{
"type": "node",
"request": "launch",
"name": "depend",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"depend"
]
},
{
"type": "node",
"request": "launch",
"name": "dev:depend",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"dev:depend"
]
"name": "调试程序",
"command": "pnpm run dev:shell",
"cwd": "${workspaceFolder}"
}
]
}

70
.vscode/settings.json vendored
View File

@@ -1,37 +1,37 @@
{
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.expand": false,
"explorer.fileNesting.patterns": {
".env.universal": ".env.*",
"vite.config.ts": "vite*.ts",
"README.md": "CODE_OF_CONDUCT.md, RELEASES.md, CONTRIBUTING.md, CHANGELOG.md, SECURITY.md",
"tsconfig.json": "tsconfig.*.json, env.d.ts",
"package.json": "package-lock.json, eslint*, .prettier*, .editorconfig, manifest.json, logo.png, .gitignore, LICENSE"
},
"css.customData": [
".vscode/tailwindcss.json"
],
"editor.detectIndentation": false,
"editor.tabSize": 2,
"editor.formatOnSave": true,
"editor.formatOnType": false,
"editor.formatOnPaste": true,
"editor.formatOnSaveMode": "file",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "always"
},
"files.autoSave": "onFocusChange",
"javascript.preferences.quoteStyle": "single",
"typescript.preferences.quoteStyle": "single",
"javascript.format.semicolons": "insert",
"typescript.format.semicolons": "insert",
"javascript.format.insertSpaceBeforeFunctionParenthesis": true,
"typescript.format.insertSpaceBeforeFunctionParenthesis": true,
"typescript.format.insertSpaceAfterConstructor": true,
"javascript.format.insertSpaceAfterConstructor": true,
"typescript.preferences.importModuleSpecifier": "non-relative",
"typescript.preferences.importModuleSpecifierEnding": "minimal",
"javascript.preferences.importModuleSpecifier": "non-relative",
"javascript.preferences.importModuleSpecifierEnding": "minimal",
"typescript.disableAutomaticTypeAcquisition": true,
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.expand": false,
"explorer.fileNesting.patterns": {
".env.universal": ".env.*",
"vite.config.ts": "vite*.ts",
"README.md": "CODE_OF_CONDUCT.md, RELEASES.md, CONTRIBUTING.md, CHANGELOG.md, SECURITY.md",
"tsconfig.json": "tsconfig.*.json, env.d.ts",
"package.json": "package-lock.json, eslint*, .prettier*, .editorconfig, manifest.json, logo.png, .gitignore, LICENSE"
},
"css.customData": [
".vscode/tailwindcss.json"
],
"editor.detectIndentation": false,
"editor.tabSize": 2,
"editor.formatOnSave": true,
"editor.formatOnType": false,
"editor.formatOnPaste": true,
"editor.formatOnSaveMode": "file",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "always"
},
"files.autoSave": "onFocusChange",
"javascript.preferences.quoteStyle": "single",
"typescript.preferences.quoteStyle": "single",
"javascript.format.semicolons": "insert",
"typescript.format.semicolons": "insert",
"javascript.format.insertSpaceBeforeFunctionParenthesis": true,
"typescript.format.insertSpaceBeforeFunctionParenthesis": true,
"typescript.format.insertSpaceAfterConstructor": true,
"javascript.format.insertSpaceAfterConstructor": true,
"typescript.preferences.importModuleSpecifier": "non-relative",
"typescript.preferences.importModuleSpecifierEnding": "minimal",
"javascript.preferences.importModuleSpecifier": "non-relative",
"javascript.preferences.importModuleSpecifierEnding": "minimal",
"typescript.disableAutomaticTypeAcquisition": true
}

BIN
external/logo.png vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

BIN
logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 684 KiB

After

Width:  |  Height:  |  Size: 250 KiB

View File

@@ -1,2 +0,0 @@
import eslintConfig from '../eslint.config.mjs';
export default eslintConfig;

File diff suppressed because it is too large Load Diff

View File

@@ -1,93 +0,0 @@
import { Button } from '@heroui/button';
import { Image } from '@heroui/image';
import clsx from 'clsx';
import { motion } from 'motion/react';
import React from 'react';
import { IoMdLogOut } from 'react-icons/io';
import { MdDarkMode, MdLightMode } from 'react-icons/md';
import useAuth from '@/hooks/auth';
import useDialog from '@/hooks/use-dialog';
import { useTheme } from '@/hooks/use-theme';
import logo from '@/assets/images/logo.png';
import type { MenuItem } from '@/config/site';
import Menus from './menus';
interface SideBarProps {
open: boolean
items: MenuItem[]
}
const SideBar: React.FC<SideBarProps> = (props) => {
const { open, items } = props;
const { toggleTheme, isDark } = useTheme();
const { revokeAuth } = useAuth();
const dialog = useDialog();
const onRevokeAuth = () => {
dialog.confirm({
title: '退出登录',
content: '确定要退出登录吗?',
onConfirm: revokeAuth,
});
};
return (
<motion.div
className={clsx(
'overflow-hidden fixed top-0 left-0 h-full z-50 bg-background md:bg-transparent md:static shadow-md md:shadow-none rounded-r-md md:rounded-none'
)}
initial={{ width: 0 }}
animate={{ width: open ? '16rem' : 0 }}
transition={{
type: open ? 'spring' : 'tween',
stiffness: 150,
damping: open ? 15 : 10,
}}
style={{ overflow: 'hidden' }}
>
<motion.div className='w-64 flex flex-col items-stretch h-full transition-transform duration-300 ease-in-out z-30 relative float-right'>
<div className='flex justify-center items-center my-2 gap-2'>
<Image radius='none' height={40} src={logo} className='mb-2' />
<div
className={clsx(
'flex items-center font-bold',
'!text-2xl shiny-text'
)}
>
NapCat
</div>
</div>
<div className='overflow-y-auto flex flex-col flex-1 px-4'>
<Menus items={items} />
<div className='mt-auto mb-10 md:mb-0'>
<Button
className='w-full'
color='primary'
radius='full'
variant='light'
onPress={toggleTheme}
startContent={
!isDark ? <MdLightMode size={16} /> : <MdDarkMode size={16} />
}
>
</Button>
<Button
className='w-full mb-2'
color='primary'
radius='full'
variant='light'
onPress={onRevokeAuth}
startContent={<IoMdLogOut size={16} />}
>
退
</Button>
</div>
</div>
</motion.div>
</motion.div>
);
};
export default SideBar;

View File

@@ -1,282 +0,0 @@
import { Button } from '@heroui/button';
import { Card, CardBody, CardHeader } from '@heroui/card';
import { Chip } from '@heroui/chip';
import { Spinner } from '@heroui/spinner';
import { Tooltip } from '@heroui/tooltip';
import { useRequest } from 'ahooks';
import { useEffect } from 'react';
import { BsStars } from 'react-icons/bs';
import { FaCircleInfo, FaInfo, FaQq } from 'react-icons/fa6';
import { IoLogoChrome, IoLogoOctocat } from 'react-icons/io';
import { RiMacFill } from 'react-icons/ri';
import useDialog from '@/hooks/use-dialog';
import { request } from '@/utils/request';
import { compareVersion } from '@/utils/version';
import WebUIManager from '@/controllers/webui_manager';
import { GithubRelease } from '@/types/github';
import TailwindMarkdown from './tailwind_markdown';
export interface SystemInfoItemProps {
title: string
icon?: React.ReactNode
value?: React.ReactNode
endContent?: React.ReactNode
}
const SystemInfoItem: React.FC<SystemInfoItemProps> = ({
title,
value = '--',
icon,
endContent,
}) => {
return (
<div className='flex text-sm gap-1 p-2 items-center shadow-sm shadow-primary-100 dark:shadow-primary-100 rounded text-primary-400'>
{icon}
<div className='w-24'>{title}</div>
<div className='text-primary-200'>{value}</div>
<div className='ml-auto'>{endContent}</div>
</div>
);
};
export interface NewVersionTipProps {
currentVersion?: string
}
const NewVersionTip = (props: NewVersionTipProps) => {
const { currentVersion } = props;
const dialog = useDialog();
const { data: releaseData, error } = useRequest(() =>
request.get<GithubRelease[]>(
'https://api.github.com/repos/NapNeko/NapCatQQ/releases'
)
);
if (error) {
return (
<Tooltip content='检查新版本失败'>
<Button
isIconOnly
radius='full'
color='primary'
variant='shadow'
className='!w-5 !h-5 !min-w-0 text-small shadow-md'
onPress={() => {
dialog.alert({
title: '检查新版本失败',
content: error.message,
});
}}
>
<FaInfo />
</Button>
</Tooltip>
);
}
const latestVersion = releaseData?.data?.[0]?.tag_name;
if (!latestVersion || !currentVersion) {
return null;
}
if (compareVersion(latestVersion, currentVersion) <= 0) {
return null;
}
const middleVersions: GithubRelease[] = [];
for (let i = 0; i < releaseData.data.length; i++) {
const versionInfo = releaseData.data[i];
if (compareVersion(versionInfo.tag_name, currentVersion) > 0) {
middleVersions.push(versionInfo);
} else {
break;
}
}
const AISummaryComponent = () => {
const {
data: aiSummaryData,
loading: aiSummaryLoading,
error: aiSummaryError,
run: runAiSummary,
} = useRequest(
(version) =>
request.get<ServerResponse<string | null>>(
`https://release.nc.152710.xyz/?version=${version}`,
{
timeout: 30000,
}
),
{
manual: true,
}
);
useEffect(() => {
runAiSummary(currentVersion);
}, [currentVersion, runAiSummary]);
if (aiSummaryLoading) {
return (
<div className='flex justify-center py-1'>
<Spinner size='sm' />
</div>
);
}
if (aiSummaryError) {
return <div className='text-center text-primary-500'>AI </div>;
}
return <span className='text-default-700'>{aiSummaryData?.data.data}</span>;
};
return (
<Tooltip content='有新版本可用'>
<Button
isIconOnly
radius='full'
color='primary'
variant='shadow'
className='!w-5 !h-5 !min-w-0 text-small shadow-md'
onPress={() => {
dialog.confirm({
title: '有新版本可用',
content: (
<div className='space-y-2'>
<div className='text-sm space-x-2'>
<span></span>
<Chip color='primary' variant='flat'>
v{currentVersion}
</Chip>
</div>
<div className='text-sm space-x-2'>
<span></span>
<Chip color='primary'>{latestVersion}</Chip>
</div>
<div className='p-2 rounded-md bg-content2 text-sm'>
<div className='text-primary-400 font-bold flex items-center gap-1 mb-1'>
<BsStars />
<span>AI总结</span>
</div>
<AISummaryComponent />
</div>
<div className='text-sm space-y-2 !mt-4'>
{middleVersions.map((versionInfo) => (
<div
key={versionInfo.tag_name}
className='p-4 bg-content1 rounded-md shadow-small'
>
<TailwindMarkdown content={versionInfo.body} />
</div>
))}
</div>
</div>
),
scrollBehavior: 'inside',
size: '3xl',
confirmText: '前往下载',
onConfirm () {
window.open(
'https://github.com/NapNeko/NapCatQQ/releases',
'_blank',
'noopener'
);
},
});
}}
>
<FaInfo />
</Button>
</Tooltip>
);
};
const NapCatVersion = () => {
const {
data: packageData,
loading: packageLoading,
error: packageError,
} = useRequest(WebUIManager.getPackageInfo);
const currentVersion = packageData?.version;
return (
<SystemInfoItem
title='NapCat 版本'
icon={<IoLogoOctocat className='text-xl' />}
value={
packageError
? (
`错误:${packageError.message}`
)
: packageLoading
? (
<Spinner size='sm' />
)
: (
currentVersion
)
}
endContent={<NewVersionTip currentVersion={currentVersion} />}
/>
);
};
export interface SystemInfoProps {
archInfo?: string
}
const SystemInfo: React.FC<SystemInfoProps> = (props) => {
const { archInfo } = props;
const {
data: qqVersionData,
loading: qqVersionLoading,
error: qqVersionError,
} = useRequest(WebUIManager.getQQVersion);
return (
<Card className='bg-opacity-60 shadow-sm shadow-primary-100 dark:shadow-primary-100 overflow-visible flex-1'>
<CardHeader className='pb-0 items-center gap-1 text-primary-500 font-extrabold'>
<FaCircleInfo className='text-lg' />
<span></span>
</CardHeader>
<CardBody className='flex-1'>
<div className='flex flex-col justify-between h-full'>
<NapCatVersion />
<SystemInfoItem
title='QQ 版本'
icon={<FaQq className='text-lg' />}
value={
qqVersionError
? (
`错误:${qqVersionError.message}`
)
: qqVersionLoading
? (
<Spinner size='sm' />
)
: (
qqVersionData
)
}
/>
<SystemInfoItem
title='WebUI 版本'
icon={<IoLogoChrome className='text-xl' />}
value='Next'
/>
<SystemInfoItem
title='系统版本'
icon={<RiMacFill className='text-xl' />}
value={archInfo}
/>
</div>
</CardBody>
</Card>
);
};
export default SystemInfo;

View File

@@ -1,137 +0,0 @@
import { Input } from '@heroui/input';
import { useLocalStorage } from '@uidotdev/usehooks';
import { useEffect } from 'react';
import { Controller, useForm } from 'react-hook-form';
import toast from 'react-hot-toast';
import key from '@/const/key';
import SaveButtons from '@/components/button/save_buttons';
import FileInput from '@/components/input/file_input';
import ImageInput from '@/components/input/image_input';
import useMusic from '@/hooks/use-music';
import { siteConfig } from '@/config/site';
import FileManager from '@/controllers/file_manager';
const WebUIConfigCard = () => {
const {
control,
handleSubmit: handleWebuiSubmit,
formState: { isSubmitting },
setValue: setWebuiValue,
} = useForm<IConfig['webui']>({
defaultValues: {
background: '',
musicListID: '',
customIcons: {},
},
});
const [b64img, setB64img] = useLocalStorage(key.backgroundImage, '');
const [customIcons, setCustomIcons] = useLocalStorage<Record<string, string>>(
key.customIcons,
{}
);
const { setListId, listId } = useMusic();
const reset = () => {
setWebuiValue('musicListID', listId);
setWebuiValue('customIcons', customIcons);
setWebuiValue('background', b64img);
};
const onSubmit = handleWebuiSubmit((data) => {
try {
setListId(data.musicListID);
setCustomIcons(data.customIcons);
setB64img(data.background);
toast.success('保存成功');
} catch (error) {
const msg = (error as Error).message;
toast.error(`保存失败: ${msg}`);
}
});
useEffect(() => {
reset();
}, [listId, customIcons, b64img]);
return (
<>
<title>WebUI配置 - NapCat WebUI</title>
<div className='flex flex-col gap-2'>
<div className='flex-shrink-0 w-full'>WebUI字体</div>
<div className='text-sm text-default-400'>
<FileInput
label='中文字体'
onChange={async (file) => {
try {
await FileManager.uploadWebUIFont(file);
toast.success('上传成功');
setTimeout(() => {
window.location.reload();
}, 1000);
} catch (error) {
toast.error('上传失败: ' + (error as Error).message);
}
}}
onDelete={async () => {
try {
await FileManager.deleteWebUIFont();
toast.success('删除成功');
setTimeout(() => {
window.location.reload();
}, 1000);
} catch (error) {
toast.error('删除失败: ' + (error as Error).message);
}
}}
/>
</div>
</div>
<div className='flex flex-col gap-2'>
<div className='flex-shrink-0 w-full'>WebUI音乐播放器</div>
<Controller
control={control}
name='musicListID'
render={({ field }) => (
<Input
{...field}
label='网易云音乐歌单ID网页内音乐播放器'
placeholder='请输入歌单ID'
/>
)}
/>
</div>
<div className='flex flex-col gap-2'>
<div className='flex-shrink-0 w-full'></div>
<Controller
control={control}
name='background'
render={({ field }) => <ImageInput {...field} />}
/>
</div>
<div className='flex flex-col gap-2'>
<div></div>
{siteConfig.navItems.map((item) => (
<Controller
key={item.label}
control={control}
name={`customIcons.${item.label}`}
render={({ field }) => <ImageInput {...field} label={item.label} />}
/>
))}
</div>
<SaveButtons
onSubmit={onSubmit}
reset={reset}
isSubmitting={isSubmitting}
/>
</>
);
};
export default WebUIConfigCard;

9104
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,73 +2,29 @@
"name": "napcat",
"private": true,
"type": "module",
"version": "4.9.42",
"version": "0.0.1",
"scripts": {
"build:universal": "npm run build:webui && npm run dev:universal || exit 1",
"build:framework": "npm run build:webui && npm run dev:framework || exit 1",
"build:shell": "npm run build:webui && npm run dev:shell || exit 1",
"build:webui": "cd napcat.webui && npm run build",
"dev:universal": "vite build --mode universal",
"dev:framework": "vite build --mode framework",
"dev:shell": "vite build --mode shell",
"dev:shell-analysis": "vite build --mode shell-analysis",
"dev:webui": "cd napcat.webui && npm run dev",
"tsc": "npm run tsc:webui && npm run tsc:core",
"tsc:core": "tsc --noEmit",
"tsc:webui": "cd napcat.webui && tsc --noEmit",
"lint": "npm run lint:core && npm run lint:webui",
"lint:fix": "npm run lint:fix:core && npm run lint:fix:webui",
"lint:core": "eslint src/**/*",
"lint:fix:core": "eslint --fix src/**/*",
"lint:webui": "cd napcat.webui && eslint src/**/*",
"lint:fix:webui": "cd napcat.webui && eslint --fix src/**/*",
"depend": "cd dist && npm install --omit=dev",
"dev:depend": "npm i && cd napcat.webui && npm i",
"test:winshell": "pwsh ./tests/nodeTest.ps1"
"build:shell": "pnpm --filter napcat-shell run build || exit 1",
"build:shell:dev": "pnpm --filter napcat-shell run build:dev || exit 1",
"build:framework": "pnpm --filter napcat-framework run build || exit 1",
"build:webui": "pnpm --filter napcat-webui-frontend run build || exit 1",
"dev:shell": "pnpm --filter napcat-develop run dev || exit 1",
"typecheck": "pnpm -r --if-present run typecheck",
"test": "pnpm --filter napcat-test run test",
"test:ui": "pnpm --filter napcat-test run test:ui",
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},
"devDependencies": {
"@babel/core": "^7.28.0",
"@babel/generator": "^7.28.0",
"@babel/parser": "^7.28.0",
"@babel/preset-typescript": "^7.24.7",
"@babel/traverse": "^7.28.0",
"@babel/types": "^7.28.2",
"@homebridge/node-pty-prebuilt-multiarch": "^0.12.0-beta.5",
"@log4js-node/log4js-api": "^1.0.2",
"@napneko/nap-proto-core": "^0.0.4",
"@rollup/plugin-node-resolve": "^16.0.0",
"@rollup/plugin-typescript": "^12.1.4",
"@sinclair/typebox": "^0.34.38",
"@types/cors": "^2.8.17",
"@types/express": "^5.0.0",
"@types/multer": "^1.4.12",
"@types/node": "^22.0.1",
"@types/on-finished": "^2.3.4",
"@types/qrcode-terminal": "^0.12.2",
"@types/react-color": "^3.0.13",
"@types/type-is": "^1.6.7",
"@types/ws": "^8.5.12",
"ajv": "^8.13.0",
"async-mutex": "^0.5.0",
"commander": "^13.0.0",
"compressing": "^1.10.1",
"cors": "^2.8.5",
"esbuild": "0.25.8",
"eslint": "^9.14.0",
"express-rate-limit": "^7.5.0",
"fast-xml-parser": "^4.3.6",
"file-type": "^21.0.0",
"fs-extra": "^11.3.2",
"json5": "^2.2.3",
"multer": "^2.0.1",
"napcat.protobuf": "^1.1.4",
"@rollup/plugin-node-resolve": "^16.0.3",
"@vitejs/plugin-react-swc": "^4.2.2",
"@vitest/ui": "^4.0.9",
"eslint": "^9.39.1",
"neostandard": "^0.12.2",
"typescript": "^5.3.3",
"typescript-eslint": "^8.35.1",
"vite": "^7.1.1",
"vite-plugin-cp": "^6.0.0",
"vite-tsconfig-paths": "^5.1.0",
"winston": "^3.17.0"
"typescript": "^5.3.0",
"vite": "^6.4.1",
"vite-plugin-cp": "^6.0.3",
"vitest": "^4.0.9"
},
"dependencies": {
"express": "^5.0.0",

View File

@@ -0,0 +1,29 @@
{
"name": "napcat-common",
"version": "0.0.1",
"private": true,
"type": "module",
"main": "src/index.ts",
"scripts": {
"typecheck": "tsc --noEmit --skipLibCheck -p tsconfig.json"
},
"exports": {
".": {
"import": "./src/index.ts"
},
"./src/*": {
"import": "./src/*"
}
},
"dependencies": {
"ajv": "^8.13.0",
"file-type": "^21.0.0",
"silk-wasm": "^3.6.1"
},
"devDependencies": {
"@types/node": "^22.0.1"
},
"engines": {
"node": ">=18.0.0"
}
}

9
packages/napcat-common/src/env.d.ts vendored Normal file
View File

@@ -0,0 +1,9 @@
/// <reference types="vite/client" />
declare global {
interface ImportMetaEnv {
readonly VITE_NAPCAT_VERSION: string;
}
}
export {};

View File

@@ -1,4 +1,4 @@
import { Peer } from '@/core';
import { Peer } from './types';
import { randomUUID } from 'crypto';
class TimeBasedCache<K, V> {

View File

@@ -2,7 +2,7 @@ import fs from 'fs';
import { stat } from 'fs/promises';
import crypto, { randomUUID } from 'crypto';
import path from 'node:path';
import { solveProblem } from '@/common/helper';
import { solveProblem } from '@/napcat-common/src/helper';
export interface HttpDownloadOptions {
url: string;

View File

@@ -1,8 +1,8 @@
import path from 'node:path';
import fs from 'fs';
import os from 'node:os';
import { QQLevel } from '@/core';
import { QQVersionConfigType } from './types';
import { QQVersionConfigType, QQLevel } from './types';
import { RequestUtil } from './request';
export async function solveProblem<T extends (...arg: any[]) => any> (func: T, ...args: Parameters<T>): Promise<ReturnType<T> | undefined> {
return new Promise<ReturnType<T> | undefined>((resolve) => {
@@ -212,3 +212,81 @@ export function parseAppidFromMajor (nodeMajor: string): string | undefined {
return undefined;
}
const baseUrl = 'https://github.com/NapNeko/NapCatQQ.git/info/refs?service=git-upload-pack';
const urls = [
'https://j.1win.ggff.net/' + baseUrl,
'https://git.yylx.win/' + baseUrl,
'https://ghfile.geekertao.top/' + baseUrl,
'https://gh-proxy.net/' + baseUrl,
'https://ghm.078465.xyz/' + baseUrl,
'https://gitproxy.127731.xyz/' + baseUrl,
'https://jiashu.1win.eu.org/' + baseUrl,
baseUrl,
];
async function testUrl (url: string): Promise<boolean> {
try {
await PromiseTimer(RequestUtil.HttpGetText(url), 5000);
return true;
} catch {
return false;
}
}
async function findAvailableUrl (): Promise<string | null> {
for (const url of urls) {
if (await testUrl(url)) {
return url;
}
}
return null;
}
export async function getAllTags (): Promise<string[]> {
const availableUrl = await findAvailableUrl();
if (!availableUrl) {
throw new Error('No available URL for fetching tags');
}
const raw = await RequestUtil.HttpGetText(availableUrl);
return raw
.split('\n')
.map(line => {
const match = line.match(/refs\/tags\/(.+)$/);
return match ? match[1] : null;
})
.filter(tag => tag !== null && !tag!.endsWith('^{}')) as string[];
}
export async function getLatestTag (): Promise<string> {
const tags = await getAllTags();
tags.sort((a, b) => compareVersion(a, b));
const latest = tags.at(-1);
if (!latest) {
throw new Error('No tags found');
}
// 去掉开头的 v
return latest.replace(/^v/, '');
}
function compareVersion (a: string, b: string): number {
const normalize = (v: string) =>
v.replace(/^v/, '') // 去掉开头的 v
.split('.')
.map(n => parseInt(n) || 0);
const pa = normalize(a);
const pb = normalize(b);
const len = Math.max(pa.length, pb.length);
for (let i = 0; i < len; i++) {
const na = pa[i] || 0;
const nb = pb[i] || 0;
if (na !== nb) return na - nb;
}
return 0;
}

View File

@@ -0,0 +1,24 @@
export enum LogLevel {
DEBUG = 'debug',
INFO = 'info',
WARN = 'warn',
ERROR = 'error',
FATAL = 'fatal',
}
export interface ILogWrapper {
fileLogEnabled: boolean;
consoleLogEnabled: boolean;
cleanOldLogs (logDir: string): void;
setFileAndConsoleLogLevel (fileLogLevel: LogLevel, consoleLogLevel: LogLevel): void;
setLogSelfInfo (selfInfo: { nick: string; uid: string; }): void;
setFileLogEnabled (isEnabled: boolean): void;
setConsoleLogEnabled (isEnabled: boolean): void;
formatMsg (msg: any[]): string;
_log (level: LogLevel, ...args: any[]): void;
log (...args: any[]): void;
logDebug (...args: any[]): void;
logError (...args: any[]): void;
logWarn (...args: any[]): void;
logFatal (...args: any[]): void;
logMessage (msg: unknown, selfInfo: unknown): void;
}

View File

@@ -1,6 +1,5 @@
import { Peer } from '@/core';
import crypto from 'crypto';
import { Peer } from './types';
export class LimitedHashTable<K, V> {
private readonly keyToValue: Map<K, V> = new Map();
private readonly valueToKey: Map<V, K> = new Map();

View File

@@ -0,0 +1,24 @@
export interface SystemStatus {
cpu: {
model: string,
speed: string;
usage: {
system: string;
qq: string;
},
core: number;
},
memory: {
total: string;
usage: {
system: string;
qq: string;
};
},
arch: string;
}
export interface IStatusHelperSubscription {
on (event: 'statusUpdate', listener: (status: SystemStatus) => void): this;
off (event: 'statusUpdate', listener: (status: SystemStatus) => void): this;
emit (event: 'statusUpdate', status: SystemStatus): boolean;
}

View File

@@ -19,4 +19,4 @@ class Store {
const store = new Store();
export default store;
export default store;

View File

@@ -0,0 +1,6 @@
export type LogListener = (msg: string) => void;
export interface ISubscription {
subscribe (listener: LogListener): void;
unsubscribe (listener: LogListener): void;
notify (msg: string): void;
}

View File

@@ -15,3 +15,14 @@ export type QQVersionConfigType = {
export type QQAppidTableType = {
[key: string]: { appid: string, qua: string };
};
export interface Peer {
chatType: number; // 聊天类型
peerUid: string; // 对等方的唯一标识符
guildId?: string; // 可选的频道ID
}
export interface QQLevel {
crownNum: number;
sunNum: number;
moonNum: number;
starNum: number;
}

View File

@@ -0,0 +1,2 @@
// @ts-ignore
export const napCatVersion = (typeof import.meta?.env !== 'undefined' && import.meta.env.VITE_NAPCAT_VERSION) || 'alpha';

View File

@@ -1,36 +1,21 @@
{
"compilerOptions": {
"target": "ES2021",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": [
"ES2021",
"DOM",
"DOM.Iterable"
],
"skipLibCheck": true,
"moduleResolution": "Node",
"experimentalDecorators": true,
"allowImportingTsExtensions": false,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"lib": [
"ES2021"
],
"typeRoots": [
"./node_modules/@types"
],
"esModuleInterop": true,
"outDir": "dist",
"rootDir": ".",
"noEmit": false,
"sourceMap": true,
"paths": {
"@/*": [
"./src/*"
],
"@webapi/*": [
"./src/webui/src/*"
]
},
"noImplicitAny": true,
"strict": true,
"noImplicitAny": false,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"alwaysStrict": true,
@@ -38,23 +23,31 @@
"noImplicitReturns": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": false, //
"exactOptionalPropertyTypes": false,
"forceConsistentCasingInFileNames": true,
"useUnknownInCatchVariables": true,
"noImplicitOverride": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"useDefineForClassFields": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"baseUrl": ".",
"paths": {
"@/*": [
"../*"
]
},
"skipLibCheck": true,
"skipDefaultLibCheck": true
},
"include": [
"!@homebridge/node-pty-prebuilt-multiarch/src/eventEmitter2.ts",
"!@homebridge/node-pty-prebuilt-multiarch/src/terminal.ts",
"!@napneko/nap-proto-core/NapProto.ts",
"src/**/*.ts",
"src/**/*.ts"
],
"exclude": [
"node_modules",
"node_modules/**/*",
"node_modules/@homebridge/node-pty-prebuilt-multiarch/src/eventEmitter2.ts",
"node_modules/@homebridge/node-pty-prebuilt-multiarch/src/terminal.ts",
"node_modules/@napneko/nap-proto-core/NapProto.ts"
"dist"
]
}

View File

@@ -1,11 +1,11 @@
import { MsfChangeReasonType, MsfStatusType } from '@/core/types/adapter';
import { MsfChangeReasonType, MsfStatusType } from '@/napcat-core/types/adapter';
export class NodeIDependsAdapter {
onMSFStatusChange (_statusType: MsfStatusType, _changeReasonType: MsfChangeReasonType) {
}
onMSFSsoError (_args: unknown) {
onMSFSsoError (_code: number, _desc: string) {
}
@@ -24,4 +24,4 @@ export class NodeIDependsAdapter {
// console.log('[NodeIDependsAdapter] onSendMsfReply', _seq, _cmd, _uk1, _uk2, Buffer.from(_rsp.pbBuffer).toString('hex'));
// }
}
}

View File

@@ -1,4 +1,4 @@
import { InstanceContext, NapCatCore } from '@/core';
import { InstanceContext, NapCatCore } from '@/napcat-core/index';
export class NTQQCollectionApi {
context: InstanceContext;

View File

@@ -5,30 +5,18 @@ import {
IMAGE_HTTP_HOST_NT,
Peer,
PicElement,
PicSubType,
RawMessage,
SendFileElement,
SendPicElement,
SendPttElement,
SendVideoElement,
} from '@/core/types';
} from '@/napcat-core/types';
import path from 'path';
import fs from 'fs';
import fsPromises from 'fs/promises';
import { InstanceContext, NapCatCore, SearchResultItem } from '@/core';
import { InstanceContext, NapCatCore, SearchResultItem } from '@/napcat-core/index';
import { fileTypeFromFile } from 'file-type';
import { RkeyManager } from '@/core/helper/rkey';
import { calculateFileMD5 } from '@/common/file';
import pathLib from 'node:path';
import { defaultVideoThumbB64 } from '@/common/video';
import { encodeSilk } from '@/common/audio';
import { SendMessageContext } from '@/onebot/api';
import { getFileTypeForSendType } from '../helper/msg';
import { FFmpegService } from '@/common/ffmpeg';
import { RkeyManager } from '@/napcat-core/helper/rkey';
import { calculateFileMD5 } from 'napcat-common/src/file';
import { rkeyDataType } from '../types/file';
import { NapProtoMsg } from '@napneko/nap-proto-core';
import { NapProtoMsg } from 'napcat-protobuf';
import { FileId } from '../packet/transformer/proto/misc/fileid';
import { imageSizeFallBack } from '@/image-size';
export class NTQQFileApi {
context: InstanceContext;
@@ -45,7 +33,7 @@ export class NTQQFileApi {
'http://ss.xingzhige.com/music_card/rkey',
'https://secret-service.bietiaop.com/rkeys',
],
this.context.logger
this.context.logger
);
}
@@ -181,165 +169,6 @@ export class NTQQFileApi {
};
}
async createValidSendFileElement (context: SendMessageContext, filePath: string, fileName: string = '', folderId: string = ''): Promise<SendFileElement> {
const {
fileName: _fileName,
path,
fileSize,
} = await this.core.apis.FileApi.uploadFile(filePath, ElementType.FILE);
if (fileSize === 0) {
throw new Error('文件异常大小为0');
}
context.deleteAfterSentFiles.push(path);
return {
elementType: ElementType.FILE,
elementId: '',
fileElement: {
fileName: fileName || _fileName,
folderId,
filePath: path,
fileSize: fileSize.toString(),
},
};
}
async createValidSendPicElement (context: SendMessageContext, picPath: string, summary: string = '', subType: PicSubType = 0): Promise<SendPicElement> {
const { md5, fileName, path, fileSize } = await this.core.apis.FileApi.uploadFile(picPath, ElementType.PIC, subType);
if (fileSize === 0) {
throw new Error('文件异常大小为0');
}
const imageSize = await imageSizeFallBack(picPath);
context.deleteAfterSentFiles.push(path);
return {
elementType: ElementType.PIC,
elementId: '',
picElement: {
md5HexStr: md5,
fileSize: fileSize.toString(),
picWidth: imageSize.width,
picHeight: imageSize.height,
fileName,
sourcePath: path,
original: true,
picType: await getFileTypeForSendType(picPath),
picSubType: subType,
fileUuid: '',
fileSubId: '',
thumbFileSize: 0,
summary,
} as PicElement,
};
}
async createValidSendVideoElement (context: SendMessageContext, filePath: string, fileName: string = '', _diyThumbPath: string = ''): Promise<SendVideoElement> {
let videoInfo = {
width: 1920,
height: 1080,
time: 15,
format: 'mp4',
size: 0,
filePath,
};
let fileExt = 'mp4';
try {
const tempExt = (await fileTypeFromFile(filePath))?.ext;
if (tempExt) fileExt = tempExt;
} catch (e) {
this.context.logger.logError('获取文件类型失败', e);
}
const newFilePath = `${filePath}.${fileExt}`;
fs.copyFileSync(filePath, newFilePath);
context.deleteAfterSentFiles.push(newFilePath);
filePath = newFilePath;
const { fileName: _fileName, path, fileSize, md5 } = await this.core.apis.FileApi.uploadFile(filePath, ElementType.VIDEO);
context.deleteAfterSentFiles.push(path);
if (fileSize === 0) {
throw new Error('文件异常大小为0');
}
const thumbDir = path.replace(`${pathLib.sep}Ori${pathLib.sep}`, `${pathLib.sep}Thumb${pathLib.sep}`);
fs.mkdirSync(pathLib.dirname(thumbDir), { recursive: true });
const thumbPath = pathLib.join(pathLib.dirname(thumbDir), `${md5}_0.png`);
try {
videoInfo = await FFmpegService.getVideoInfo(filePath, thumbPath);
if (!fs.existsSync(thumbPath)) {
this.context.logger.logError('获取视频缩略图失败', new Error('缩略图不存在'));
throw new Error('获取视频缩略图失败');
}
} catch (e) {
this.context.logger.logError('获取视频信息失败', e);
fs.writeFileSync(thumbPath, Buffer.from(defaultVideoThumbB64, 'base64'));
}
if (_diyThumbPath) {
try {
await this.copyFile(_diyThumbPath, thumbPath);
} catch (e) {
this.context.logger.logError('复制自定义缩略图失败', e);
}
}
context.deleteAfterSentFiles.push(thumbPath);
const thumbSize = (await fsPromises.stat(thumbPath)).size;
const thumbMd5 = await calculateFileMD5(thumbPath);
context.deleteAfterSentFiles.push(thumbPath);
const uploadName = (fileName || _fileName).toLocaleLowerCase().endsWith(`.${fileExt.toLocaleLowerCase()}`) ? (fileName || _fileName) : `${fileName || _fileName}.${fileExt}`;
return {
elementType: ElementType.VIDEO,
elementId: '',
videoElement: {
fileName: uploadName,
filePath: path,
videoMd5: md5,
thumbMd5,
fileTime: videoInfo.time,
thumbPath: new Map([[0, thumbPath]]),
thumbSize,
thumbWidth: videoInfo.width,
thumbHeight: videoInfo.height,
fileSize: fileSize.toString(),
},
};
}
async createValidSendPttElement (_context: SendMessageContext, pttPath: string): Promise<SendPttElement> {
const { converted, path: silkPath, duration } = await encodeSilk(pttPath, this.core.NapCatTempPath, this.core.context.logger);
if (!silkPath) {
throw new Error('语音转换失败, 请检查语音文件是否正常');
}
const { md5, fileName, path, fileSize } = await this.core.apis.FileApi.uploadFile(silkPath, ElementType.PTT);
if (fileSize === 0) {
throw new Error('文件异常大小为0');
}
if (converted) {
fsPromises.unlink(silkPath).then().catch((e) => this.context.logger.logError('删除临时文件失败', e));
}
return {
elementType: ElementType.PTT,
elementId: '',
pttElement: {
fileName,
filePath: path,
md5HexStr: md5,
fileSize: fileSize.toString(),
duration: duration ?? 1,
formatType: 1,
voiceType: 1,
voiceChangeType: 0,
canConvert2Text: true,
waveAmplitudes: [
0, 18, 9, 23, 16, 17, 16, 15, 44, 17, 24, 20, 14, 15, 17,
],
fileSubId: '',
playState: 1,
autoConvertText: 0,
storeID: 0,
otherBusinessInfo: {
aiVoiceType: 0,
},
},
};
}
async downloadFileForModelId (peer: Peer, modelId: string, unknown: string, timeout = 1000 * 60 * 2) {
const [, fileTransNotifyInfo] = await this.core.eventWrapper.callNormalEventV2(
'NodeIKernelRichMediaService/downloadFileForModelId',

View File

@@ -1,6 +1,6 @@
import { FriendRequest, FriendV2 } from '@/core/types';
import { BuddyListReqType, InstanceContext, NapCatCore } from '@/core';
import { LimitedHashTable } from '@/common/message-unique';
import { FriendRequest, FriendV2 } from '@/napcat-core/types';
import { BuddyListReqType, InstanceContext, NapCatCore } from '@/napcat-core/index';
import { LimitedHashTable } from 'napcat-common/src/message-unique';
export class NTQQFriendApi {
context: InstanceContext;

View File

@@ -12,12 +12,12 @@ import {
ShutUpGroupMember,
Peer,
ChatType,
} from '@/core';
import { isNumeric, solveAsyncProblem } from '@/common/helper';
import { LimitedHashTable } from '@/common/message-unique';
import { NTEventWrapper } from '@/common/event';
import { CancelableTask, TaskExecutor } from '@/common/cancel-task';
} from '@/napcat-core/index';
import { isNumeric, solveAsyncProblem } from 'napcat-common/src/helper';
import { LimitedHashTable } from 'napcat-common/src/message-unique';
import { CancelableTask, TaskExecutor } from 'napcat-common/src/cancel-task';
import { createGroupDetailInfoV2Param, createGroupExtFilter, createGroupExtInfo } from '../data';
import { NTEventWrapper } from '../helper/event';
export class NTQQGroupApi {
context: InstanceContext;
@@ -395,7 +395,7 @@ export class NTQQGroupApi {
'NodeIKernelGroupListener/onMemberInfoChange',
[groupCode, [uid], forced],
(ret) => ret.result === 0,
(params, _, members) => params === GroupCode && members.size > 0 && members.has(uid),
(params: string, _: any, members: Map<string, GroupMember>) => params === GroupCode && members.size > 0 && members.has(uid),
1,
forced ? 2500 : 250
);

View File

@@ -1,6 +1,6 @@
import { ChatType, GetFileListParam, Peer, RawMessage, SendMessageElement, SendStatusType } from '@/core/types';
import { GroupFileInfoUpdateItem, InstanceContext, NapCatCore, NodeIKernelMsgService } from '@/core';
import { GeneralCallResult } from '@/core/services/common';
import { ChatType, GetFileListParam, Peer, RawMessage, SendMessageElement, SendStatusType } from '@/napcat-core/types';
import { GroupFileInfoUpdateItem, InstanceContext, NapCatCore, NodeIKernelMsgService } from '@/napcat-core/index';
import { GeneralCallResult } from '@/napcat-core/services/common';
export class NTQQMsgApi {
context: InstanceContext;

View File

@@ -1,9 +1,9 @@
import * as os from 'os';
import offset from '@/core/external/napi2native.json';
import { InstanceContext, NapCatCore } from '@/core';
import { LogWrapper } from '@/common/log';
import { PacketClientSession } from '@/core/packet/clientSession';
import { napCatVersion } from '@/common/version';
import offset from '@/napcat-core/external/napi2native.json';
import { InstanceContext, NapCatCore } from '@/napcat-core/index';
import { PacketClientSession } from '@/napcat-core/packet/clientSession';
import { napCatVersion } from 'napcat-common/src/version';
import { LogWrapper } from '../helper/log';
interface OffsetType {
[key: string]: {

View File

@@ -1,4 +1,4 @@
import { InstanceContext, NapCatCore } from '@/core';
import { InstanceContext, NapCatCore } from '@/napcat-core/index';
export class NTQQSystemApi {
context: InstanceContext;

View File

@@ -1,8 +1,8 @@
import { ModifyProfileParams, User, UserDetailSource } from '@/core/types';
import { RequestUtil } from '@/common/request';
import { ModifyProfileParams, User, UserDetailSource } from '@/napcat-core/types';
import { RequestUtil } from 'napcat-common/src/request';
import { InstanceContext, NapCatCore, ProfileBizType } from '..';
import { solveAsyncProblem } from '@/common/helper';
import { Fallback, FallbackUtil } from '@/common/fall-back';
import { solveAsyncProblem } from 'napcat-common/src/helper';
import { Fallback, FallbackUtil } from 'napcat-common/src/fall-back';
export class NTQQUserApi {
context: InstanceContext;

View File

@@ -1,4 +1,4 @@
import { RequestUtil } from '@/common/request';
import { RequestUtil } from 'napcat-common/src/request';
import {
GroupEssenceMsgRet,
InstanceContext,
@@ -6,7 +6,7 @@ import {
WebApiGroupMemberRet,
WebApiGroupNoticeRet,
WebHonorType, NapCatCore,
} from '@/core';
} from '@/napcat-core/index';
import { createReadStream, readFileSync, statSync } from 'node:fs';
import { createHash } from 'node:crypto';

View File

@@ -466,5 +466,17 @@
"6.9.85-42086": {
"appid": 537320237,
"qua": "V1_MAC_NQ_6.9.85_42086_GW_B"
},
"9.9.23-42430": {
"appid": 537320212,
"qua": "V1_WIN_NQ_9.9.23_42430_GW_B"
},
"9.9.25-42744": {
"appid": 537328470,
"qua": "V1_WIN_NQ_9.9.23_42744_GW_B"
},
"6.9.86-42744": {
"appid": 537328495,
"qua": "V1_MAC_NQ_6.9.85_42744_GW_B"
}
}

View File

@@ -90,5 +90,17 @@
"3.2.21-42086-x64": {
"send": "5B42CF0",
"recv": "2FDA6F0"
},
"9.9.23-42430-x64": {
"send": "0A01A34",
"recv": "1D1CFF9"
},
"9.9.25-42744-x64": {
"send": "0A0D104",
"recv": "1D3E7F9"
},
"6.9.85-42744-arm64": {
"send": "23DFEF0",
"recv": "095FD80"
}
}

View File

@@ -602,5 +602,17 @@
"3.2.21-42086-arm64": {
"send": "6B13038",
"recv": "6B169C8"
},
"9.9.23-42430-x64": {
"send": "2C9A4A0",
"recv": "2C9DA20"
},
"9.9.25-42744-x64": {
"send": "2CD8E40",
"recv": "2CDC3C0"
},
"6.9.86-42744-arm64": {
"send": "3DCC840",
"recv": "3DCF150"
}
}

View File

@@ -1,5 +1,5 @@
// TODO: further refactor in NapCat.Packet v2
import { NapProtoMsg, ProtoField, ScalarType } from '@napneko/nap-proto-core';
import { NapProtoMsg, ProtoField, ScalarType } from 'napcat-protobuf';
const LikeDetail = {
txt: ProtoField(1, ScalarType.STRING),

View File

@@ -2,10 +2,10 @@ import fsPromise from 'fs/promises';
import path from 'node:path';
import { randomUUID } from 'crypto';
import { EncodeResult, getDuration, getWavFileInfo, isSilk, isWav } from 'silk-wasm';
import { LogWrapper } from '@/common/log';
import { EncodeArgs } from '@/common/audio-worker';
import { FFmpegService } from '@/common/ffmpeg';
import { runTask } from './worker';
import { LogWrapper } from '@/napcat-core/helper/log';
import { EncodeArgs } from 'napcat-common/src/audio-worker';
import { FFmpegService } from '@/napcat-core/helper/ffmpeg/ffmpeg';
import { runTask } from 'napcat-common/src/worker';
import { fileURLToPath } from 'node:url';
const ALLOW_SAMPLE_RATE = [8000, 12000, 16000, 24000, 32000, 44100, 48000];

View File

@@ -1,6 +1,6 @@
import path from 'node:path';
import fs from 'node:fs';
import type { NapCatCore } from '@/core';
import type { NapCatCore } from '@/napcat-core';
import json5 from 'json5';
import Ajv, { AnySchema, ValidateFunction } from 'ajv';

View File

@@ -1,5 +1,5 @@
import { ConfigBase } from '@/common/config-base';
import { NapCatCore } from '@/core';
import { ConfigBase } from '@/napcat-core/helper/config-base';
import { NapCatCore } from '@/napcat-core/index';
import { Type, Static } from '@sinclair/typebox';
import { AnySchema } from 'ajv';

View File

@@ -1,6 +1,6 @@
import { NodeIQQNTWrapperSession } from '@/core/wrapper';
import { NodeIQQNTWrapperSession } from '@/napcat-core/wrapper';
import { randomUUID } from 'crypto';
import { ListenerNamingMapping, ServiceNamingMapping } from '@/core';
import { ListenerNamingMapping, ServiceNamingMapping } from '@/napcat-core/index';
interface InternalMapKey {
timeout: number;
@@ -54,7 +54,7 @@ export class NTEventWrapper {
Service extends keyof ServiceNamingMapping,
ServiceMethod extends FuncKeys<ServiceNamingMapping[Service]>,
T extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>
> (eventName: `${Service}/${ServiceMethod}`): T | undefined {
>(eventName: `${Service}/${ServiceMethod}`): T | undefined {
const eventNameArr = eventName.split('/');
type eventType = {
[key: string]: () => { [key: string]: (...params: Parameters<T>) => Promise<ReturnType<T>>; };
@@ -112,7 +112,7 @@ export class NTEventWrapper {
Service extends keyof ServiceNamingMapping,
ServiceMethod extends FuncKeys<ServiceNamingMapping[Service]>,
EventType extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>
> (
>(
serviceAndMethod: `${Service}/${ServiceMethod}`,
...args: Parameters<EventType>
): Promise<Awaited<ReturnType<EventType>>> {
@@ -123,7 +123,7 @@ export class NTEventWrapper {
Listener extends keyof ListenerNamingMapping,
ListenerMethod extends FuncKeys<ListenerNamingMapping[Listener]>,
ListenerType extends (...args: any) => any = EnsureFunc<ListenerNamingMapping[Listener][ListenerMethod]>
> (
>(
listenerAndMethod: `${Listener}/${ListenerMethod}`,
checker: (...args: Parameters<ListenerType>) => boolean,
waitTimes = 1,
@@ -177,7 +177,7 @@ export class NTEventWrapper {
ListenerMethod extends FuncKeys<ListenerNamingMapping[Listener]>,
EventType extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>,
ListenerType extends (...args: any) => any = EnsureFunc<ListenerNamingMapping[Listener][ListenerMethod]>
> (
>(
serviceAndMethod: `${Service}/${ServiceMethod}`,
listenerAndMethod: `${Listener}/${ListenerMethod}`,
args: Parameters<EventType>,

View File

@@ -6,7 +6,7 @@ import * as os from 'os';
import * as compressing from 'compressing'; // 修正导入方式
import { pipeline } from 'stream/promises';
import { fileURLToPath } from 'url';
import { LogWrapper } from './log';
import { LogWrapper } from '@/napcat-core/helper/log';
const downloadOri = 'https://github.com/NapNeko/ffmpeg-build/releases/download/v1.0.0/ffmpeg-7.1.1-win64.zip';
const urls = [

View File

@@ -3,7 +3,7 @@
* FFmpeg
*/
import { LogWrapper } from './log';
import { LogWrapper } from '@/napcat-core/helper/log';
import { FFmpegAddonAdapter } from './ffmpeg-addon-adapter';
import { FFmpegExecAdapter } from './ffmpeg-exec-adapter';
import type { IFFmpegAdapter } from './ffmpeg-adapter-interface';

View File

@@ -68,13 +68,13 @@ export class FFmpegAddonAdapter implements IFFmpegAdapter {
const addon = this.ensureAddon();
const info = await addon.getVideoInfo(videoPath);
let format = info.format.includes(',') ? info.format.split(',')[0] ?? info.format : info.format;
const format = info.format.includes(',') ? info.format.split(',')[0] ?? info.format : info.format;
console.log('[FFmpegAddonAdapter] Detected format:', format);
return {
width: info.width,
height: info.height,
duration: info.duration,
format: format,
format,
thumbnail: info.image,
};
}

View File

@@ -8,9 +8,9 @@ import { dirname, join } from 'path';
import { execFile } from 'child_process';
import { promisify } from 'util';
import { fileTypeFromFile } from 'file-type';
import { imageSizeFallBack } from '@/image-size';
import { imageSizeFallBack } from 'napcat-image-size/src/index';
import { downloadFFmpegIfNotExists } from './download-ffmpeg';
import { LogWrapper } from './log';
import { LogWrapper } from '@/napcat-core/helper/log';
import type { IFFmpegAdapter, VideoInfoResult } from './ffmpeg-adapter-interface';
const execFileAsync = promisify(execFile);

View File

@@ -3,7 +3,7 @@ import path from 'path';
import type { VideoInfo } from './video';
import { fileTypeFromFile } from 'file-type';
import { platform } from 'node:os';
import { LogWrapper } from './log';
import { LogWrapper } from '@/napcat-core/helper/log';
import { FFmpegAdapterFactory } from './ffmpeg-adapter-factory';
import type { IFFmpegAdapter } from './ffmpeg-adapter-interface';
@@ -53,7 +53,6 @@ export class FFmpegService {
throw new Error('FFmpeg service not initialized. Please call FFmpegService.init() first.');
}
return this.adapter.name;
}
/**

View File

@@ -1,5 +1,5 @@
import * as crypto from 'node:crypto';
import { PacketMsg } from '@/core/packet/message/message';
import { PacketMsg } from '@/napcat-core/packet/message/message';
interface ForwardMsgJson {
app: string

View File

@@ -1,8 +1,9 @@
import winston, { format, transports } from 'winston';
import { truncateString } from '@/common/helper';
import { truncateString } from 'napcat-common/src/helper';
import path from 'node:path';
import fs from 'node:fs/promises';
import { NTMsgAtType, ChatType, ElementType, MessageElement, RawMessage, SelfInfo } from '@/core';
import { NTMsgAtType, ChatType, ElementType, MessageElement, RawMessage, SelfInfo } from '@/napcat-core/index';
import { ILogWrapper } from 'napcat-common/src/log-interface';
import EventEmitter from 'node:events';
export enum LogLevel {
DEBUG = 'debug',
@@ -56,7 +57,7 @@ class Subscription {
export const logSubscription = new Subscription();
export class LogWrapper {
export class LogWrapper implements ILogWrapper {
fileLogEnabled = true;
consoleLogEnabled = true;
logger: winston.Logger;

View File

@@ -1,4 +1,4 @@
import { LogWrapper } from '@/common/log';
import { LogWrapper } from '@/napcat-core/helper/log';
export function proxyHandlerOf (logger: LogWrapper) {
return {

View File

@@ -1,10 +1,10 @@
import fs from 'node:fs';
import { systemPlatform } from '@/common/system';
import { getDefaultQQVersionConfigInfo, getQQPackageInfoPath, getQQVersionConfigPath, parseAppidFromMajor } from './helper';
import AppidTable from '@/core/external/appid.json';
import { LogWrapper } from '@/common/log';
import { getMajorPath } from '@/core';
import { QQAppidTableType, QQPackageInfoType, QQVersionConfigType } from './types';
import { systemPlatform } from 'napcat-common/src/system';
import { getDefaultQQVersionConfigInfo, getQQPackageInfoPath, getQQVersionConfigPath, parseAppidFromMajor } from 'napcat-common/src/helper';
import AppidTable from '@/napcat-core/external/appid.json';
import { LogWrapper } from './log';
import { getMajorPath } from '@/napcat-core/index';
import { QQAppidTableType, QQPackageInfoType, QQVersionConfigType } from 'napcat-common/src/types';
export class QQBasicInfoWrapper {
QQMainPath: string | undefined;

View File

@@ -1,5 +1,5 @@
import { LogWrapper } from '@/common/log';
import { RequestUtil } from '@/common/request';
import { RequestUtil } from 'napcat-common/src/request';
import { LogWrapper } from './log';
interface ServerRkeyData {
group_rkey: string;

View File

@@ -1,24 +1,24 @@
import os from 'node:os';
import EventEmitter from 'node:events';
import { IStatusHelperSubscription } from 'napcat-common/src/status-interface';
export interface SystemStatus {
cpu: {
model: string,
speed: string
speed: string;
usage: {
system: string
qq: string
system: string;
qq: string;
},
core: number
core: number;
},
memory: {
total: string
total: string;
usage: {
system: string
qq: string
}
system: string;
qq: string;
};
},
arch: string
arch: string;
}
export class StatusHelper {
@@ -101,7 +101,7 @@ export class StatusHelper {
}
}
class StatusHelperSubscription extends EventEmitter {
class StatusHelperSubscription extends EventEmitter implements IStatusHelperSubscription {
private statusHelper: StatusHelper;
private interval: NodeJS.Timeout | null = null;

View File

@@ -6,8 +6,8 @@ import {
NTQQSystemApi,
NTQQUserApi,
NTQQWebApi,
} from '@/core/apis';
import { NTQQCollectionApi } from '@/core/apis/collection';
} from '@/napcat-core/apis';
import { NTQQCollectionApi } from '@/napcat-core/apis/collection';
import {
NodeIQQNTWrapperSession,
NodeQQNTWrapperUtil,
@@ -15,26 +15,29 @@ import {
VendorType,
WrapperNodeApi,
WrapperSessionInitConfig,
} from '@/core/wrapper';
import { LogLevel, LogWrapper } from '@/common/log';
import { NodeIKernelLoginService } from '@/core/services';
import { QQBasicInfoWrapper } from '@/common/qq-basic-info';
import { NapCatPathWrapper } from '@/common/path';
} from '@/napcat-core/wrapper';
import { LogLevel, LogWrapper } from '@/napcat-core/helper/log';
import { NodeIKernelLoginService } from '@/napcat-core/services';
import { QQBasicInfoWrapper } from '@/napcat-core/helper/qq-basic-info';
import { NapCatPathWrapper } from 'napcat-common/src/path';
import path from 'node:path';
import fs from 'node:fs';
import { hostname, systemName, systemVersion } from '@/common/system';
import { NTEventWrapper } from '@/common/event';
import { KickedOffLineInfo, SelfInfo, SelfStatusInfo } from '@/core/types';
import { NapCatConfigLoader, NapcatConfigSchema } from '@/core/helper/config';
import { hostname, systemName, systemVersion } from 'napcat-common/src/system';
import { NTEventWrapper } from '@/napcat-core/helper/event';
import { KickedOffLineInfo, SelfInfo, SelfStatusInfo } from '@/napcat-core/types';
import { NapCatConfigLoader, NapcatConfigSchema } from '@/napcat-core/helper/config';
import os from 'node:os';
import { NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/core/listeners';
import { proxiedListenerOf } from '@/common/proxy-handler';
import { NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/napcat-core/listeners';
import { proxiedListenerOf } from '@/napcat-core/helper/proxy-handler';
import { NTQQPacketApi } from './apis/packet';
import { NativePacketHandler } from './packet/handler/client';
import { container, ReceiverServiceRegistry } from './packet/handler/serviceRegister';
import { appEvent } from './packet/handler/eventList';
import { TypedEventEmitter } from './packet/handler/typeEvent';
export * from './wrapper';
export * from './types';
export * from './services';
export * from './listeners';
export * from './types/index';
export * from './services/index';
export * from './listeners/index';
export enum NapCatCoreWorkingEnv {
Unknown = 0,
@@ -92,6 +95,7 @@ export function getMajorPath (QQVersion: string): string {
export class NapCatCore {
readonly context: InstanceContext;
readonly eventWrapper: NTEventWrapper;
event = appEvent;
NapCatDataPath: string = '';
NapCatTempPath: string = '';
apis: StableNTApiWrapper;
@@ -118,6 +122,16 @@ export class NapCatCore {
UserApi: new NTQQUserApi(this.context, this),
GroupApi: new NTQQGroupApi(this.context, this),
};
container.bind(NapCatCore).toConstantValue(this);
container.bind(TypedEventEmitter).toConstantValue(this.event);
ReceiverServiceRegistry.forEach((ServiceClass, serviceName) => {
container.bind(ServiceClass).toSelf();
console.log(`Registering service handler for: ${serviceName}`);
this.context.packetHandler.onCmd(serviceName, ({ seq, hex_data }) => {
const serviceInstance = container.get(ServiceClass);
return serviceInstance.handler(seq, hex_data);
});
});
}
async initCore () {

View File

@@ -1,4 +1,4 @@
import { BuddyCategoryType, FriendRequestNotify } from '@/core/types';
import { BuddyCategoryType, FriendRequestNotify } from '@/napcat-core/types';
export type OnBuddyChangeParams = BuddyCategoryType[];

View File

@@ -1,4 +1,4 @@
import { DataSource, Group, GroupDetailInfo, GroupListUpdateType, GroupMember, GroupNotify, ShutUpGroupMember } from '@/core/types';
import { DataSource, Group, GroupDetailInfo, GroupListUpdateType, GroupMember, GroupNotify, ShutUpGroupMember } from '@/napcat-core/types';
export class NodeIKernelGroupListener {
onGroupListInited (_listEmpty: boolean): any { }

View File

@@ -1,5 +1,5 @@
import { ChatType, KickedOffLineInfo, RawMessage } from '@/core/types';
import { CommonFileInfo } from '@/core';
import { ChatType, KickedOffLineInfo, RawMessage } from '@/napcat-core/types';
import { CommonFileInfo } from '@/napcat-core/index';
export interface OnRichMediaDownloadCompleteParams {
fileModelId: string,

View File

@@ -1,4 +1,4 @@
import { User, UserDetailInfoListenerArg } from '@/core/types';
import { User, UserDetailInfoListenerArg } from '@/napcat-core/types';
export class NodeIKernelProfileListener {
onUserDetailInfoChanged (_arg: UserDetailInfoListenerArg): void {

View File

@@ -1,4 +1,4 @@
import { ChatType, RawMessage } from '@/core';
import { ChatType, RawMessage } from '@/napcat-core/index';
export interface SearchGroupInfo {
groupCode: string;
ownerUid: string;

Some files were not shown because too many files have changed in this diff Show More