create-maa-project 1.2.2__tar.gz → 1.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/.release/create-maa-project-manifest.json +23 -23
  2. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/PKG-INFO +1 -1
  3. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/package.json +1 -1
  4. create_maa_project-1.2.3/py-wrapper/create_maa_project/__init__.py +1 -0
  5. create_maa_project-1.2.3/py-wrapper/create_maa_project/release_manifest.py +2 -0
  6. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/pyproject.toml +1 -1
  7. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/github/tools/build-release.mjs +23 -0
  8. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/agent/bootstrap.py +137 -20
  9. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/tests/scaffold.test.ts +6 -0
  10. create_maa_project-1.2.3/tests/test_agent_bootstrap.py +153 -0
  11. create_maa_project-1.2.2/py-wrapper/create_maa_project/__init__.py +0 -1
  12. create_maa_project-1.2.2/py-wrapper/create_maa_project/release_manifest.py +0 -2
  13. create_maa_project-1.2.2/tests/test_agent_bootstrap.py +0 -39
  14. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/.editorconfig +0 -0
  15. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/.gitattributes +0 -0
  16. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/.github/cliff.toml +0 -0
  17. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/.github/workflows/network-assets.yml +0 -0
  18. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/.github/workflows/release.yml +0 -0
  19. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/.github/workflows/schema-sync.yml +0 -0
  20. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/.gitignore +0 -0
  21. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/.prettierignore +0 -0
  22. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/.prettierrc.mjs +0 -0
  23. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/LICENSE +0 -0
  24. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/README.en.md +0 -0
  25. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/README.md +0 -0
  26. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/pnpm-lock.yaml +0 -0
  27. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/pnpm-workspace.yaml +0 -0
  28. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/py-wrapper/create_maa_project/__main__.py +0 -0
  29. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/scripts/build-sea.mjs +0 -0
  30. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/scripts/build.mjs +0 -0
  31. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/scripts/check-network-assets.ts +0 -0
  32. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/scripts/create-release-manifest.mjs +0 -0
  33. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/scripts/generate-template-assets.mjs +0 -0
  34. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/scripts/prepare-pypi-release.mjs +0 -0
  35. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/scripts/sync-release-version.mjs +0 -0
  36. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/scripts/sync-schema.mjs +0 -0
  37. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/scripts/test-python.mjs +0 -0
  38. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/addons.ts +0 -0
  39. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/args.ts +0 -0
  40. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/assets.ts +0 -0
  41. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/controllers.ts +0 -0
  42. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/doctor.ts +0 -0
  43. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/features.ts +0 -0
  44. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/incremental-addons.ts +0 -0
  45. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/index.ts +0 -0
  46. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/lang.ts +0 -0
  47. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/log.ts +0 -0
  48. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/mcp.ts +0 -0
  49. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/project.ts +0 -0
  50. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/prompt.ts +0 -0
  51. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/report.ts +0 -0
  52. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/scaffold.ts +0 -0
  53. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/sync.ts +0 -0
  54. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/template-assets.generated.ts +0 -0
  55. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/templates.ts +0 -0
  56. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/types.ts +0 -0
  57. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/update.ts +0 -0
  58. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/src/utils.ts +0 -0
  59. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/auto-format/.github/workflows/format.yml +0 -0
  60. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/community/CONTRIBUTING.md +0 -0
  61. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/community/PULL_REQUEST_TEMPLATE.md +0 -0
  62. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/community/bug_report.yml +0 -0
  63. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/community/feature_request.yml +0 -0
  64. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/community/issue_config.yml +0 -0
  65. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/community/other_issue.yml +0 -0
  66. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/dependabot/.github/dependabot.yml +0 -0
  67. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/dev-tools/.vscode/extensions.agent.json +0 -0
  68. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/dev-tools/.vscode/extensions.json +0 -0
  69. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/dev-tools/.vscode/launch.agent.json +0 -0
  70. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/dev-tools/.vscode/settings.agent.json +0 -0
  71. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/dev-tools/.vscode/settings.json +0 -0
  72. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/dev-tools/.vscode/tasks.github.json +0 -0
  73. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/dev-tools/.vscode/tasks.json +0 -0
  74. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/dev-tools/package.json +0 -0
  75. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/dev-tools/pnpm-workspace.yaml +0 -0
  76. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/dev-tools/tools/check-project.mjs +0 -0
  77. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/dev-tools/tools/validate-schema.mjs +0 -0
  78. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/git-cliff/.github/cliff.toml +0 -0
  79. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/github/.github/workflows/check.yml +0 -0
  80. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/github/.github/workflows/release.yml +0 -0
  81. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/github/tools/sync-runtime.mjs +0 -0
  82. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/optimize-images/.github/workflows/optimize-images.yml +0 -0
  83. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/optimize-images/tools/optimize-images.mjs +0 -0
  84. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/schema-sync/.github/workflows/schema-sync.yml +0 -0
  85. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/addons/schema-sync/tools/sync-schema.mjs +0 -0
  86. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/README.en.md +0 -0
  87. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/README.md +0 -0
  88. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/agent/__init__.py +0 -0
  89. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/agent/agent_runtime.py +0 -0
  90. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/agent/custom/__init__.py +0 -0
  91. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/agent/custom/action/__init__.py +0 -0
  92. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/agent/custom/action/general.py +0 -0
  93. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/agent/custom/reco/__init__.py +0 -0
  94. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/agent/custom/reco/general.py +0 -0
  95. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/agent/custom/sink/__init__.py +0 -0
  96. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/agent/main.py +0 -0
  97. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/agent/utils/__init__.py +0 -0
  98. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/agent/utils/logger.py +0 -0
  99. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/agent/utils/maa_types.py +0 -0
  100. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/agent/utils/params.py +0 -0
  101. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/agent/utils/pienv.py +0 -0
  102. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/agent/utils/runtime_paths.py +0 -0
  103. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/pyproject.toml +0 -0
  104. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/requirements.txt +0 -0
  105. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/tools/schema/custom.action.schema.json +0 -0
  106. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/tools/schema/custom.recognition.schema.json +0 -0
  107. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/agent/uv.lock +0 -0
  108. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/.editorconfig +0 -0
  109. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/.gitattributes +0 -0
  110. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/.gitignore +0 -0
  111. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/.prettierignore +0 -0
  112. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/.prettierrc.mjs +0 -0
  113. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/README.en.md +0 -0
  114. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/README.md +0 -0
  115. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/gitignore.tmpl +0 -0
  116. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/interface.json.tmpl +0 -0
  117. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/licenses/AGPL-3.0-or-later.txt +0 -0
  118. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/licenses/MIT.txt +0 -0
  119. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/maatools.config.mts +0 -0
  120. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/resource/base/default_pipeline.json +0 -0
  121. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/resource/base/image/empty.png +0 -0
  122. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/resource/base/model/ocr/manifest.json +0 -0
  123. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/resource/base/pipeline/tutorial.json +0 -0
  124. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/tasks/tutorial.json +0 -0
  125. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/tools/schema/custom.action.schema.json +0 -0
  126. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/tools/schema/custom.recognition.schema.json +0 -0
  127. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/tools/schema/interface.schema.json +0 -0
  128. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/tools/schema/interface_config.schema.json +0 -0
  129. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/tools/schema/interface_import.schema.json +0 -0
  130. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/tools/schema/pipeline.schema.json +0 -0
  131. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/templates/base/tools/schema/schema-manifest.json +0 -0
  132. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/tests/addons.test.ts +0 -0
  133. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/tests/args.test.ts +0 -0
  134. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/tests/child-env.ts +0 -0
  135. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/tests/lang.test.ts +0 -0
  136. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/tests/mcp.test.ts +0 -0
  137. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/tests/project.test.ts +0 -0
  138. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/tests/prompt.test.ts +0 -0
  139. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/tests/report.test.ts +0 -0
  140. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/tests/templates.test.ts +0 -0
  141. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/tests/test_py_wrapper.py +0 -0
  142. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/tsconfig.json +0 -0
  143. {create_maa_project-1.2.2 → create_maa_project-1.2.3}/vitest.config.ts +0 -0
