@lesliechan721/aw 0.1.0-beta.63 → 0.1.0-beta.65

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 (302) hide show
  1. package/dist/authoring/assets/aw-runtime-config.mjs +3 -3
  2. package/dist/authoring/assets/aw-runtime-config.mjs.map +1 -1
  3. package/dist/authoring/scripts/add-skill.mjs +3 -17
  4. package/dist/authoring/scripts/add-skill.mjs.map +1 -1
  5. package/dist/authoring/scripts/init-plugin.mjs +1 -0
  6. package/dist/authoring/scripts/init-plugin.mjs.map +1 -1
  7. package/dist/authoring/scripts/lib/plugin-version-check.mjs +1 -1
  8. package/dist/authoring/scripts/lib/skill-scaffold.d.mts +2 -0
  9. package/dist/authoring/scripts/lib/skill-scaffold.mjs +2 -0
  10. package/dist/authoring/scripts/lib/skill-scaffold.mjs.map +1 -1
  11. package/dist/authoring/scripts/validate-plugin.mjs +95 -698
  12. package/dist/authoring/scripts/validate-plugin.mjs.map +1 -1
  13. package/dist/scripts/aw-skill-eval-materializer.d.ts +2 -0
  14. package/dist/scripts/aw-skill-eval-materializer.js +74 -44
  15. package/dist/scripts/aw-skill-eval-materializer.js.map +1 -1
  16. package/dist/scripts/bundle-plugins.js +10 -2
  17. package/dist/scripts/bundle-plugins.js.map +1 -1
  18. package/dist/scripts/plugin-staging.d.ts +1 -1
  19. package/dist/scripts/plugin-staging.js +1 -1
  20. package/dist/scripts/plugin-staging.js.map +1 -1
  21. package/dist/scripts/test-plugin-scripts.js +31 -31
  22. package/dist/scripts/test-plugin-scripts.js.map +1 -1
  23. package/dist/src/commands/aw-capabilities.d.ts +1 -1
  24. package/dist/src/commands/aw-capabilities.js +2 -0
  25. package/dist/src/commands/aw-capabilities.js.map +1 -1
  26. package/dist/src/commands/console.js +4 -3
  27. package/dist/src/commands/console.js.map +1 -1
  28. package/dist/src/commands/intent-command.d.ts +30 -0
  29. package/dist/src/commands/intent-command.js +164 -0
  30. package/dist/src/commands/intent-command.js.map +1 -0
  31. package/dist/src/commands/operation-plan.d.ts +2 -0
  32. package/dist/src/commands/operation-plan.js +2 -1
  33. package/dist/src/commands/operation-plan.js.map +1 -1
  34. package/dist/src/commands/options.d.ts +3 -11
  35. package/dist/src/commands/options.js +11 -17
  36. package/dist/src/commands/options.js.map +1 -1
  37. package/dist/src/commands/plugin-capabilities.js +27 -33
  38. package/dist/src/commands/plugin-capabilities.js.map +1 -1
  39. package/dist/src/commands/rebuild-command.d.ts +108 -6
  40. package/dist/src/commands/rebuild-command.js +617 -1549
  41. package/dist/src/commands/rebuild-command.js.map +1 -1
  42. package/dist/src/commands/rebuild-integration.d.ts +19 -3
  43. package/dist/src/commands/rebuild-integration.js +500 -459
  44. package/dist/src/commands/rebuild-integration.js.map +1 -1
  45. package/dist/src/commands/rebuild-operations.js +1 -2
  46. package/dist/src/commands/rebuild-operations.js.map +1 -1
  47. package/dist/src/commands/review-inspection.d.ts +2 -2
  48. package/dist/src/commands/review-inspection.js +30 -86
  49. package/dist/src/commands/review-inspection.js.map +1 -1
  50. package/dist/src/commands/review-preparation.js +16 -7
  51. package/dist/src/commands/review-preparation.js.map +1 -1
  52. package/dist/src/commands/skill-eval.d.ts +2 -0
  53. package/dist/src/commands/skill-eval.js +15 -9
  54. package/dist/src/commands/skill-eval.js.map +1 -1
  55. package/dist/src/commands/status-v6.d.ts +38 -5
  56. package/dist/src/commands/status-v6.js +269 -102
  57. package/dist/src/commands/status-v6.js.map +1 -1
  58. package/dist/src/commands/targets-command.d.ts +27 -0
  59. package/dist/src/commands/targets-command.js +77 -0
  60. package/dist/src/commands/targets-command.js.map +1 -0
  61. package/dist/src/commands/write-commands.js +5 -5
  62. package/dist/src/commands/write-commands.js.map +1 -1
  63. package/dist/src/eval/manifest-v1.d.ts +2 -0
  64. package/dist/src/eval/manifest-v1.js +7 -2
  65. package/dist/src/eval/manifest-v1.js.map +1 -1
  66. package/dist/src/generators/local-plugin.d.ts +2 -1
  67. package/dist/src/generators/local-plugin.js +111 -108
  68. package/dist/src/generators/local-plugin.js.map +1 -1
  69. package/dist/src/index.d.ts +10 -17
  70. package/dist/src/index.js +585 -1349
  71. package/dist/src/index.js.map +1 -1
  72. package/dist/src/intent/deployment-preferences.d.ts +63 -0
  73. package/dist/src/intent/deployment-preferences.js +170 -0
  74. package/dist/src/intent/deployment-preferences.js.map +1 -0
  75. package/dist/src/intent/diagnostics.d.ts +11 -0
  76. package/dist/src/intent/diagnostics.js +14 -0
  77. package/dist/src/intent/diagnostics.js.map +1 -0
  78. package/dist/src/intent/intent-codec.d.ts +19 -0
  79. package/dist/src/intent/intent-codec.js +117 -0
  80. package/dist/src/intent/intent-codec.js.map +1 -0
  81. package/dist/src/intent/intent-store.d.ts +43 -0
  82. package/dist/src/intent/intent-store.js +118 -0
  83. package/dist/src/intent/intent-store.js.map +1 -0
  84. package/dist/src/intent/scope-context.d.ts +33 -0
  85. package/dist/src/intent/scope-context.js +145 -0
  86. package/dist/src/intent/scope-context.js.map +1 -0
  87. package/dist/src/intent/work-context.d.ts +13 -0
  88. package/dist/src/intent/work-context.js +22 -0
  89. package/dist/src/intent/work-context.js.map +1 -0
  90. package/dist/src/output/command-receipt.js +16 -9
  91. package/dist/src/output/command-receipt.js.map +1 -1
  92. package/dist/src/portable/commands.d.ts +18 -8
  93. package/dist/src/portable/commands.js +46 -562
  94. package/dist/src/portable/commands.js.map +1 -1
  95. package/dist/src/portable/historical-materialization.d.ts +22 -0
  96. package/dist/src/portable/historical-materialization.js +124 -0
  97. package/dist/src/portable/historical-materialization.js.map +1 -0
  98. package/dist/src/portable/materializer.d.ts +8 -0
  99. package/dist/src/portable/materializer.js +75 -44
  100. package/dist/src/portable/materializer.js.map +1 -1
  101. package/dist/src/portable/recovery-layout.d.ts +17 -0
  102. package/dist/src/portable/recovery-layout.js +55 -0
  103. package/dist/src/portable/recovery-layout.js.map +1 -0
  104. package/dist/src/portable/recovery.d.ts +143 -0
  105. package/dist/src/portable/recovery.js +339 -0
  106. package/dist/src/portable/recovery.js.map +1 -0
  107. package/dist/src/portable/writer.d.ts +64 -0
  108. package/dist/src/portable/writer.js +316 -0
  109. package/dist/src/portable/writer.js.map +1 -0
  110. package/dist/src/recovery/coordinator.d.ts +137 -0
  111. package/dist/src/recovery/coordinator.js +1198 -0
  112. package/dist/src/recovery/coordinator.js.map +1 -0
  113. package/dist/src/recovery/demand.d.ts +44 -0
  114. package/dist/src/recovery/demand.js +178 -0
  115. package/dist/src/recovery/demand.js.map +1 -0
  116. package/dist/src/recovery/joint-coordinator.d.ts +24 -0
  117. package/dist/src/recovery/joint-coordinator.js +770 -0
  118. package/dist/src/recovery/joint-coordinator.js.map +1 -0
  119. package/dist/src/recovery/joint-demand.d.ts +68 -0
  120. package/dist/src/recovery/joint-demand.js +166 -0
  121. package/dist/src/recovery/joint-demand.js.map +1 -0
  122. package/dist/src/recovery/receipt.d.ts +81 -0
  123. package/dist/src/recovery/receipt.js +2 -0
  124. package/dist/src/recovery/receipt.js.map +1 -0
  125. package/dist/src/recovery/retirement.d.ts +45 -0
  126. package/dist/src/recovery/retirement.js +366 -0
  127. package/dist/src/recovery/retirement.js.map +1 -0
  128. package/dist/src/recovery/status.d.ts +108 -0
  129. package/dist/src/recovery/status.js +417 -0
  130. package/dist/src/recovery/status.js.map +1 -0
  131. package/dist/src/recovery/types.d.ts +86 -0
  132. package/dist/src/recovery/types.js +2 -0
  133. package/dist/src/recovery/types.js.map +1 -0
  134. package/dist/src/review/review-profile.d.ts +2 -1
  135. package/dist/src/review/review-profile.js +15 -15
  136. package/dist/src/review/review-profile.js.map +1 -1
  137. package/dist/src/review/review-selection.d.ts +1 -2
  138. package/dist/src/review/review-selection.js +40 -114
  139. package/dist/src/review/review-selection.js.map +1 -1
  140. package/dist/src/review/review-types.d.ts +4 -4
  141. package/dist/src/review/review-types.js.map +1 -1
  142. package/dist/src/review/skill-materialization.js +15 -6
  143. package/dist/src/review/skill-materialization.js.map +1 -1
  144. package/dist/src/review/source-binding.d.ts +14 -4
  145. package/dist/src/review/source-binding.js +62 -117
  146. package/dist/src/review/source-binding.js.map +1 -1
  147. package/dist/src/tui/agent-management.d.ts +23 -0
  148. package/dist/src/tui/agent-management.js +217 -0
  149. package/dist/src/tui/agent-management.js.map +1 -0
  150. package/dist/src/tui/agent-settings.d.ts +44 -0
  151. package/dist/src/tui/agent-settings.js +98 -0
  152. package/dist/src/tui/agent-settings.js.map +1 -0
  153. package/dist/src/tui/components.d.ts +3 -0
  154. package/dist/src/tui/components.js +10 -1
  155. package/dist/src/tui/components.js.map +1 -1
  156. package/dist/src/tui/config-references.d.ts +6 -3
  157. package/dist/src/tui/config-references.js +17 -12
  158. package/dist/src/tui/config-references.js.map +1 -1
  159. package/dist/src/tui/console-app-v4.d.ts +1 -2
  160. package/dist/src/tui/console-app-v4.js +1533 -1047
  161. package/dist/src/tui/console-app-v4.js.map +1 -1
  162. package/dist/src/tui/controller-runtime.d.ts +2 -1
  163. package/dist/src/tui/controller-runtime.js +457 -1634
  164. package/dist/src/tui/controller-runtime.js.map +1 -1
  165. package/dist/src/tui/controller.d.ts +131 -81
  166. package/dist/src/tui/controller.js +307 -227
  167. package/dist/src/tui/controller.js.map +1 -1
  168. package/dist/src/tui/entity-cards.d.ts +2 -2
  169. package/dist/src/tui/entity-cards.js +98 -20
  170. package/dist/src/tui/entity-cards.js.map +1 -1
  171. package/dist/src/tui/glossary.d.ts +2 -0
  172. package/dist/src/tui/glossary.js +20 -0
  173. package/dist/src/tui/glossary.js.map +1 -1
  174. package/dist/src/tui/model.d.ts +28 -10
  175. package/dist/src/tui/model.js +41 -41
  176. package/dist/src/tui/model.js.map +1 -1
  177. package/dist/src/tui/operation-review-planner.d.ts +2 -0
  178. package/dist/src/tui/operation-review-planner.js +58 -122
  179. package/dist/src/tui/operation-review-planner.js.map +1 -1
  180. package/dist/src/tui/plugin-content.js +7 -4
  181. package/dist/src/tui/plugin-content.js.map +1 -1
  182. package/dist/src/tui/plugin-detail.d.ts +22 -3
  183. package/dist/src/tui/plugin-detail.js +113 -26
  184. package/dist/src/tui/plugin-detail.js.map +1 -1
  185. package/dist/src/tui/reader.d.ts +1 -0
  186. package/dist/src/tui/reader.js +3 -1
  187. package/dist/src/tui/reader.js.map +1 -1
  188. package/dist/src/tui/router.d.ts +23 -33
  189. package/dist/src/tui/router.js.map +1 -1
  190. package/dist/src/tui/scoped-flow.d.ts +45 -0
  191. package/dist/src/tui/scoped-flow.js +96 -0
  192. package/dist/src/tui/scoped-flow.js.map +1 -0
  193. package/dist/src/tui/scoped-inventory.d.ts +122 -0
  194. package/dist/src/tui/scoped-inventory.js +225 -0
  195. package/dist/src/tui/scoped-inventory.js.map +1 -0
  196. package/dist/src/tui/screen-registry.d.ts +25 -25
  197. package/dist/src/tui/screen-registry.js +3 -7
  198. package/dist/src/tui/screen-registry.js.map +1 -1
  199. package/dist/src/tui/session-console-app.js +1 -1
  200. package/dist/src/tui/session-console-app.js.map +1 -1
  201. package/dist/src/tui/session-host.js +12 -2
  202. package/dist/src/tui/session-host.js.map +1 -1
  203. package/dist/src/types.d.ts +15 -12
  204. package/dist/src/types.js.map +1 -1
  205. package/dist/src/utils/agent-version.js +2 -0
  206. package/dist/src/utils/agent-version.js.map +1 -1
  207. package/dist/src/utils/artifact-plan.js +13 -6
  208. package/dist/src/utils/artifact-plan.js.map +1 -1
  209. package/dist/src/utils/artifact-renderer.d.ts +6 -3
  210. package/dist/src/utils/artifact-renderer.js +27 -32
  211. package/dist/src/utils/artifact-renderer.js.map +1 -1
  212. package/dist/src/utils/artifact-request.d.ts +1 -0
  213. package/dist/src/utils/artifact-request.js +22 -12
  214. package/dist/src/utils/artifact-request.js.map +1 -1
  215. package/dist/src/utils/artifact-sources.d.ts +2 -2
  216. package/dist/src/utils/bundle-layout.js +18 -16
  217. package/dist/src/utils/bundle-layout.js.map +1 -1
  218. package/dist/src/utils/catalog-digests.js +2 -0
  219. package/dist/src/utils/catalog-digests.js.map +1 -1
  220. package/dist/src/utils/catalog-runtime-projection.d.ts +4 -3
  221. package/dist/src/utils/catalog-runtime-projection.js.map +1 -1
  222. package/dist/src/utils/catalog-source-references.d.ts +5 -0
  223. package/dist/src/utils/catalog-source-references.js +42 -57
  224. package/dist/src/utils/catalog-source-references.js.map +1 -1
  225. package/dist/src/utils/claude-native-render-receipt.d.ts +14 -0
  226. package/dist/src/utils/claude-native-render-receipt.js +26 -0
  227. package/dist/src/utils/claude-native-render-receipt.js.map +1 -0
  228. package/dist/src/utils/claude-skills-root.js +14 -3
  229. package/dist/src/utils/claude-skills-root.js.map +1 -1
  230. package/dist/src/utils/codex-manager.js +6 -12
  231. package/dist/src/utils/codex-manager.js.map +1 -1
  232. package/dist/src/utils/codex-native-observation.js +29 -13
  233. package/dist/src/utils/codex-native-observation.js.map +1 -1
  234. package/dist/src/utils/codex-reconciler.d.ts +2 -5
  235. package/dist/src/utils/codex-reconciler.js +25 -1
  236. package/dist/src/utils/codex-reconciler.js.map +1 -1
  237. package/dist/src/utils/codex-surface-analysis.js +5 -3
  238. package/dist/src/utils/codex-surface-analysis.js.map +1 -1
  239. package/dist/src/utils/local-marketplace.d.ts +14 -2
  240. package/dist/src/utils/local-marketplace.js +209 -42
  241. package/dist/src/utils/local-marketplace.js.map +1 -1
  242. package/dist/src/utils/managed-command-evidence.js +1 -1
  243. package/dist/src/utils/managed-command-evidence.js.map +1 -1
  244. package/dist/src/utils/managed-command-materialization.d.ts +4 -0
  245. package/dist/src/utils/managed-command-materialization.js +15 -6
  246. package/dist/src/utils/managed-command-materialization.js.map +1 -1
  247. package/dist/src/utils/managed-command-store.d.ts +15 -0
  248. package/dist/src/utils/managed-command-store.js +73 -8
  249. package/dist/src/utils/managed-command-store.js.map +1 -1
  250. package/dist/src/utils/native-cli.d.ts +2 -0
  251. package/dist/src/utils/native-cli.js +22 -0
  252. package/dist/src/utils/native-cli.js.map +1 -1
  253. package/dist/src/utils/native-demand.d.ts +10 -0
  254. package/dist/src/utils/native-demand.js +4 -0
  255. package/dist/src/utils/native-demand.js.map +1 -0
  256. package/dist/src/utils/ownership.js +2 -0
  257. package/dist/src/utils/ownership.js.map +1 -1
  258. package/dist/src/utils/paths.js +1 -1
  259. package/dist/src/utils/paths.js.map +1 -1
  260. package/dist/src/utils/platform-support.d.ts +1 -1
  261. package/dist/src/utils/platform-support.js +1 -1
  262. package/dist/src/utils/platform-support.js.map +1 -1
  263. package/dist/src/utils/plugin-config-impact.d.ts +3 -0
  264. package/dist/src/utils/plugin-config-impact.js +115 -273
  265. package/dist/src/utils/plugin-config-impact.js.map +1 -1
  266. package/dist/src/utils/plugin-config-references.d.ts +11 -2
  267. package/dist/src/utils/plugin-config-references.js +85 -90
  268. package/dist/src/utils/plugin-config-references.js.map +1 -1
  269. package/dist/src/utils/plugin-config-write.d.ts +58 -1
  270. package/dist/src/utils/plugin-config-write.js +756 -809
  271. package/dist/src/utils/plugin-config-write.js.map +1 -1
  272. package/dist/src/utils/plugin-config.d.ts +47 -46
  273. package/dist/src/utils/plugin-config.js +292 -833
  274. package/dist/src/utils/plugin-config.js.map +1 -1
  275. package/dist/src/utils/plugin-scripts.d.ts +11 -6
  276. package/dist/src/utils/plugin-scripts.js +52 -35
  277. package/dist/src/utils/plugin-scripts.js.map +1 -1
  278. package/dist/src/utils/runtime-config.js +5 -4
  279. package/dist/src/utils/runtime-config.js.map +1 -1
  280. package/dist/src/utils/runtime-skill-closure.d.ts +2 -2
  281. package/dist/src/utils/runtime-skill-closure.js.map +1 -1
  282. package/dist/src/utils/state-paths.d.ts +8 -3
  283. package/dist/src/utils/state-paths.js +53 -16
  284. package/dist/src/utils/state-paths.js.map +1 -1
  285. package/dist/src/utils/windows-npm-shim.d.ts +2 -0
  286. package/dist/src/utils/windows-npm-shim.js +5 -7
  287. package/dist/src/utils/windows-npm-shim.js.map +1 -1
  288. package/dist/vitest.config.js +1 -0
  289. package/dist/vitest.config.js.map +1 -1
  290. package/package.json +3 -3
  291. package/dist/src/commands/sync-command.d.ts +0 -40
  292. package/dist/src/commands/sync-command.js +0 -254
  293. package/dist/src/commands/sync-command.js.map +0 -1
  294. package/dist/src/portable/skills-cli.d.ts +0 -51
  295. package/dist/src/portable/skills-cli.js +0 -202
  296. package/dist/src/portable/skills-cli.js.map +0 -1
  297. package/dist/src/tui/project-inventory.d.ts +0 -68
  298. package/dist/src/tui/project-inventory.js +0 -203
  299. package/dist/src/tui/project-inventory.js.map +0 -1
  300. package/dist/src/utils/plugin-intent-state.d.ts +0 -49
  301. package/dist/src/utils/plugin-intent-state.js +0 -320
  302. package/dist/src/utils/plugin-intent-state.js.map +0 -1