@@ -1,68 +1,68 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "name": "create-maa-project",
4
- "version": "1.2.2",
5
- "tag": "v1.2.2",
4
+ "version": "1.2.3",
5
+ "tag": "v1.2.3",
6
6
  "assets": [
7
7
  {
8
8
  "kind": "sea",
9
9
  "os": "linux",
10
10
  "arch": "aarch64",
11
- "version": "1.2.2",
11
+ "version": "1.2.3",
12
12
  "name": "create-maa-project-linux-aarch64",
13
- "url": "https://github.com/Windsland52/create-maa-project/releases/download/v1.2.2/create-maa-project-linux-aarch64",
14
- "sha256": "302f1b94b68ead54ccfd7da68c5f0631fe2ea354469cc59da9238325cec6cc8f",
13
+ "url": "https://github.com/Windsland52/create-maa-project/releases/download/v1.2.3/create-maa-project-linux-aarch64",
14
+ "sha256": "8a6eda1cabb647e0df9ba8f2e12e273317089a97b43c465a54e3b5dc1ef0bc73",
15
15
  "size": 123145344
16
16
  },
17
17
  {
18
18
  "kind": "sea",
19
19
  "os": "linux",
20
20
  "arch": "x86_64",
21
- "version": "1.2.2",
21
+ "version": "1.2.3",
22
22
  "name": "create-maa-project-linux-x86_64",
23
- "url": "https://github.com/Windsland52/create-maa-project/releases/download/v1.2.2/create-maa-project-linux-x86_64",
24
- "sha256": "8ee14bcb3fafea060891cf98b2a131381065c7053019ac4eb1d6dffc4fa36ff6",
23
+ "url": "https://github.com/Windsland52/create-maa-project/releases/download/v1.2.3/create-maa-project-linux-x86_64",
24
+ "sha256": "f4cb775d3d85aba1475ef041d654de13a06cdf17801bc479648bd75e351932b5",
25
25
  "size": 125045952
26
26
  },
27
27
  {
28
28
  "kind": "sea",
29
29
  "os": "macos",
30
30
  "arch": "aarch64",
31
- "version": "1.2.2",
31
+ "version": "1.2.3",
32
32
  "name": "create-maa-project-macos-aarch64",
33
- "url": "https://github.com/Windsland52/create-maa-project/releases/download/v1.2.2/create-maa-project-macos-aarch64",
34
- "sha256": "b5cac2f528e7029224283dd7f623f85b6ab6199476ee6d29742d3323352119e4",
33
+ "url": "https://github.com/Windsland52/create-maa-project/releases/download/v1.2.3/create-maa-project-macos-aarch64",
34
+ "sha256": "d0fe39da998fdde748ea5477618a705dad9adfb45ea8d34e17c8aa63430b943b",
35
35
  "size": 121408240
36
36
  },
37
37
  {
38
38
  "kind": "sea",
39
39
  "os": "macos",
40
40
  "arch": "x86_64",
41
- "version": "1.2.2",
41
+ "version": "1.2.3",
42
42
  "name": "create-maa-project-macos-x86_64",
43
- "url": "https://github.com/Windsland52/create-maa-project/releases/download/v1.2.2/create-maa-project-macos-x86_64",
44
- "sha256": "05bb2f42843ce33bcb76e2dd701050ce224905bb08e5c620a4a6c62d7bb5da85",
45
- "size": 124472240
43
+ "url": "https://github.com/Windsland52/create-maa-project/releases/download/v1.2.3/create-maa-project-macos-x86_64",
44
+ "sha256": "68364953c76c81d8426ebaf2fc571296ecedc81f3f2f3c2e2f75146d98e7e16c",
45
+ "size": 124476368
46
46
  },
47
47
  {
48
48
  "kind": "sea",
49
49
  "os": "win",
50
50
  "arch": "aarch64",
51
- "version": "1.2.2",
51
+ "version": "1.2.3",
52
52
  "name": "create-maa-project-win-aarch64.exe",
53
- "url": "https://github.com/Windsland52/create-maa-project/releases/download/v1.2.2/create-maa-project-win-aarch64.exe",
54
- "sha256": "a554bdc37a181d7a407b1027effe5913a33833cea59c7707e1ec1fdd01df6342",
55
- "size": 82560000
53
+ "url": "https://github.com/Windsland52/create-maa-project/releases/download/v1.2.3/create-maa-project-win-aarch64.exe",
54
+ "sha256": "68c26c233b409357e8873b014918c71bc3012addf9678315e4273180d2760ff3",
55
+ "size": 82565120
56
56
  },
57
57
  {
58
58
  "kind": "sea",
59
59
  "os": "win",
60
60
  "arch": "x86_64",
61
- "version": "1.2.2",
61
+ "version": "1.2.3",
62
62
  "name": "create-maa-project-win-x86_64.exe",
63
- "url": "https://github.com/Windsland52/create-maa-project/releases/download/v1.2.2/create-maa-project-win-x86_64.exe",
64
- "sha256": "8a70811812de26fe0b9b51eb7908bd411351bfdbfe20da857bae82fb6d86db5c",
65
- "size": 94026240
63
+ "url": "https://github.com/Windsland52/create-maa-project/releases/download/v1.2.3/create-maa-project-win-x86_64.exe",
64
+ "sha256": "e730e080a811fc901ea7c1932792452118d6468676bdb6560af491e0b8e796ff",
65
+ "size": 94031360
66
66
  }
67
67
  ]
68
68
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: create-maa-project
3
- Version: 1.2.2
3
+ Version: 1.2.3
4
4
  Summary: 用于创建和维护 MaaFW 应用项目的脚手架 CLI / Scaffold and maintenance CLI for MaaFW application projects
5
5
  Project-URL: Homepage, https://github.com/Windsland52/create-maa-project
6
6
  Project-URL: Source, https://github.com/Windsland52/create-maa-project
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-maa-project",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "用于创建和维护 MaaFW 应用项目的脚手架 CLI / Scaffold and maintenance CLI for MaaFW application projects",
5
5
  "keywords": [
6
6
  "maafw",
@@ -0,0 +1 @@
1
+ __version__ = "1.2.3"
@@ -0,0 +1,2 @@
1
+ # Filled by the release workflow when publishing the PyPI wrapper.
2
+ RELEASE_MANIFEST_SHA256 = "63b2a8f2fb60bed85e531ca81d842844cad9c8cfc4c53865c9b7e61dc4cf79a8"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "create-maa-project"
3
- version = "1.2.2"
3
+ version = "1.2.3"
4
4
  description = "用于创建和维护 MaaFW 应用项目的脚手架 CLI / Scaffold and maintenance CLI for MaaFW application projects"
5
5
  keywords = ["maafw", "scaffold", "mcp"]
6
6
  readme = "README.md"
@@ -10,11 +10,13 @@ import {
10
10
  statSync,
11
11
  writeFileSync,
12
12
  } from "node:fs";
13
+ import {createHash} from "node:crypto";
13
14
  import {basename, dirname, join} from "node:path";
14
15
 
15
16
  const dryRun = process.argv.includes("--dry-run");
16
17
  const projectSlug = {{projectSlug}};
17
18
  const releaseArtifactName = {{releaseArtifactName}};
19
+ const requirementsMarker = ".create-maa-project-requirements.sha256";
18
20
  mkdirSync("dist", {recursive: true});
19
21
 
20
22
  const lock = readJson("maa-project.lock.json");
@@ -278,6 +280,7 @@ function prepareReleasePackage(guiKey, gui, packagePaths, interfaceJson, runtime
278
280
  }
279
281
  if (packageHasAgent(interfaceJson) && hasEmbeddedPythonRuntime(runtimePlatform)) {
280
282
  copyPath(pythonRuntimePath(runtimePlatform), join(pkgDir, "python"));
283
+ writeEmbeddedRequirementsMarker(pkgDir);
281
284
  }
282
285
  if (!gui.flatLayout) {
283
286
  prepareMxuMaafwRuntime(pkgDir, runtimePlatform);
@@ -364,6 +367,17 @@ function smokeReleasePackage(gui, root, packagePaths, runtimePlatform) {
364
367
  if (!existsSync(join(root, "agent", "bootstrap.py"))) {
365
368
  throw new Error("release package smoke failed: Agent bootstrap is missing");
366
369
  }
370
+ if (hasEmbeddedPythonRuntime(runtimePlatform)) {
371
+ const markerPath = join(root, "python", requirementsMarker);
372
+ if (!existsSync(markerPath)) {
373
+ throw new Error("release package smoke failed: Python requirements marker is missing");
374
+ }
375
+ const expectedDigest = requirementsDigest(join(root, "requirements.txt"));
376
+ const actualDigest = readFileSync(markerPath, "utf8").trim();
377
+ if (actualDigest !== expectedDigest) {
378
+ throw new Error("release package smoke failed: Python requirements marker does not match requirements.txt");
379
+ }
380
+ }
367
381
  }
368
382
  assertUnixExecutablePermissions(root, runtimePlatform);
369
383
  for (const path of [
@@ -409,6 +423,15 @@ function copyDirectoryContents(source, target) {
409
423
  }
410
424
  }
411
425
 
426
+ function requirementsDigest(requirementsPath) {
427
+ return createHash("sha256").update(readFileSync(requirementsPath)).digest("hex");
428
+ }
429
+
430
+ function writeEmbeddedRequirementsMarker(pkgDir) {
431
+ const digest = requirementsDigest(join(pkgDir, "requirements.txt"));
432
+ writeFileSync(join(pkgDir, "python", requirementsMarker), digest + "\n", "utf8");
433
+ }
434
+
412
435
  function shouldCopyAgentPath(source) {
413
436
  const name = basename(source).toLowerCase();
414
437
  return name !== "__pycache__" && !name.endsWith(".pyc") && !name.endsWith(".pyo");
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import errno
3
4
  import hashlib
4
5
  import importlib.metadata
5
6
  import json
@@ -8,14 +9,19 @@ import runpy
8
9
  import shutil
9
10
  import subprocess
10
11
  import sys
12
+ import time
13
+ from collections.abc import Generator
14
+ from contextlib import contextmanager
11
15
  from datetime import UTC, datetime
12
16
  from pathlib import Path
13
- from typing import Any
17
+ from typing import Any, BinaryIO
14
18
 
15
19
  PYTHON_MIN = (3, 13)
16
20
  PYTHON_MAX = (3, 14)
17
21
  VENV_NAME = ".venv"
18
22
  REQUIREMENTS_MARKER = ".create-maa-project-requirements.sha256"
23
+ REQUIREMENTS_LOCK = ".create-maa-project-requirements.lock"
24
+ REQUIREMENTS_LOCK_TIMEOUT_SECONDS = 300.0
19
25
  DEFAULT_PIP_CONFIG = {
20
26
  "enable_pip_install": True,
21
27
  "mirror": "https://pypi.tuna.tsinghua.edu.cn/simple",
@@ -172,23 +178,26 @@ def find_requirements_file(project_root: Path) -> Path:
172
178
 
173
179
 
174
180
  def ensure_requirements_installed(project_root: Path, requirements: Path, digest: str) -> None:
175
- if not needs_requirement_install(project_root, digest):
176
- return
177
-
178
- pip_config = read_pip_config(project_root)
179
- if not pip_config.get("enable_pip_install", True):
180
- warn(project_root, "pip install is disabled by config/pip_config.json")
181
- return
182
-
183
- if install_from_local_wheels(project_root, requirements) or install_from_indexes(
184
- project_root,
185
- requirements,
186
- pip_config,
187
- ):
188
- write_requirements_marker(project_root, digest)
189
- return
181
+ with requirements_install_lock(project_root):
182
+ # Another Agent may have completed the installation while this process
183
+ # waited for the shared environment lock.
184
+ if not needs_requirement_install(project_root, digest):
185
+ return
186
+
187
+ pip_config = read_pip_config(project_root)
188
+ if not pip_config.get("enable_pip_install", True):
189
+ warn(project_root, "pip install is disabled by config/pip_config.json")
190
+ return
191
+
192
+ if install_from_local_wheels(project_root, requirements) or install_from_indexes(
193
+ project_root,
194
+ requirements,
195
+ pip_config,
196
+ ):
197
+ write_requirements_marker(project_root, digest)
198
+ return
190
199
 
191
- warn(project_root, "Python dependencies were not installed successfully")
200
+ warn(project_root, "Python dependencies were not installed successfully")
192
201
 
193
202
 
194
203
  def needs_requirement_install(project_root: Path, digest: str) -> bool:
@@ -203,16 +212,121 @@ def needs_requirement_install(project_root: Path, digest: str) -> bool:
203
212
  def requirements_marker(project_root: Path) -> Path:
204
213
  if is_running_in_project_venv(project_root):
205
214
  return venv_dir(project_root) / REQUIREMENTS_MARKER
215
+ if is_running_in_embedded_python(project_root):
216
+ return project_root / "python" / REQUIREMENTS_MARKER
206
217
  return project_root / "debug" / REQUIREMENTS_MARKER
207
218
 
208
219
 
220
+ def is_running_in_embedded_python(project_root: Path) -> bool:
221
+ try:
222
+ return Path(sys.executable).resolve().is_relative_to((project_root / "python").resolve())
223
+ except OSError:
224
+ return False
225
+
226
+
227
+ def requirements_lock_path(project_root: Path) -> Path:
228
+ return requirements_marker(project_root).with_name(REQUIREMENTS_LOCK)
229
+
230
+
231
+ @contextmanager
232
+ def requirements_install_lock(
233
+ project_root: Path,
234
+ timeout_seconds: float = REQUIREMENTS_LOCK_TIMEOUT_SECONDS,
235
+ ) -> Generator[None]:
236
+ lock_path = requirements_lock_path(project_root)
237
+ try:
238
+ lock_path.parent.mkdir(parents=True, exist_ok=True)
239
+ handle = lock_path.open("a+b")
240
+ except OSError as error:
241
+ warn(project_root, "failed to open Python requirements install lock: " + str(error))
242
+ raise SystemExit(1) from error
243
+
244
+ with handle:
245
+ try:
246
+ ensure_lock_file_byte(handle)
247
+ except OSError as error:
248
+ warn(project_root, "failed to initialize Python requirements install lock: " + str(error))
249
+ raise SystemExit(1) from error
250
+
251
+ deadline = time.monotonic() + timeout_seconds
252
+ waiting_logged = False
253
+ while True:
254
+ try:
255
+ acquired = try_lock_file(handle)
256
+ except OSError as error:
257
+ warn(project_root, "failed to acquire Python requirements install lock: " + str(error))
258
+ raise SystemExit(1) from error
259
+ if acquired:
260
+ break
261
+ if not waiting_logged:
262
+ log(project_root, "waiting for Python requirements install lock: " + str(lock_path))
263
+ waiting_logged = True
264
+ if time.monotonic() >= deadline:
265
+ warn(project_root, "timed out waiting for Python requirements install lock: " + str(lock_path))
266
+ raise SystemExit(1)
267
+ time.sleep(0.1)
268
+
269
+ log(project_root, "acquired Python requirements install lock: " + str(lock_path))
270
+ try:
271
+ yield
272
+ finally:
273
+ try:
274
+ unlock_file(handle)
275
+ except OSError as error:
276
+ warn(project_root, "failed to release Python requirements install lock: " + str(error))
277
+
278
+
279
+ def ensure_lock_file_byte(handle: BinaryIO) -> None:
280
+ handle.seek(0, 2)
281
+ if handle.tell() == 0:
282
+ handle.write(b"\0")
283
+ handle.flush()
284
+ handle.seek(0)
285
+
286
+
287
+ def try_lock_file(handle: BinaryIO) -> bool:
288
+ handle.seek(0)
289
+ try:
290
+ if sys.platform.startswith("win"):
291
+ import msvcrt
292
+
293
+ msvcrt.locking(handle.fileno(), msvcrt.LK_NBLCK, 1)
294
+ else:
295
+ import fcntl
296
+
297
+ fcntl.flock(handle.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
298
+ except OSError as error:
299
+ if error.errno in (errno.EACCES, errno.EAGAIN):
300
+ return False
301
+ raise
302
+ return True
303
+
304
+
305
+ def unlock_file(handle: BinaryIO) -> None:
306
+ handle.seek(0)
307
+ if sys.platform.startswith("win"):
308
+ import msvcrt
309
+
310
+ msvcrt.locking(handle.fileno(), msvcrt.LK_UNLCK, 1)
311
+ else:
312
+ import fcntl
313
+
314
+ fcntl.flock(handle.fileno(), fcntl.LOCK_UN)
315
+
316
+
209
317
  def write_requirements_marker(project_root: Path, digest: str) -> None:
210
318
  marker = requirements_marker(project_root)
319
+ temp_marker = marker.with_name(marker.name + ".tmp")
211
320
  try:
212
321
  marker.parent.mkdir(parents=True, exist_ok=True)
213
- marker.write_text(digest + "\n", encoding="utf8")
322
+ temp_marker.write_text(digest + "\n", encoding="utf8")
323
+ temp_marker.replace(marker)
214
324
  except OSError as error:
215
325
  warn(project_root, "failed to write requirements marker: " + str(error))
326
+ try:
327
+ temp_marker.unlink(missing_ok=True)
328
+ except OSError:
329
+ pass
216
330
 
217
331
 
218
332
  def install_from_local_wheels(project_root: Path, requirements: Path) -> bool:
@@ -320,15 +434,18 @@ def check_maafw(project_root: Path) -> None:
320
434
  except importlib.metadata.PackageNotFoundError:
321
435
  warn(project_root, "Python package maafw is not installed")
322
436
  return
437
+ if not version:
438
+ warn(project_root, "Python package maafw has invalid or incomplete metadata")
439
+ return
323
440
  log(project_root, "maafw " + version)
324
441
 
325
442
 
326
443
  def is_package_installed(name: str) -> bool:
327
444
  try:
328
- importlib.metadata.version(name)
445
+ version = importlib.metadata.version(name)
329
446
  except importlib.metadata.PackageNotFoundError:
330
447
  return False
331
- return True
448
+ return bool(version)
332
449
 
333
450
 
334
451
  def command_output(error: subprocess.CalledProcessError) -> str:
@@ -2465,6 +2465,12 @@ jobs:
2465
2465
  expect(await pathExists(join(projectRoot, 'dist/package-mfaa/deps/maafw-0.0.0-py3-none-any.whl'))).toBe(true)
2466
2466
  } else {
2467
2467
  expect(await pathExists(join(projectRoot, 'dist/package-mfaa', expectedChildExec))).toBe(true)
2468
+ const packagedRequirements = await readFile(join(projectRoot, 'dist/package-mfaa/requirements.txt'))
2469
+ const packagedMarker = await readFile(
2470
+ join(projectRoot, 'dist/package-mfaa/python/.create-maa-project-requirements.sha256'),
2471
+ 'utf8',
2472
+ )
2473
+ expect(packagedMarker).toBe(`${sha256(packagedRequirements)}\n`)
2468
2474
  }
2469
2475
  if (!runtimePlatform.startsWith('win-') && process.platform !== 'win32') {
2470
2476
  expect(
@@ -0,0 +1,153 @@
1
+ from __future__ import annotations
2
+
3
+ import importlib.util
4
+ import multiprocessing
5
+ import tempfile
6
+ import time
7
+ import unittest
8
+ from contextlib import nullcontext
9
+ from pathlib import Path
10
+ from unittest.mock import patch
11
+
12
+
13
+ BOOTSTRAP_PATH = Path(__file__).resolve().parents[1] / "templates" / "agent" / "agent" / "bootstrap.py"
14
+ SPEC = importlib.util.spec_from_file_location("agent_bootstrap_template", BOOTSTRAP_PATH)
15
+ if SPEC is None or SPEC.loader is None:
16
+ raise RuntimeError("unable to load Agent bootstrap template")
17
+ agent_bootstrap = importlib.util.module_from_spec(SPEC)
18
+ SPEC.loader.exec_module(agent_bootstrap)
19
+
20
+
21
+ def acquire_requirements_lock_and_touch(project_root: str, touched_path: str) -> None:
22
+ with agent_bootstrap.requirements_install_lock(Path(project_root), timeout_seconds=5.0):
23
+ Path(touched_path).write_text("acquired\n", encoding="utf8")
24
+
25
+
26
+ class AgentBootstrapRequirementsTest(unittest.TestCase):
27
+ def test_external_maafw_without_marker_does_not_skip_requirements(self) -> None:
28
+ with tempfile.TemporaryDirectory() as temp_dir:
29
+ project_root = Path(temp_dir)
30
+ with patch.object(agent_bootstrap, "is_package_installed", return_value=True):
31
+ with patch.object(agent_bootstrap, "is_running_in_project_venv", return_value=False):
32
+ self.assertTrue(agent_bootstrap.needs_requirement_install(project_root, "digest"))
33
+
34
+ def test_matching_marker_skips_reinstall_when_maafw_is_available(self) -> None:
35
+ with tempfile.TemporaryDirectory() as temp_dir:
36
+ project_root = Path(temp_dir)
37
+ marker = project_root / "debug" / agent_bootstrap.REQUIREMENTS_MARKER
38
+ marker.parent.mkdir()
39
+ marker.write_text("digest\n", encoding="utf8")
40
+
41
+ with patch.object(agent_bootstrap, "is_package_installed", return_value=True):
42
+ with patch.object(agent_bootstrap, "is_running_in_project_venv", return_value=False):
43
+ self.assertFalse(agent_bootstrap.needs_requirement_install(project_root, "digest"))
44
+
45
+ def test_system_python_bin_is_not_treated_as_embedded(self) -> None:
46
+ with tempfile.TemporaryDirectory() as temp_dir:
47
+ project_root = Path(temp_dir)
48
+ with patch.object(agent_bootstrap.sys, "executable", "/usr/bin/python3"):
49
+ self.assertFalse(agent_bootstrap.is_running_in_embedded_python(project_root))
50
+
51
+ def test_macos_packaged_python_path_is_treated_as_embedded(self) -> None:
52
+ with tempfile.TemporaryDirectory() as temp_dir:
53
+ project_root = Path(temp_dir)
54
+ embedded_python = project_root / "python" / "bin" / "python3"
55
+ with patch.object(agent_bootstrap.sys, "executable", str(embedded_python)):
56
+ self.assertTrue(agent_bootstrap.is_running_in_embedded_python(project_root))
57
+
58
+ def test_project_venv_marker_takes_priority_over_embedded_runtime(self) -> None:
59
+ with tempfile.TemporaryDirectory() as temp_dir:
60
+ project_root = Path(temp_dir)
61
+ with patch.object(agent_bootstrap, "is_running_in_project_venv", return_value=True):
62
+ with patch.object(agent_bootstrap, "is_running_in_embedded_python", return_value=True):
63
+ marker = agent_bootstrap.requirements_marker(project_root)
64
+
65
+ self.assertEqual(marker, project_root / ".venv" / agent_bootstrap.REQUIREMENTS_MARKER)
66
+
67
+ def test_waiting_installer_rechecks_marker_after_acquiring_lock(self) -> None:
68
+ with tempfile.TemporaryDirectory() as temp_dir:
69
+ project_root = Path(temp_dir)
70
+ requirements = project_root / "requirements.txt"
71
+ requirements.write_text("maafw==1.0.0\n", encoding="utf8")
72
+
73
+ with patch.object(agent_bootstrap, "requirements_install_lock", return_value=nullcontext()):
74
+ with patch.object(agent_bootstrap, "needs_requirement_install", return_value=False):
75
+ with patch.object(agent_bootstrap, "install_from_local_wheels") as install_local:
76
+ with patch.object(agent_bootstrap, "install_from_indexes") as install_indexes:
77
+ agent_bootstrap.ensure_requirements_installed(project_root, requirements, "digest")
78
+
79
+ install_local.assert_not_called()
80
+ install_indexes.assert_not_called()
81
+
82
+ def test_requirements_lock_retries_and_releases(self) -> None:
83
+ with tempfile.TemporaryDirectory() as temp_dir:
84
+ project_root = Path(temp_dir)
85
+
86
+ with patch.object(agent_bootstrap, "try_lock_file", side_effect=[False, True]):
87
+ with patch.object(agent_bootstrap, "unlock_file") as unlock:
88
+ with patch.object(agent_bootstrap.time, "monotonic", side_effect=[0.0, 0.0]):
89
+ with patch.object(agent_bootstrap.time, "sleep") as sleep:
90
+ with agent_bootstrap.requirements_install_lock(project_root, timeout_seconds=1.0):
91
+ pass
92
+
93
+ sleep.assert_called_once_with(0.1)
94
+ unlock.assert_called_once()
95
+
96
+ def test_requirements_lock_timeout_stops_bootstrap(self) -> None:
97
+ with tempfile.TemporaryDirectory() as temp_dir:
98
+ project_root = Path(temp_dir)
99
+
100
+ with patch.object(agent_bootstrap, "try_lock_file", return_value=False):
101
+ with patch.object(agent_bootstrap.time, "monotonic", side_effect=[0.0, 2.0]):
102
+ with patch.object(agent_bootstrap, "warn") as warn:
103
+ with self.assertRaises(SystemExit):
104
+ with agent_bootstrap.requirements_install_lock(project_root, timeout_seconds=1.0):
105
+ pass
106
+
107
+ warn.assert_called_once()
108
+
109
+ def test_requirements_lock_serializes_processes(self) -> None:
110
+ with tempfile.TemporaryDirectory() as temp_dir:
111
+ project_root = Path(temp_dir)
112
+ touched_path = project_root / "second-process-acquired"
113
+ process = multiprocessing.get_context("spawn").Process(
114
+ target=acquire_requirements_lock_and_touch,
115
+ args=(str(project_root), str(touched_path)),
116
+ )
117
+
118
+ with agent_bootstrap.requirements_install_lock(project_root, timeout_seconds=5.0):
119
+ process.start()
120
+ time.sleep(0.3)
121
+ self.assertFalse(touched_path.exists())
122
+
123
+ process.join(timeout=5.0)
124
+ self.assertEqual(process.exitcode, 0)
125
+ self.assertTrue(touched_path.exists())
126
+
127
+ def test_requirements_marker_is_written_atomically(self) -> None:
128
+ with tempfile.TemporaryDirectory() as temp_dir:
129
+ project_root = Path(temp_dir)
130
+ with patch.object(agent_bootstrap, "is_running_in_project_venv", return_value=False):
131
+ with patch.object(agent_bootstrap, "is_running_in_embedded_python", return_value=False):
132
+ agent_bootstrap.write_requirements_marker(project_root, "digest")
133
+
134
+ marker = project_root / "debug" / agent_bootstrap.REQUIREMENTS_MARKER
135
+ self.assertEqual(marker.read_text(encoding="utf8"), "digest\n")
136
+ self.assertFalse(marker.with_name(marker.name + ".tmp").exists())
137
+
138
+ def test_empty_package_version_is_not_installed(self) -> None:
139
+ with patch.object(agent_bootstrap.importlib.metadata, "version", return_value=None):
140
+ self.assertFalse(agent_bootstrap.is_package_installed("maafw"))
141
+
142
+ def test_empty_maafw_version_reports_invalid_metadata(self) -> None:
143
+ with tempfile.TemporaryDirectory() as temp_dir:
144
+ project_root = Path(temp_dir)
145
+ with patch.object(agent_bootstrap.importlib.metadata, "version", return_value=None):
146
+ with patch.object(agent_bootstrap, "warn") as warn:
147
+ agent_bootstrap.check_maafw(project_root)
148
+
149
+ warn.assert_called_once_with(project_root, "Python package maafw has invalid or incomplete metadata")
150
+
151
+
152
+ if __name__ == "__main__":
153
+ unittest.main()
@@ -1 +0,0 @@
1
- __version__ = "1.2.2"
@@ -1,2 +0,0 @@
1
- # Filled by the release workflow when publishing the PyPI wrapper.
2
- RELEASE_MANIFEST_SHA256 = "5c42a0a01b4e2c34e18d8e8adba50bb541ecff5529a84d298b869e29e4864b41"
@@ -1,39 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import importlib.util
4
- import tempfile
5
- import unittest
6
- from pathlib import Path
7
- from unittest.mock import patch
8
-
9
-
10
- BOOTSTRAP_PATH = Path(__file__).resolve().parents[1] / "templates" / "agent" / "agent" / "bootstrap.py"
11
- SPEC = importlib.util.spec_from_file_location("agent_bootstrap_template", BOOTSTRAP_PATH)
12
- if SPEC is None or SPEC.loader is None:
13
- raise RuntimeError("unable to load Agent bootstrap template")
14
- agent_bootstrap = importlib.util.module_from_spec(SPEC)
15
- SPEC.loader.exec_module(agent_bootstrap)
16
-
17
-
18
- class AgentBootstrapRequirementsTest(unittest.TestCase):
19
- def test_external_maafw_without_marker_does_not_skip_requirements(self) -> None:
20
- with tempfile.TemporaryDirectory() as temp_dir:
21
- project_root = Path(temp_dir)
22
- with patch.object(agent_bootstrap, "is_package_installed", return_value=True):
23
- with patch.object(agent_bootstrap, "is_running_in_project_venv", return_value=False):
24
- self.assertTrue(agent_bootstrap.needs_requirement_install(project_root, "digest"))
25
-
26
- def test_matching_marker_skips_reinstall_when_maafw_is_available(self) -> None:
27
- with tempfile.TemporaryDirectory() as temp_dir:
28
- project_root = Path(temp_dir)
29
- marker = project_root / "debug" / agent_bootstrap.REQUIREMENTS_MARKER
30
- marker.parent.mkdir()
31
- marker.write_text("digest\n", encoding="utf8")
32
-
33
- with patch.object(agent_bootstrap, "is_package_installed", return_value=True):
34
- with patch.object(agent_bootstrap, "is_running_in_project_venv", return_value=False):
35
- self.assertFalse(agent_bootstrap.needs_requirement_install(project_root, "digest"))
36
-
37
-
38
- if __name__ == "__main__":
39
- unittest.main()