@@ -2,17 +2,16 @@ import crypto from 'node:crypto';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import fs from 'fs-extra';
5
- import { withAwHomeMutationLock } from '../utils/aw-home-mutation-lock.js';
6
- import { resolveCatalogOperationContext, } from '../utils/catalog-operation-context.js';
5
+ import { isPortablePlatformTarget } from '@lesliechan721/aw-plugin-core';
6
+ import { resolveCatalogOperationContext } from '../utils/catalog-operation-context.js';
7
7
  import { readCatalogSourcesConfigSnapshot } from '../utils/catalog-sources.js';
8
8
  import { parsePluginId } from '../utils/multi-source-catalog.js';
9
9
  import { resolveAwProjectRoot } from '../utils/plugin-config.js';
10
10
  import { getClaudeHome, getCodexHome, resolveAwHome } from '../utils/paths.js';
11
- import { canonicalizePathThroughExistingAncestor, ensureRegularDirectoryPath, } from '../utils/state-paths.js';
12
- import { materializePortableSkillsFromCatalog, resolvePortableCatalogBindingInput, } from './materializer.js';
11
+ import { canonicalizePathThroughExistingAncestor, ensureRegularDirectoryPath } from '../utils/state-paths.js';
12
+ import { assertPortablePlatform, materializePortableSkillsFromCatalog, resolvePortableCatalogBindingInput } from './materializer.js';
13
13
  import { AW_SOURCE_BINDING_FILENAME, writeAwSourceBinding } from '../review/source-binding.js';
14
- import { addSkills, listInstalledSkills, probeSkillsCli, SkillsCliError, verifySkills, verifySkillTargets, } from './skills-cli.js';
15
- export { SKILLS_CLI_SUPPORTED_VERSION_LABEL, } from './skills-cli.js';
14
+ export const SKILLS_CLI_SUPPORTED_VERSION_LABEL = 'AW Portable writer';
16
15
  export class PortableCommandError extends Error {
17
16
  code;
18
17
  constructor(code, message) {
@@ -28,40 +27,21 @@ export function setPortableCommandTestHooksForTests(hooks) {
28
27
  function digest(value) {
29
28
  return `sha256:${crypto.createHash('sha256').update(JSON.stringify(value)).digest('hex')}`;
30
29
  }
31
- function toPublicInstalledRecord(record) {
32
- return {
33
- name: record.name,
34
- ...(record.scope !== undefined ? { scope: record.scope } : {}),
35
- agents: [...record.agents],
36
- };
37
- }
38
- function publicInstalledRecords(records) {
39
- return records.map(toPublicInstalledRecord);
40
- }
41
30
  function assertScope(scope) {
42
- if (scope !== 'project' && scope !== 'user') {
31
+ if (scope !== 'project' && scope !== 'user')
43
32
  throw new Error('scope 必须是 project 或 user。');
44
- }
45
33
  }
46
34
  export function normalizePortableAgents(values) {
47
35
  if (values === undefined)
48
36
  return undefined;
49
- if (values.length === 0 || values.length > 32) {
50
- throw new PortableCommandError('portableInvalidAgentSelection', 'Agent 选择必须包含 1 到 32 项。');
51
- }
52
- const result = [];
53
- const seen = new Set();
54
- for (const raw of values) {
55
- const value = raw.trim();
56
- if (!value || value.length > 128 || value.startsWith('-') || /[\s\p{Cc}]/u.test(value)) {
57
- throw new PortableCommandError('portableInvalidAgentSelection', `无效 Agent ID:${JSON.stringify(raw)}。`);
58
- }
59
- if (!seen.has(value)) {
60
- seen.add(value);
61
- result.push(value);
62
- }
37
+ if (values.length === 0 || new Set(values).size !== values.length
38
+ || values.some((value) => !isPortablePlatformTarget(value))) {
39
+ throw new PortableCommandError('portableInvalidAgentSelection', '请选择有效的 Portable 平台。');
63
40
  }
64
- return result;
41
+ return [...values];
42
+ }
43
+ function removedPortableWorkflow() {
44
+ throw new PortableCommandError('portableUnsupported', '此旧安装流程已移除。请设置本机 targets,再使用统一 install 或 sync。');
65
45
  }
66
46
  function selectCandidates(candidates, requested) {
67
47
  if (candidates.length === 0) {
@@ -81,530 +61,23 @@ function selectCandidates(candidates, requested) {
81
61
  }
82
62
  return selected;
83
63
  }
84
- function classifyMaterializationError(error) {
85
- if (error instanceof PortableCommandError || error instanceof SkillsCliError)
86
- throw error;
87
- const message = error instanceof Error ? error.message : String(error);
88
- if (message.includes('does not declare distributions.agentSkills')) {
89
- throw new PortableCommandError('portableUnsupported', '插件不支持 Agent Skills distribution。');
90
- }
91
- if (message.includes('Portable materialization config is invalid')) {
92
- throw new PortableCommandError('requiredConfigMissing', '插件缺少生成内容所需的设置,或设置无效。');
93
- }
94
- if (message.includes('name collision')) {
95
- throw new PortableCommandError('portableSkillNameConflict', message);
96
- }
97
- if (message.includes('sensitive config') || message.includes('unresolved template')) {
98
- throw new PortableCommandError('portableSensitiveOutput', 'portable 输出包含敏感值或未解析模板。');
99
- }
100
- if (message.includes('runtime import')) {
101
- throw new PortableCommandError('portableRuntimeImportMissing', 'portable runtime import 缺失或无效。');
102
- }
103
- if (message.toLowerCase().includes('renderer')) {
104
- throw new PortableCommandError('portableRendererFailed', 'portable renderer 执行失败。');
105
- }
106
- if (message.includes('Skill') || message.includes('SKILL.md')) {
107
- throw new PortableCommandError('portableSkillInvalid', 'portable Skill 内容无效。');
108
- }
109
- throw error;
110
- }
111
- async function createMaterialization(options) {
112
- try {
113
- return await materializePortableSkillsFromCatalog({
114
- selector: options.selector,
115
- scope: options.scope,
116
- cwd: options.cwd,
117
- cliVersion: options.cliVersion,
118
- env: options.env,
119
- signal: options.signal,
120
- configSnapshot: options.configSnapshot,
121
- catalogOperationContext: options.catalogOperationContext,
122
- });
123
- }
124
- catch (error) {
125
- if (options.signal?.aborted)
126
- options.signal.throwIfAborted();
127
- classifyMaterializationError(error);
128
- }
64
+ export async function preparePortableInstall(_options) {
65
+ return removedPortableWorkflow();
129
66
  }
130
- async function collectEvidence(options) {
131
- const executionCwd = options.scope === 'project' ? resolveAwProjectRoot(options.cwd) : options.cwd;
132
- const configSnapshot = await readCatalogSourcesConfigSnapshot(options.env);
133
- const materialized = await createMaterialization({ ...options, configSnapshot });
134
- try {
135
- const skillsCli = await probeSkillsCli({ cwd: executionCwd, env: options.env, signal: options.signal });
136
- const selected = selectCandidates(materialized.candidates, options.requestedSkills);
137
- const installed = await listInstalledSkills({
138
- cwd: executionCwd,
139
- env: options.env,
140
- signal: options.signal,
141
- global: options.scope === 'user',
142
- });
143
- const names = new Set(selected.map((candidate) => candidate.name));
144
- const collisions = installed
145
- .filter((entry) => names.has(entry.name))
146
- .map((entry) => ({ ...toPublicInstalledRecord(entry), requestedName: entry.name }));
147
- const evidence = {
148
- pluginId: materialized.pluginId,
149
- sourceId: materialized.sourceId,
150
- sourceIdentity: materialized.sourceIdentity,
151
- pluginVersion: materialized.pluginVersion,
152
- scope: options.scope,
153
- selected,
154
- requestedSkills: options.requestedSkills,
155
- agentMode: options.agents ? 'explicit' : 'automatic',
156
- requestedAgents: options.agents ?? [],
157
- skillsCliVersion: skillsCli.version,
158
- collisions,
159
- dependencies: materialized.dependencyPluginIds,
160
- materializationDigest: materialized.digest,
161
- configDigest: digest({
162
- catalogSources: configSnapshot.digest,
163
- pluginConfig: materialized.configDigest,
164
- }),
165
- generationSetDigest: options.catalogOperationContext.generationSetDigest,
166
- };
167
- return {
168
- materialized,
169
- review: { ...evidence, evidenceDigest: digest(evidence) },
170
- };
171
- }
172
- catch (error) {
173
- await materialized.cleanup();
174
- throw error;
175
- }
67
+ export async function installPortableSkills(_options) {
68
+ return removedPortableWorkflow();
176
69
  }
177
- export async function preparePortableInstall(options) {
178
- const agents = normalizePortableAgents(options.requestedAgents);
179
- const catalogOperationContext = options.catalogOperationContext
180
- ?? await resolveCatalogOperationContext({
181
- ...(parsePluginId(options.selector).sourceId
182
- ? { sourceIds: [parsePluginId(options.selector).sourceId] }
183
- : {}),
184
- env: options.env,
185
- ...(options.signal ? { signal: options.signal } : {}),
186
- });
187
- const collected = await collectEvidence({ ...options, agents, catalogOperationContext });
188
- try {
189
- return structuredClone(collected.review);
190
- }
191
- finally {
192
- await collected.materialized.cleanup();
193
- }
70
+ export async function recheckPortableInstall(_options) {
71
+ return removedPortableWorkflow();
194
72
  }
195
- export function renderPortableReview(review) {
196
- return [
197
- `插件:${review.pluginId}${review.pluginVersion ? ` @ ${review.pluginVersion}` : ''}`,
198
- `范围:${review.scope}`,
199
- `Skill:${review.selected.map((entry) => `${entry.name}(${entry.providerPluginId})`).join(', ')}`,
200
- review.agentMode === 'automatic'
201
- ? 'Agent:自动选择检测到的 Agent;未检测到时可能选择全部 Agent'
202
- : `Agent:${review.requestedAgents.join(', ')}`,
203
- `依赖:${review.dependencies.length > 0 ? review.dependencies.join(', ') : '无'}`,
204
- `同名覆盖:${review.collisions.length > 0
205
- ? review.collisions.map((entry) => `${entry.name} [${entry.agents.join(', ') || 'unknown'}]`).join('; ')
206
- : '无'}`,
207
- ];
73
+ export async function preparePortableRetry(_options) {
74
+ return removedPortableWorkflow();
208
75
  }
209
- function installFailureReceipt(review, code, status, verification, attemptedTargets) {
210
- return {
211
- receiptSchemaVersion: 5,
212
- command: 'skill:install',
213
- ok: false,
214
- status,
215
- plugin: {
216
- id: review.pluginId,
217
- ...(review.sourceId ? { sourceId: review.sourceId } : {}),
218
- ...(review.sourceIdentity ? { sourceIdentity: review.sourceIdentity } : {}),
219
- ...(review.pluginVersion ? { version: review.pluginVersion } : {}),
220
- },
221
- scope: review.scope,
222
- selectedSkills: review.selected,
223
- ...(review.requestedSkills ? { requestedSkills: review.requestedSkills } : {}),
224
- agentMode: review.agentMode,
225
- requestedAgents: review.requestedAgents,
226
- skillsCliVersion: review.skillsCliVersion,
227
- collisions: review.collisions,
228
- dependencies: review.dependencies,
229
- materializationDigest: review.materializationDigest,
230
- verification: {
231
- ...verification,
232
- records: publicInstalledRecords(verification.records),
233
- },
234
- ...(attemptedTargets ? { attemptedTargets } : {}),
235
- warnings: [],
236
- failures: [{
237
- code,
238
- message: code === 'portableSkillsCliInstallFailed'
239
- ? 'skills add 执行失败,可能已写入部分目标。'
240
- : 'skills add 已完成,但安装验证缺少目标。',
241
- recovery: '修复问题后重新运行 aw skill install;也可使用 skills remove 清理外部安装。',
242
- }],
243
- };
76
+ export async function executePortableRetry(_options) {
77
+ return removedPortableWorkflow();
244
78
  }
245
- export async function installPortableSkills(options) {
246
- assertScope(options.scope);
247
- const scope = options.scope;
248
- const agents = normalizePortableAgents(options.requestedAgents);
249
- await options.onProgress?.('prepare');
250
- const parsedSelector = parsePluginId(options.selector);
251
- const initialCatalogOperation = await resolveCatalogOperationContext({
252
- ...(parsedSelector.sourceId ? { sourceIds: [parsedSelector.sourceId] } : {}),
253
- env: options.env,
254
- });
255
- if (options.expectedGenerationSetDigest
256
- && initialCatalogOperation.generationSetDigest !== options.expectedGenerationSetDigest) {
257
- throw new PortableCommandError('reviewStale', '确认后 Active Catalog generation 已变化。');
258
- }
259
- const initial = await collectEvidence({
260
- ...options,
261
- scope,
262
- agents,
263
- catalogOperationContext: initialCatalogOperation,
264
- });
265
- options.onReview?.(initial.review);
266
- try {
267
- if (!options.yes) {
268
- if (!options.confirm) {
269
- throw new PortableCommandError('confirmationRequired', '安装需要交互确认或 --yes。');
270
- }
271
- const confirmed = await options.confirm(initial.review);
272
- if (confirmed.cancelled || confirmed.value !== true) {
273
- throw new PortableCommandError('confirmationRequired', '用户未确认安装。');
274
- }
275
- }
276
- }
277
- finally {
278
- await initial.materialized.cleanup();
279
- }
280
- return withAwHomeMutationLock({
281
- env: options.env,
282
- action: async () => {
283
- let current;
284
- try {
285
- const currentCatalogOperation = await resolveCatalogOperationContext({
286
- ...(parsedSelector.sourceId ? { sourceIds: [parsedSelector.sourceId] } : {}),
287
- env: options.env,
288
- });
289
- if (currentCatalogOperation.generationSetDigest
290
- !== initialCatalogOperation.generationSetDigest
291
- || options.expectedGenerationSetDigest
292
- && currentCatalogOperation.generationSetDigest !== options.expectedGenerationSetDigest) {
293
- throw new PortableCommandError('reviewStale', '确认后 Active Catalog generation 已变化。');
294
- }
295
- current = await collectEvidence({
296
- ...options,
297
- scope,
298
- agents,
299
- catalogOperationContext: currentCatalogOperation,
300
- });
301
- }
302
- catch (error) {
303
- if (error instanceof PortableCommandError && error.code === 'portableNoSkillsSelected') {
304
- throw new PortableCommandError('reviewStale', '确认后的所选 Skill 已消失。');
305
- }
306
- throw error;
307
- }
308
- try {
309
- const initialNames = new Set(initial.review.selected.map((entry) => entry.name));
310
- const currentNames = new Set(current.review.selected.map((entry) => entry.name));
311
- if ([...initialNames].some((name) => !currentNames.has(name))) {
312
- throw new PortableCommandError('reviewStale', '确认后的所选 Skill 已消失。');
313
- }
314
- if (options.expectedEvidenceDigest
315
- && current.review.evidenceDigest !== options.expectedEvidenceDigest) {
316
- throw new PortableCommandError('reviewStale', '确认后的安装证据已变化。');
317
- }
318
- if (current.review.evidenceDigest !== initial.review.evidenceDigest && !options.yes) {
319
- options.onReview?.(current.review);
320
- const confirmed = await options.confirm?.(current.review);
321
- if (!confirmed || confirmed.cancelled || confirmed.value !== true) {
322
- throw new PortableCommandError('reviewStale', '安装证据已变化,且新 Review 未确认。');
323
- }
324
- }
325
- const executionCwd = options.scope === 'project' ? resolveAwProjectRoot(options.cwd) : options.cwd;
326
- let addFailure;
327
- try {
328
- await options.onProgress?.('add');
329
- await addSkills({
330
- rootDir: current.materialized.rootDir,
331
- skills: current.review.selected.map((entry) => entry.name),
332
- ...(agents ? { agents } : {}),
333
- global: options.scope === 'user',
334
- cwd: executionCwd,
335
- env: options.env,
336
- });
337
- }
338
- catch (error) {
339
- if (error instanceof SkillsCliError && error.code === 'portableSkillsCliInstallFailed') {
340
- addFailure = error;
341
- }
342
- else {
343
- throw error;
344
- }
345
- }
346
- await options.onProgress?.('verify');
347
- const verification = await verifySkills({
348
- skills: current.review.selected.map((entry) => entry.name),
349
- ...(agents ? { agents } : {}),
350
- global: options.scope === 'user',
351
- cwd: executionCwd,
352
- env: options.env,
353
- });
354
- if (verification.unknown.length > 0) {
355
- const receipt = installFailureReceipt(current.review, addFailure?.code ?? 'portableSkillsCliVerificationFailed', 'partial', verification);
356
- receipt.warnings.push('skills list 验证失败,部分目标的结果无法确认。');
357
- if (!addFailure)
358
- receipt.failures = [];
359
- receipt.failures.push({
360
- code: 'portableSkillsCliVerificationFailed',
361
- message: 'skills list 验证失败,部分安装结果为 unknown。',
362
- recovery: '修复 Skills CLI 后先重新检查结果,再决定是否重试或清理外部安装。',
363
- });
364
- return receipt;
365
- }
366
- if (addFailure) {
367
- const expectedCount = current.review.selected.length * (agents?.length ?? 1);
368
- return installFailureReceipt(current.review, addFailure.code, verification.missing.length === expectedCount ? 'failed' : 'partial', verification);
369
- }
370
- if (verification.missing.length > 0) {
371
- return installFailureReceipt(current.review, 'portableSkillsCliVerificationFailed', 'partial', verification);
372
- }
373
- return {
374
- ...installFailureReceipt(current.review, '', 'failed', verification),
375
- ok: true,
376
- status: 'succeeded',
377
- failures: [],
378
- };
379
- }
380
- finally {
381
- await current.materialized.cleanup();
382
- }
383
- },
384
- });
385
- }
386
- function receiptTargets(receipt) {
387
- if (receipt.attemptedTargets)
388
- return receipt.attemptedTargets.map((target) => ({ ...target }));
389
- const skills = receipt.selectedSkills.map((candidate) => candidate.name);
390
- if (receipt.agentMode === 'explicit') {
391
- return receipt.requestedAgents.flatMap((agent) => skills.map((skill) => ({ skill, agent })));
392
- }
393
- return skills.map((skill) => ({ skill }));
394
- }
395
- function verificationStatus(targets, verification) {
396
- if (verification.unknown.length > 0)
397
- return 'partial';
398
- if (verification.missing.length === 0)
399
- return 'succeeded';
400
- return verification.missing.length === targets.length ? 'failed' : 'partial';
401
- }
402
- function recheckedReceipt(receipt, skillsCliVersion, verification) {
403
- const targets = receiptTargets(receipt);
404
- const status = verificationStatus(targets, verification);
405
- const unknown = verification.unknown.length > 0;
406
- const missing = verification.missing.length > 0;
407
- return {
408
- ...receipt,
409
- ok: status === 'succeeded',
410
- status,
411
- skillsCliVersion,
412
- verification: {
413
- ...verification,
414
- records: publicInstalledRecords(verification.records),
415
- },
416
- warnings: unknown ? ['skills list 验证失败,部分目标的结果无法确认。'] : [],
417
- failures: unknown ? [{
418
- code: 'portableSkillsCliVerificationFailed',
419
- message: 'skills list 验证失败,部分安装结果为 unknown。',
420
- recovery: '修复 Skills CLI 后先重新检查结果,再决定是否重试或清理外部安装。',
421
- }] : missing ? [{
422
- code: 'portableSkillsCliVerificationFailed',
423
- message: '只读检查确认部分目标缺失。',
424
- recovery: '重新准备后只重试明确缺失的 Skill 与 Agent 组合。',
425
- }] : [],
426
- };
427
- }
428
- export async function recheckPortableInstall(options) {
429
- assertScope(options.receipt.scope);
430
- const executionCwd = options.receipt.scope === 'project'
431
- ? resolveAwProjectRoot(options.cwd)
432
- : options.cwd;
433
- const skillsCli = await probeSkillsCli({
434
- cwd: executionCwd,
435
- env: options.env,
436
- signal: options.signal,
437
- });
438
- const verification = await verifySkillTargets({
439
- targets: receiptTargets(options.receipt),
440
- global: options.receipt.scope === 'user',
441
- cwd: executionCwd,
442
- env: options.env,
443
- signal: options.signal,
444
- });
445
- return recheckedReceipt(options.receipt, skillsCli.version, verification);
446
- }
447
- function normalizeRetryPairs(receipt) {
448
- if ((receipt.verification.unknown?.length ?? 0) > 0) {
449
- throw new PortableCommandError('portableRetryNotExact', '存在无法确认的目标;必须先只读复查,不能猜测重试目标。');
450
- }
451
- if (receipt.verification.missing.length === 0) {
452
- throw new PortableCommandError('portableNoRetryTargets', '没有已确认缺失的目标可重试。');
453
- }
454
- if (receipt.agentMode !== 'explicit') {
455
- throw new PortableCommandError('portableRetryNotExact', '自动 Agent 结果没有精确 Agent 身份;只能先只读复查。');
456
- }
457
- const selected = new Set(receipt.selectedSkills.map((candidate) => candidate.name));
458
- const agents = new Set(receipt.requestedAgents);
459
- const result = [];
460
- const seen = new Set();
461
- for (const target of receipt.verification.missing) {
462
- if (!target.agent || !selected.has(target.skill) || !agents.has(target.agent)) {
463
- throw new PortableCommandError('portableRetryNotExact', '缺失结果不能绑定到原请求中的精确 Skill 与 Agent。');
464
- }
465
- const key = `${target.skill}\0${target.agent}`;
466
- if (!seen.has(key)) {
467
- seen.add(key);
468
- result.push({ skill: target.skill, agent: target.agent });
469
- }
470
- }
471
- return result;
472
- }
473
- function retryTargetGroups(pairs) {
474
- const groups = new Map();
475
- for (const pair of pairs) {
476
- if (!pair.agent) {
477
- throw new PortableCommandError('portableRetryNotExact', '重试目标缺少精确 Agent。');
478
- }
479
- const skills = groups.get(pair.agent) ?? [];
480
- skills.push(pair.skill);
481
- groups.set(pair.agent, skills);
482
- }
483
- return [...groups].map(([agent, skills]) => ({ agent, skills }));
484
- }
485
- function createRetryReview(review, retryPairs) {
486
- const targetGroups = retryTargetGroups(retryPairs);
487
- const baseEvidenceDigest = review.evidenceDigest;
488
- return {
489
- ...review,
490
- baseEvidenceDigest,
491
- retryPairs: retryPairs.map((pair) => ({ ...pair })),
492
- targetGroups,
493
- evidenceDigest: digest({ baseEvidenceDigest, retryPairs, targetGroups }),
494
- };
495
- }
496
- async function collectRetryEvidence(options) {
497
- const skills = [...new Set(options.retryPairs.map((pair) => pair.skill))];
498
- const agents = [...new Set(options.retryPairs.map((pair) => pair.agent))];
499
- const parsedSelector = parsePluginId(options.receipt.plugin.id);
500
- const catalogOperationContext = options.catalogOperationContext
501
- ?? await resolveCatalogOperationContext({
502
- ...(parsedSelector.sourceId ? { sourceIds: [parsedSelector.sourceId] } : {}),
503
- env: options.env,
504
- ...(options.signal ? { signal: options.signal } : {}),
505
- });
506
- const collected = await collectEvidence({
507
- selector: options.receipt.plugin.id,
508
- scope: options.receipt.scope,
509
- requestedSkills: skills,
510
- agents,
511
- cwd: options.cwd,
512
- cliVersion: options.cliVersion,
513
- env: options.env,
514
- signal: options.signal,
515
- catalogOperationContext,
516
- });
517
- return { ...collected, review: createRetryReview(collected.review, options.retryPairs) };
518
- }
519
- export async function preparePortableRetry(options) {
520
- const checked = await recheckPortableInstall(options);
521
- const retryPairs = normalizeRetryPairs(checked);
522
- const collected = await collectRetryEvidence({ ...options, receipt: checked, retryPairs });
523
- try {
524
- return structuredClone(collected.review);
525
- }
526
- finally {
527
- await collected.materialized.cleanup();
528
- }
529
- }
530
- export async function executePortableRetry(options) {
531
- if (options.expectedEvidenceDigest !== options.review.evidenceDigest) {
532
- throw new PortableCommandError('reviewStale', 'Portable 重试票据不匹配。');
533
- }
534
- await options.onProgress?.('prepare');
535
- return withAwHomeMutationLock({
536
- env: options.env,
537
- action: async () => {
538
- const checked = await recheckPortableInstall({
539
- receipt: options.receipt,
540
- cwd: options.cwd,
541
- env: options.env,
542
- signal: options.signal,
543
- });
544
- const retryPairs = normalizeRetryPairs(checked);
545
- const collected = await collectRetryEvidence({ ...options, receipt: checked, retryPairs });
546
- try {
547
- if (collected.review.evidenceDigest !== options.expectedEvidenceDigest) {
548
- throw new PortableCommandError('reviewStale', '确认后的 Portable 重试证据已变化。');
549
- }
550
- const executionCwd = checked.scope === 'project'
551
- ? resolveAwProjectRoot(options.cwd)
552
- : options.cwd;
553
- let addFailed = false;
554
- await options.onProgress?.('add');
555
- for (const group of collected.review.targetGroups) {
556
- try {
557
- await addSkills({
558
- rootDir: collected.materialized.rootDir,
559
- skills: group.skills,
560
- agents: [group.agent],
561
- global: checked.scope === 'user',
562
- cwd: executionCwd,
563
- env: options.env,
564
- signal: options.signal,
565
- });
566
- }
567
- catch (error) {
568
- if (error instanceof SkillsCliError && error.code === 'portableSkillsCliInstallFailed') {
569
- addFailed = true;
570
- continue;
571
- }
572
- throw error;
573
- }
574
- }
575
- await options.onProgress?.('verify');
576
- const verification = await verifySkillTargets({
577
- targets: collected.review.retryPairs,
578
- global: checked.scope === 'user',
579
- cwd: executionCwd,
580
- env: options.env,
581
- signal: options.signal,
582
- });
583
- const status = verificationStatus(collected.review.retryPairs, verification);
584
- if (!addFailed && status === 'succeeded') {
585
- return {
586
- ...installFailureReceipt(collected.review, '', 'failed', verification, collected.review.retryPairs),
587
- ok: true,
588
- status: 'succeeded',
589
- failures: [],
590
- };
591
- }
592
- const receipt = installFailureReceipt(collected.review, addFailed ? 'portableSkillsCliInstallFailed' : 'portableSkillsCliVerificationFailed', status === 'failed' ? 'failed' : 'partial', verification, collected.review.retryPairs);
593
- if (verification.unknown.length > 0) {
594
- receipt.warnings.push('skills list 验证失败,部分目标的结果无法确认。');
595
- receipt.failures.push({
596
- code: 'portableSkillsCliVerificationFailed',
597
- message: 'skills list 验证失败,部分重试结果为 unknown。',
598
- recovery: '修复 Skills CLI 后先重新检查结果,再决定是否重试。',
599
- });
600
- }
601
- return receipt;
602
- }
603
- finally {
604
- await collected.materialized.cleanup();
605
- }
606
- },
607
- });
79
+ export function renderPortableReview(_review) {
80
+ return removedPortableWorkflow();
608
81
  }
609
82
  async function assertNoSymlinks(root) {
610
83
  const stats = await fs.lstat(root);
@@ -638,7 +111,7 @@ async function assertSafeOutputPath(target, options) {
638
111
  throw new PortableCommandError('portableOutputConflict', '输出目标范围过宽。');
639
112
  }
640
113
  }
641
- async function prepareExistingOutput(target, pluginId, sourceIdentity, scope) {
114
+ async function prepareExistingOutput(target, pluginId, sourceIdentity, scope, platform) {
642
115
  if (!await fs.pathExists(target))
643
116
  return;
644
117
  await assertNoSymlinks(target);
@@ -652,8 +125,9 @@ async function prepareExistingOutput(target, pluginId, sourceIdentity, scope) {
652
125
  || marker.plugin?.id !== pluginId
653
126
  || sourceIdentity === undefined
654
127
  || marker.plugin?.sourceIdentity !== sourceIdentity
655
- || marker.scope !== scope) {
656
- throw new PortableCommandError('portableOutputConflict', '已有输出的 pluginId、sourceIdentity 或 scope 不匹配。');
128
+ || marker.scope !== scope
129
+ || marker.platform !== platform) {
130
+ throw new PortableCommandError('portableOutputConflict', '已有输出的 pluginId、sourceIdentity、platform 或 scope 不匹配。');
657
131
  }
658
132
  }
659
133
  async function commitOutput(staging, target, expected) {
@@ -662,7 +136,7 @@ async function commitOutput(staging, target, expected) {
662
136
  if (existing) {
663
137
  await fs.rename(target, backup);
664
138
  try {
665
- await prepareExistingOutput(backup, expected.pluginId, expected.sourceIdentity, expected.scope);
139
+ await prepareExistingOutput(backup, expected.pluginId, expected.sourceIdentity, expected.scope, expected.platform);
666
140
  }
667
141
  catch {
668
142
  const replacement = await fs.lstat(target).catch(() => undefined);
@@ -685,6 +159,7 @@ async function commitOutput(staging, target, expected) {
685
159
  await fs.remove(backup).catch(() => undefined);
686
160
  }
687
161
  export async function materializePortableSkillsToDirectory(options) {
162
+ assertPortablePlatform(options.platform);
688
163
  assertScope(options.scope);
689
164
  const scope = options.scope;
690
165
  const rawTarget = path.resolve(options.cwd, options.out);
@@ -696,28 +171,33 @@ export async function materializePortableSkillsToDirectory(options) {
696
171
  await assertSafeOutputPath(target, options);
697
172
  const configSnapshot = await readCatalogSourcesConfigSnapshot(options.env);
698
173
  const parsedSelector = parsePluginId(options.selector);
699
- const catalogOperationContext = await resolveCatalogOperationContext({
174
+ const catalogOperationContext = options.catalogOperationContext ?? await resolveCatalogOperationContext({
700
175
  ...(parsedSelector.sourceId ? { sourceIds: [parsedSelector.sourceId] } : {}),
701
176
  env: options.env,
702
177
  });
703
- const materialized = await createMaterialization({
178
+ const materialized = await materializePortableSkillsFromCatalog({
704
179
  ...options,
705
180
  scope,
706
181
  configSnapshot,
707
182
  catalogOperationContext,
708
183
  });
709
184
  try {
710
- const selected = selectCandidates(materialized.candidates, options.requestedSkills);
711
- await prepareExistingOutput(target, materialized.pluginId, materialized.sourceIdentity, options.scope);
185
+ const selected = options.allowEmpty && options.requestedSkills === undefined && materialized.candidates.length === 0
186
+ ? [] : selectCandidates(materialized.candidates, options.requestedSkills);
187
+ await prepareExistingOutput(target, materialized.pluginId, materialized.sourceIdentity, options.scope, options.platform);
712
188
  try {
713
189
  await ensureRegularDirectoryPath(path.dirname(target), 'portable output parent');
714
190
  }
715
191
  catch {
716
192
  throw new PortableCommandError('portableOutputConflict', '输出目标的父目录不是安全的普通目录。');
717
193
  }
718
- const staging = await fs.mkdtemp(path.join(path.dirname(target), `.${path.basename(target)}.aw-stage-`));
194
+ const stagingPrefix = path.join(path.dirname(target), `.${path.basename(target)}.aw-stage-`);
195
+ // Node's mkdtemp does not add the Windows extended-length prefix itself.
196
+ const createdStaging = await fs.mkdtemp(path.toNamespacedPath(stagingPrefix));
197
+ const staging = path.join(path.dirname(target), path.basename(createdStaging));
719
198
  let committed = false;
720
199
  try {
200
+ await fs.ensureDir(path.join(staging, 'skills'));
721
201
  for (const candidate of selected) {
722
202
  await fs.copy(path.join(materialized.rootDir, 'skills', candidate.name), path.join(staging, 'skills', candidate.name), { dereference: false, errorOnExist: true });
723
203
  }
@@ -737,6 +217,7 @@ export async function materializePortableSkillsToDirectory(options) {
737
217
  ...(materialized.sourceIdentity ? { sourceIdentity: materialized.sourceIdentity } : {}),
738
218
  ...(materialized.pluginVersion ? { version: materialized.pluginVersion } : {}),
739
219
  },
220
+ platform: options.platform,
740
221
  scope: options.scope,
741
222
  out: target,
742
223
  selectedSkills: selected,
@@ -766,7 +247,8 @@ export async function materializePortableSkillsToDirectory(options) {
766
247
  subject: { plugin: materialized.pluginId.split('/').at(-1) },
767
248
  profile: {
768
249
  kind: 'portable',
769
- id: `agent-skills-${scope}`,
250
+ id: `${options.platform}-${scope}`,
251
+ platform: options.platform,
770
252
  scope,
771
253
  inputDigest: materialized.configDigest,
772
254
  },
@@ -786,6 +268,7 @@ export async function materializePortableSkillsToDirectory(options) {
786
268
  });
787
269
  const currentBinding = await resolvePortableCatalogBindingInput({
788
270
  selector: options.selector,
271
+ platform: options.platform,
789
272
  scope,
790
273
  cwd: options.cwd,
791
274
  cliVersion: options.cliVersion,
@@ -801,6 +284,7 @@ export async function materializePortableSkillsToDirectory(options) {
801
284
  await commitOutput(staging, target, {
802
285
  pluginId: materialized.pluginId,
803
286
  sourceIdentity: materialized.sourceIdentity,
287
+ platform: options.platform,
804
288
  scope: options.scope,
805
289
  });
806
290
  committed = true;