mano-coding 0.1.32 → 0.1.34

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 (2) hide show
  1. package/dist/bin.js +788 -438
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -3404,17 +3404,19 @@ var init_zh = __esm({
3404
3404
  "version.description": "\u663E\u793A CLI \u7248\u672C",
3405
3405
  // create.ts
3406
3406
  "create.description": "\u5411\u6307\u5B9A\u76EE\u5F55\u521B\u5EFA\u5DE5\u7A0B\u5E76\u5B89\u88C5 AI Coding \u8D44\u4EA7",
3407
- "create.argPackageSpec": "\u6269\u5C55\u5305\u89C4\u683C\u6216\u9879\u76EE\u76EE\u5F55",
3407
+ "create.argTemplateSpec": "\u6A21\u677F\u89C4\u683C\uFF08\u672A\u6307\u5B9A\u65F6\u5728\u4EA4\u4E92\u7EC8\u7AEF\u4E2D\u9009\u62E9\uFF09",
3408
3408
  "create.argDirectory": "\u9879\u76EE\u76EE\u5F55\uFF08\u9ED8\u8BA4\uFF1A\u5F53\u524D\u76EE\u5F55\uFF09",
3409
- "create.optionPackage": "\u6269\u5C55\u5305\u89C4\u683C\uFF08\u53EF\u91CD\u590D\uFF0C\u6240\u6709\u5305\u6309\u540C\u540D\u751F\u547D\u5468\u671F\u4E32\u884C\u6267\u884C\uFF09",
3410
- "create.optionTemplate": "\u6269\u5C55\u5305\u89C4\u683C\uFF08\u5411\u540E\u517C\u5BB9\u522B\u540D\uFF0C\u5EFA\u8BAE\u4F7F\u7528 --package\uFF09",
3411
- "create.optionAddon": "\u6269\u5C55\u5305\u89C4\u683C\uFF08\u5411\u540E\u517C\u5BB9\u522B\u540D\uFF0C\u5EFA\u8BAE\u4F7F\u7528 --package\uFF09",
3412
- "create.templateRequired": "\u975E\u4EA4\u4E92\u73AF\u5883\u5FC5\u987B\u901A\u8FC7\u53C2\u6570\u63D0\u4F9B\u81F3\u5C11\u4E00\u4E2A\u6269\u5C55\u5305\u89C4\u683C",
3413
- "create.registryIndexUnsupported": "\u5F53\u524D Registry \u5BA2\u6237\u7AEF\u4E0D\u652F\u6301\u5305\u7D22\u5F15",
3414
- "create.chooseTemplate": "\u9009\u62E9\u8981\u5B89\u88C5\u7684\u6269\u5C55\u5305",
3415
- "create.templateSelectionCancelled": "\u6269\u5C55\u5305\u9009\u62E9\u5DF2\u53D6\u6D88",
3416
- "create.packageKindMismatch": "\u5305 {0} \u7684\u5185\u5BB9\u4E0D\u7B26\u5408 create \u547D\u4EE4\u8981\u6C42",
3417
- "create.addonKindMismatch": "\u5305 {0} \u7684\u5185\u5BB9\u4E0D\u7B26\u5408\u8981\u6C42",
3409
+ "create.optionTemplate": "\u6A21\u677F\u89C4\u683C\uFF08\u53EF\u91CD\u590D\uFF0C\u652F\u6301\u4E00\u6B21\u6027\u6307\u5B9A\u591A\u4E2A\u6A21\u677F\uFF09",
3410
+ "create.templateRequired": "\u975E\u4EA4\u4E92\u73AF\u5883\u5FC5\u987B\u901A\u8FC7\u53C2\u6570\u63D0\u4F9B\u81F3\u5C11\u4E00\u4E2A\u6A21\u677F\u89C4\u683C",
3411
+ "create.registryIndexUnsupported": "\u5F53\u524D Registry \u5BA2\u6237\u7AEF\u4E0D\u652F\u6301\u6A21\u677F\u7D22\u5F15",
3412
+ "create.chooseTemplate": "\u9009\u62E9\u8981\u5B89\u88C5\u7684\u6A21\u677F",
3413
+ "create.templateSelectionCancelled": "\u6A21\u677F\u9009\u62E9\u5DF2\u53D6\u6D88",
3414
+ "create.templateKindMismatch": "\u6A21\u677F {0} \u7684\u5185\u5BB9\u4E0D\u7B26\u5408 create \u547D\u4EE4\u8981\u6C42",
3415
+ "create.filterUnsupported": "create \u547D\u4EE4\u4E0D\u652F\u6301 --only / --skip \u8D44\u4EA7\u8FC7\u6EE4\uFF0C\u4EE5\u4FDD\u8BC1\u6A21\u677F\u5B8C\u6574\u4EA4\u4ED8\u3002\u5982\u9700\u5B9A\u5236\u53D7\u7BA1\u8D44\u4EA7\u8BF7\u4F7F\u7528 apply \u547D\u4EE4\u3002",
3416
+ "create.templateAlreadyInstalled": "\u6A21\u677F '{0}' \u5DF2\u7ECF\u5B89\u88C5\u5728\u5F53\u524D\u5DE5\u7A0B\u4E2D\u3002\u4E0D\u80FD\u901A\u8FC7 create \u91CD\u65B0\u5B89\u88C5\u3002\u5982\u9700\u66F4\u65B0\u914D\u7F6E\u6216\u540C\u6B65\u8D44\u4EA7\u8BF7\u4F7F\u7528 'apply'\u3001'sync' \u6216 'upgrade' \u547D\u4EE4\u3002",
3417
+ "create.missingTaskInputs": "\u6A21\u677F '{0}' \u7F3A\u5C11\u521D\u59CB\u5316\u53C2\u6570: {1}\uFF0C\u8BF7\u4F7F\u7528\uFF1A\n{2}",
3418
+ "create.promptTaskInput": "[{0}] \u8BF7\u8F93\u5165\u521D\u59CB\u5316\u53C2\u6570 '{1}':",
3419
+ "create.taskValidationFailed": "\u53C2\u6570\u6821\u9A8C\u5931\u8D25",
3418
3420
  "create.missingInputs": "\u7F3A\u5C11\u5FC5\u586B\u8F93\u5165\uFF1A{0}",
3419
3421
  "create.missingInputsHint": "\u7F3A\u5C11\u5FC5\u586B\u8F93\u5165\uFF1A{0}\u3002\u8BF7\u901A\u8FC7 --input <name>=<value> \u63D0\u4F9B",
3420
3422
  "create.chooseTargets": "\u9009\u62E9\u8981\u521D\u59CB\u5316\u7684 IDE \u76EE\u6807",
@@ -3425,7 +3427,7 @@ var init_zh = __esm({
3425
3427
  "create.userDeclined": "\u7528\u6237\u62D2\u7EDD\u4E86 Plan \u786E\u8BA4",
3426
3428
  "create.executionFailed": "\u6267\u884C\u5931\u8D25\uFF1B\u5DF2\u5C1D\u8BD5\u56DE\u6EDA",
3427
3429
  "create.executionFailedShort": "\u6267\u884C\u5931\u8D25",
3428
- "create.projectExtensionFailed": "\u5DE5\u7A0B\u6269\u5C55 create \u5931\u8D25\uFF1A{0}",
3430
+ "create.projectExtensionFailed": "\u5DE5\u7A0B\u6A21\u677F create \u5931\u8D25\uFF1A{0}",
3429
3431
  "create.createdProject": "\u9879\u76EE\u5DF2\u521B\u5EFA\u5728 {0}",
3430
3432
  "create.lockFile": "Lock \u6587\u4EF6\uFF1A{0}",
3431
3433
  "create.enterInput": "\u8F93\u5165 {0}",
@@ -3434,34 +3436,67 @@ var init_zh = __esm({
3434
3436
  "create.initializingWorkspace": "\u6B63\u5728\u521D\u59CB\u5316\u5DE5\u7A0B\u5DE5\u4F5C\u533A\u2026\n",
3435
3437
  "create.workspaceInitialized": "\u2713 \u5DE5\u7A0B\u5DE5\u4F5C\u533A\u521D\u59CB\u5316\u5B8C\u6210\uFF08{0}\uFF09\n",
3436
3438
  "create.installingUserTools": "\u6B63\u5728\u5B89\u88C5\u7528\u6237\u7EA7\u5DE5\u5177\uFF08{0} \u9879\uFF09\u2026\n",
3437
- "create.userToolsInstalled": "\u2713 \u7528\u6237\u7EA7\u5DE5\u5177\u5B89\u88C5\u5B8C\u6210\uFF08{0}\uFF09\n",
3439
+ "create.computingPlan": "\u6B63\u5728\u8BA1\u7B97\u53D7\u7BA1\u8D44\u6E90\u5E76\u751F\u6210\u6267\u884C\u8BA1\u5212...",
3440
+ "create.planReady": "\u2714 \u6267\u884C\u8BA1\u5212\u5DF2\u5C31\u7EEA (\u5171 {0} \u9879\u8D44\u6E90\u53D8\u66F4)",
3441
+ "create.planFailed": "\u2716 \u6267\u884C\u8BA1\u5212\u751F\u6210\u5931\u8D25",
3438
3442
  "create.installing": "\u6B63\u5728\u5B89\u88C5\uFF1A{0}\n",
3439
3443
  "create.installed": "\u2713 \u5DF2\u5B89\u88C5\uFF1A{0}\n",
3440
3444
  "create.reused": "\u2713 \u5DF2\u590D\u7528\uFF1A{0}\n",
3441
3445
  "create.skipped": "- \u65E0\u9700\u5B89\u88C5\uFF1A{0}\n",
3446
+ "common.seconds": "{0} \u79D2",
3447
+ // 模板通用解析文案
3448
+ "template.resolving": "\u6B63\u5728\u62C9\u53D6\u5E76\u89E3\u6790\u6A21\u677F ({0})...",
3449
+ "template.resolved": "\u2714 \u6A21\u677F\u89E3\u6790\u5B8C\u6210: {0} (v{1})",
3450
+ "template.resolveFailed": "\u2716 \u6A21\u677F\u89E3\u6790\u5931\u8D25: {0}",
3451
+ // 任务通用执行文案
3452
+ "task.runningBeforeCreate": "\u6B63\u5728\u6267\u884C\u524D\u7F6E\u521B\u5EFA\u4EFB\u52A1 (before:create) [{0}/{1}] ({2}):",
3453
+ "task.runningAfterCreate": "\u6B63\u5728\u6267\u884C\u540E\u7F6E\u521B\u5EFA\u4EFB\u52A1 (after:create) [{0}/{1}] ({2}):",
3454
+ "task.runningBeforeApply": "\u6B63\u5728\u6267\u884C\u524D\u7F6E\u5E94\u7528\u4EFB\u52A1 (before:apply) [{0}/{1}] ({2}):",
3455
+ "task.runningAfterApply": "\u6B63\u5728\u6267\u884C\u540E\u7F6E\u5E94\u7528\u4EFB\u52A1 (after:apply) [{0}/{1}] ({2}):",
3456
+ "task.runningBeforeRemove": "\u6B63\u5728\u6267\u884C\u524D\u7F6E\u79FB\u9664\u4EFB\u52A1 (before:remove) [{0}/{1}] ({2}):",
3457
+ "task.runningAfterRemove": "\u6B63\u5728\u6267\u884C\u540E\u7F6E\u79FB\u9664\u4EFB\u52A1 (after:remove) [{0}/{1}] ({2}):",
3458
+ "task.runningBeforeSync": "\u6B63\u5728\u6267\u884C\u524D\u7F6E\u540C\u6B65\u4EFB\u52A1 (before:sync) [{0}/{1}] ({2}):",
3459
+ "task.runningAfterSync": "\u6B63\u5728\u6267\u884C\u540E\u7F6E\u540C\u6B65\u4EFB\u52A1 (after:sync) [{0}/{1}] ({2}):",
3442
3460
  // apply.ts
3443
3461
  "apply.description": "\u5411\u6307\u5B9A\u76EE\u5F55\u589E\u52A0 AI Coding \u77E5\u8BC6\u8D44\u4EA7\u6216\u672C\u5730 MCP",
3444
- "apply.argPackageSpec": "\u8981\u5E94\u7528\u7684\u6269\u5C55\u5305\u89C4\u683C\uFF08\u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5305\uFF09",
3445
- "apply.packageRequired": "apply \u547D\u4EE4\u5FC5\u987B\u663E\u5F0F\u6307\u5B9A\u81F3\u5C11\u4E00\u4E2A\u6269\u5C55\u5305",
3462
+ "apply.argTemplateSpec": "\u8981\u5E94\u7528\u7684\u6A21\u677F\u89C4\u683C\uFF08\u672A\u6307\u5B9A\u65F6\u5728\u4EA4\u4E92\u7EC8\u7AEF\u4E2D\u9009\u62E9\uFF09",
3463
+ "apply.optionTemplate": "\u8981\u5E94\u7528\u7684\u6A21\u677F\u89C4\u683C\uFF08\u53EF\u91CD\u590D\uFF0C\u6240\u6709\u6A21\u677F\u6309\u540C\u540D\u751F\u547D\u5468\u671F\u4E32\u884C\u6267\u884C\uFF09",
3464
+ "apply.templateRequired": "\u975E\u4EA4\u4E92\u73AF\u5883\u5FC5\u987B\u663E\u5F0F\u6307\u5B9A\u81F3\u5C11\u4E00\u4E2A\u6A21\u677F",
3465
+ "apply.chooseTemplate": "\u9009\u62E9\u8981\u5E94\u7528\u7684\u6A21\u677F",
3466
+ "apply.templateSelectionCancelled": "\u6A21\u677F\u9009\u62E9\u5DF2\u53D6\u6D88",
3467
+ "apply.chooseTargets": "\u9009\u62E9\u8981\u5E94\u7528\u7684 IDE \u76EE\u6807",
3468
+ "apply.targetSelectionCancelled": "\u76EE\u6807\u9009\u62E9\u5DF2\u53D6\u6D88",
3469
+ "apply.targetRequired": "\u7F3A\u5C11\u76EE\u6807 IDE \u53C2\u6570\uFF0C\u8BF7\u4F7F\u7528 --target <ide...>",
3470
+ "apply.noAvailableTemplates": "\u6CA1\u6709\u53EF\u4F9B\u5B89\u88C5\u7684\u65B0\u6A21\u677F\u6216\u5168\u90E8\u5019\u9009\u6A21\u677F\u5DF2\u5B89\u88C5",
3446
3471
  "apply.optionOnly": "\u4EC5\u5B89\u88C5\u6307\u5B9A\u7684\u53D7\u7BA1\u77E5\u8BC6\u8D44\u4EA7\u7C7B\u578B\uFF08\u9017\u53F7\u5206\u9694\uFF1Askills,rules,subagents,mcp,agents-md\uFF09",
3447
3472
  "apply.optionSkip": "\u8DF3\u8FC7\u6307\u5B9A\u7684\u53D7\u7BA1\u77E5\u8BC6\u8D44\u4EA7\u7C7B\u578B\uFF08\u9017\u53F7\u5206\u9694\uFF1Askills,rules,subagents,mcp,agents-md\uFF09",
3448
3473
  "apply.onlySkipExclusive": "--only \u4E0E --skip \u53C2\u6570\u4E92\u65A5\uFF0C\u4E0D\u80FD\u540C\u65F6\u4F7F\u7528",
3449
3474
  "apply.invalidAssetType": "\u65E0\u6548\u7684\u8D44\u4EA7\u7C7B\u578B '{0}'\uFF0C\u4EC5\u652F\u6301: skills, rules, subagents, mcp, agents-md",
3450
- "apply.emptyAfterFilter": "\u8FC7\u6EE4\u540E\u65E0\u53EF\u4EA4\u4ED8\u7684\u6838\u5FC3\u53D7\u7BA1\u8D44\u4EA7\u4E14\u5305\u4E0D\u5305\u542B apply \u751F\u547D\u5468\u671F\u4EFB\u52A1",
3475
+ "apply.emptyAfterFilter": "\u8FC7\u6EE4\u540E\u65E0\u53EF\u4EA4\u4ED8\u7684\u6838\u5FC3\u53D7\u7BA1\u8D44\u4EA7\u4E14\u6A21\u677F\u4E0D\u5305\u542B apply \u751F\u547D\u5468\u671F\u4EFB\u52A1",
3451
3476
  "apply.driftDetected": "\u53D7\u7BA1\u8D44\u6E90\u5DF2\u6F02\u79FB\uFF0C\u62D2\u7EDD apply\uFF1B\u8BF7\u5148\u8FD0\u884C sync --drift restore \u6216 accept",
3452
- "apply.packageSpecRequired": "\u9879\u76EE\u65E0 lock \u6587\u4EF6\u65F6 apply \u9700\u8981 <package-spec>\u3002\u4F7F\u7528 --dry-run \u9884\u89C8\u3002",
3453
- "apply.addonKindMismatch": "\u5305 {0} \u7684\u7C7B\u578B\u4E3A '{1}'\uFF0C\u671F\u671B 'Addon'",
3477
+ "apply.packageSpecRequired": "\u9879\u76EE\u65E0 lock \u6587\u4EF6\u65F6 apply \u9700\u8981\u6307\u5B9A\u6A21\u677F\u3002\u4F7F\u7528 --dry-run \u9884\u89C8\u3002",
3478
+ "apply.templateKindMismatch": "\u6A21\u677F {0} \u7684\u7C7B\u578B\u4E3A '{1}'\uFF0C\u671F\u671B 'template'",
3454
3479
  "apply.missingInputs": "\u7F3A\u5C11\u5FC5\u586B\u8F93\u5165\uFF1A{0}\u3002\u901A\u8FC7 --set \u63D0\u4F9B\u3002",
3455
3480
  "apply.planConflict": "Plan \u5B58\u5728\u51B2\u7A81",
3456
3481
  "apply.needsConfirmation": "\u6267\u884C Plan \u9700\u8981 --yes\u3002\u4F7F\u7528 --dry-run \u9884\u89C8\u3002",
3457
3482
  "apply.userDeclined": "\u7528\u6237\u62D2\u7EDD\u4E86 Plan \u786E\u8BA4",
3458
3483
  "apply.executionFailed": "\u6267\u884C\u5931\u8D25\uFF1B\u5DF2\u5C1D\u8BD5\u56DE\u6EDA",
3459
3484
  "apply.executionFailedShort": "\u6267\u884C\u5931\u8D25",
3460
- "apply.projectExtensionFailed": "Addon {0} \u7684\u5DE5\u7A0B\u6269\u5C55 apply \u5931\u8D25\uFF1A{1}",
3461
- "apply.applied": "\u5DF2\u5C06 Addon \u5E94\u7528\u5230 {0}",
3485
+ "apply.projectExtensionFailed": "\u6A21\u677F {0} \u7684\u5DE5\u7A0B\u6269\u5C55 apply \u5931\u8D25\uFF1A{1}",
3486
+ "apply.applied": "\u5DF2\u5C06\u6A21\u677F\u5E94\u7528\u5230 {0}",
3462
3487
  "apply.lockFile": "Lock \u6587\u4EF6\uFF1A{0}",
3488
+ "apply.alreadyUpToDate": "\u5DF2\u5E94\u7528\uFF0C\u65E0\u53D8\u5316",
3489
+ "apply.computingPlan": "\u6B63\u5728\u8BA1\u7B97\u53D7\u7BA1\u8D44\u6E90\u5E76\u751F\u6210\u6267\u884C\u8BA1\u5212...",
3490
+ "apply.planReady": "\u2714 \u6267\u884C\u8BA1\u5212\u5DF2\u5C31\u7EEA (\u5171 {0} \u9879\u8D44\u6E90\u53D8\u66F4)",
3491
+ "apply.planFailed": "\u2716 \u6267\u884C\u8BA1\u5212\u751F\u6210\u5931\u8D25",
3492
+ "apply.resourceConflict": "\u8D44\u6E90 '{0}' \u4E0E\u5DF2\u6709\u6A21\u677F\u8D44\u6E90\u5B58\u5728\u51B2\u7A81",
3493
+ "apply.lockedConfigLoaded": "\u2714 \u5DF2\u52A0\u8F7D\u9501\u5B9A\u914D\u7F6E",
3494
+ "apply.skippedCreateTasks": "- \u5DF2\u8DF3\u8FC7 {0} \u4E2A create \u751F\u547D\u5468\u671F\u94A9\u5B50\u4EFB\u52A1\uFF08apply \u8BED\u4E49\u4E0D\u6267\u884C before:create / after:create \u94A9\u5B50\uFF09\n",
3495
+ "apply.templateUpdatedNeedsUpgrade": "\u6A21\u677F '{0}' \u7248\u672C\u76F8\u540C\u4F46\u5185\u5BB9\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u4F7F\u7528 upgrade \u547D\u4EE4\u8FDB\u884C\u66F4\u65B0",
3463
3496
  // sync.ts
3464
3497
  "sync.description": "\u4ECE lock \u6587\u4EF6\u6062\u590D\u9879\u76EE\u72B6\u6001\uFF08\u4E0D\u89E3\u6790\u7248\u672C\uFF09",
3498
+ "sync.optionTemplate": "\u4EC5\u540C\u6B65\u6307\u5B9A\u7684\u5DF2\u5B89\u88C5\u6A21\u677F",
3499
+ "sync.templateNotFound": "\u672A\u5728 Lock \u6587\u4EF6\u4E2D\u627E\u5230\u6A21\u677F '{0}'\u3002\u8BE5\u6A21\u677F\u672A\u5B89\u88C5\u6216\u65E0\u6CD5\u540C\u6B65\u3002",
3465
3500
  "sync.lockNotFound": "\u5728 {0} \u672A\u627E\u5230 lock \u6587\u4EF6\u3002\u8BF7\u5148\u4F7F\u7528 create \u6216 apply\u3002",
3466
3501
  "sync.acceptMissing": "sync --drift accept \u4E0D\u5141\u8BB8 missing \u8D44\u6E90\uFF1B\u8BF7\u5148\u6062\u590D\u6216\u4F7F\u7528 remove \u91CA\u653E\uFF1A{0}",
3467
3502
  "sync.driftDetected": "\u68C0\u6D4B\u5230 {0} \u9879\u8D44\u6E90\u6F02\u79FB\uFF1B\u4F7F\u7528 --drift restore \u6062\u590D\u6216 --drift accept \u63A5\u7EB3",
@@ -3475,35 +3510,41 @@ var init_zh = __esm({
3475
3510
  "sync.lockFile": "Lock \u6587\u4EF6\uFF1A{0}",
3476
3511
  "sync.locateDriftFailed": "\u65E0\u6CD5\u5B9A\u4F4D\u6F02\u79FB\u8D44\u6E90 {0}",
3477
3512
  // remove.ts
3478
- "remove.description": "\u4ECE\u9879\u76EE\u4E2D\u79FB\u9664\u5305\u6216\u5168\u90E8\u53D7\u7BA1\u5185\u5BB9",
3479
- "remove.optionPackage": "\u8981\u79FB\u9664\u7684\u5305 ID\uFF08\u5355\u4E2A\uFF09",
3480
- "remove.lockNotFound": "\u5728 {0} \u672A\u627E\u5230 lock \u6587\u4EF6\u3002\u65E0\u5185\u5BB9\u53EF\u79FB\u9664\u3002",
3481
- "remove.packageNotInLock": "\u5305 {0} \u4E0D\u5728\u9879\u76EE lock \u4E2D\u3002\u53EF\u7528\uFF1A{1}",
3513
+ "remove.description": "\u4ECE\u9879\u76EE\u4E2D\u79FB\u9664\u6307\u5B9A\u7684\u6A21\u677F\u6216\u5168\u90E8\u53D7\u7BA1\u5185\u5BB9",
3514
+ "remove.argTemplate": "\u8981\u79FB\u9664\u7684\u6A21\u677F ID\uFF08\u53EF\u9009\uFF0C\u672A\u6307\u5B9A\u65F6\u79FB\u9664\u5168\u90E8\uFF09",
3515
+ "remove.optionTemplate": "\u8981\u79FB\u9664\u7684\u6A21\u677F ID\uFF08\u5355\u4E2A\uFF09",
3516
+ "remove.chooseTemplate": "\u9009\u62E9\u8981\u79FB\u9664\u7684\u6A21\u677F",
3517
+ "remove.templateSelectionCancelled": "\u6A21\u677F\u79FB\u9664\u9009\u62E9\u5DF2\u53D6\u6D88",
3518
+ "remove.lockNotFound": "\u5728 {0} \u672A\u627E\u5230 lock \u6587\u4EF6\u3002\u65E0\u6A21\u677F\u53EF\u79FB\u9664\u3002",
3519
+ "remove.templateNotInLock": "\u6A21\u677F {0} \u4E0D\u5728\u9879\u76EE lock \u4E2D\u3002\u5F53\u524D\u53EF\u7528\u6A21\u677F\uFF1A{1}",
3520
+ "remove.bootstrapTemplateCannotBeRemoved": "\u6A21\u677F '{0}' \u662F\u9879\u76EE\u7684\u521D\u59CB\u5DE5\u7A0B\u6A21\u677F (bootstrap-only)\uFF0C\u4E0D\u5305\u542B\u53D7\u7BA1\u77E5\u8BC6\u8D44\u4EA7\uFF0C\u65E0\u6CD5\u88AB remove\u3002\u82E5\u9700\u5220\u9664\u6574\u4E2A\u9879\u76EE\uFF0C\u8BF7\u76F4\u63A5\u5220\u9664\u9879\u76EE\u76EE\u5F55\u3002",
3482
3521
  "remove.driftDetected": "\u68C0\u6D4B\u5230 {0} \u9879\u8D44\u6E90\u6F02\u79FB\uFF1B\u5982\u786E\u8BA4\u5220\u9664\u5DF2\u4FEE\u6539\u5185\u5BB9\uFF0C\u8BF7\u4F7F\u7528 --drift accept",
3483
3522
  "remove.needsConfirmation": "\u6267\u884C Remove \u9700\u8981 --yes\u3002\u4F7F\u7528 --dry-run \u9884\u89C8\u3002",
3484
3523
  "remove.userDeclined": "\u7528\u6237\u62D2\u7EDD\u4E86 Plan \u786E\u8BA4",
3485
3524
  "remove.executionFailed": "\u6267\u884C\u5931\u8D25\uFF1B\u5DF2\u5C1D\u8BD5\u56DE\u6EDA",
3486
3525
  "remove.executionFailedShort": "\u6267\u884C\u5931\u8D25",
3487
- "remove.removed": "\u5DF2\u4ECE {1} \u79FB\u9664 {0}",
3488
- "remove.allPackages": "\u6240\u6709\u5305",
3526
+ "remove.removed": "\u5DF2\u4ECE {1} \u79FB\u9664\u6A21\u677F {0}",
3527
+ "remove.allTemplates": "\u6240\u6709\u6A21\u677F",
3489
3528
  "remove.lockRemoved": "Lock \u6587\u4EF6\u5DF2\u79FB\u9664\u3002",
3490
3529
  "remove.lockUpdated": "Lock \u6587\u4EF6\u5DF2\u66F4\u65B0\u3002",
3491
3530
  "remove.userReferenceFailed": "\u79FB\u9664 {0}/{1}@{2} \u7684\u7528\u6237\u7EA7\u5F15\u7528\u5931\u8D25\uFF1A{3}",
3492
3531
  // upgrade.ts
3493
3532
  "upgrade.description": "\u5C06 Capability \u5347\u7EA7\u5230\u65B0\u7248\u672C\u5E76\u5207\u6362\u9879\u76EE\u5F15\u7528",
3494
3533
  "upgrade.optionProject": "\u9879\u76EE\u6839\u76EE\u5F55",
3495
- "upgrade.optionPackage": "Capability \u7684\u5305 ID",
3534
+ "upgrade.optionTemplate": "Capability \u6240\u5C5E\u7684\u6A21\u677F ID",
3496
3535
  "upgrade.optionCapability": "\u8981\u5347\u7EA7\u7684 Capability ID",
3497
3536
  "upgrade.optionVersion": "\u76EE\u6807\u5347\u7EA7\u7248\u672C",
3498
3537
  "upgrade.optionDryRun": "\u4EC5\u9884\u89C8\uFF0C\u4E0D\u6267\u884C",
3499
3538
  "upgrade.optionYes": "\u65E0\u9700\u786E\u8BA4\u5373\u6279\u51C6",
3500
3539
  "upgrade.optionAllow": "\u6388\u6743\u9AD8\u98CE\u9669\u64CD\u4F5C\uFF08\u53EF\u91CD\u590D\uFF09",
3501
- "upgrade.missingOptions": "upgrade \u9700\u8981 --package\u3001--capability \u548C --version",
3540
+ "upgrade.missingOptions": "upgrade \u9700\u8981 --template\u3001--capability \u548C --version",
3541
+ "upgrade.missingTemplate": "\u8BF7\u901A\u8FC7 --template <template-id> \u6307\u5B9A\u9700\u8981\u5347\u7EA7\u7684\u6A21\u677F\u3002",
3542
+ "upgrade.planSummary": "\u5347\u7EA7\u8BA1\u5212\uFF1A\n \u6A21\u677F\uFF1A{0}\n \u5F53\u524D\uFF1A{1}\n \u76EE\u6807\uFF1A{2}\n \u9879\u76EE\uFF1A{3}\n",
3502
3543
  "upgrade.lockNotFound": "\u5728 {0} \u672A\u627E\u5230 lock \u6587\u4EF6\u3002\u8BF7\u5148\u4F7F\u7528 create \u6216 apply\u3002",
3503
3544
  "upgrade.driftDetected": "\u53D7\u7BA1\u8D44\u6E90\u5DF2\u6F02\u79FB\uFF0C\u62D2\u7EDD\u5347\u7EA7",
3504
- "upgrade.packageNotInLock": "\u5728 lock \u6587\u4EF6\u7684 template \u4E2D\u672A\u627E\u5230\u5305 {0}",
3545
+ "upgrade.templateNotInLock": "\u5728 lock \u6587\u4EF6\u7684 template \u4E2D\u672A\u627E\u5230\u6A21\u677F {0}",
3505
3546
  "upgrade.alreadyAtVersion": "\u5DF2\u5904\u4E8E\u7248\u672C {0}\uFF0C\u65E0\u9700\u5347\u7EA7",
3506
- "upgrade.noDesiredTemplate": "\u5305 {0} \u6CA1\u6709 desired template \u6761\u76EE",
3547
+ "upgrade.noDesiredTemplate": "\u6A21\u677F {0} \u6CA1\u6709 desired template \u6761\u76EE",
3507
3548
  "upgrade.resolveFailed": "\u65E0\u6CD5\u89E3\u6790\u6A21\u677F {0}@{1}\uFF1A{2}",
3508
3549
  "upgrade.resolveInvalid": "\u65E0\u6CD5\u89E3\u6790\u6A21\u677F {0}@{1}",
3509
3550
  "upgrade.capabilityAbsent": "Capability {0}/{1} \u5728 {2} \u4E2D\u4E0D\u5B58\u5728",
@@ -3513,6 +3554,9 @@ var init_zh = __esm({
3513
3554
  "upgrade.upgraded": "\u5DF2\u5347\u7EA7 {0}/{1}\uFF1A{2} -> {3}",
3514
3555
  "upgrade.dryRunPlan": "CLI \u5347\u7EA7\u8BA1\u5212\uFF1A\n current: {0}\n target: {1}\n integrity: {2}\n manager: {3}\n bin: {4}\n",
3515
3556
  "upgrade.alreadyCurrent": "aicoding \u5DF2\u662F {0}\u3002",
3557
+ // 任务通用执行文案 (upgrade)
3558
+ "task.runningBeforeUpgrade": "\u6B63\u5728\u6267\u884C\u524D\u7F6E\u5347\u7EA7\u4EFB\u52A1 (before:upgrade) ({0}):",
3559
+ "task.runningAfterUpgrade": "\u6B63\u5728\u6267\u884C\u540E\u7F6E\u5347\u7EA7\u4EFB\u52A1 (after:upgrade) ({0}):",
3516
3560
  // self-upgrade.ts
3517
3561
  "selfUpgrade.description": "\u68C0\u67E5\u6216\u5347\u7EA7\u7531 npm/pnpm \u5B89\u88C5\u7684 mano-coding CLI",
3518
3562
  "selfUpgrade.optionCheck": "\u4EC5\u5237\u65B0\u7248\u672C\u4FE1\u606F",
@@ -3615,7 +3659,8 @@ var init_zh = __esm({
3615
3659
  // launch.ts
3616
3660
  "launch.description": "\u9690\u85CF\u542F\u52A8\u547D\u4EE4 - \u542F\u52A8\u7CBE\u786E\u5B89\u88C5\uFF08\u8BF7\u52FF\u76F4\u63A5\u4F7F\u7528\uFF09",
3617
3661
  "launch.optionKind": "\u6240\u6709\u8005\u7C7B\u578B\uFF08project|capability|plugin\uFF09",
3618
- "launch.optionPackage": "\u5305 ID",
3662
+ "launch.optionTemplate": "\u6A21\u677F ID",
3663
+ "launch.optionPackage": "\u6A21\u677F ID",
3619
3664
  "launch.optionId": "\u6240\u6709\u8005 ID",
3620
3665
  "launch.optionVersion": "\u7CBE\u786E\u7248\u672C",
3621
3666
  "launch.optionCommand": "\u547D\u4EE4\u540D\u79F0\uFF08\u53EA\u6709\u4E00\u4E2A\u547D\u4EE4\u65F6\u53EF\u9009\uFF09",
@@ -3644,17 +3689,37 @@ var init_zh = __esm({
3644
3689
  // extension commands
3645
3690
  "extension.create.description": "\u521D\u59CB\u5316\u6807\u51C6\u6269\u5C55/\u6A21\u677F\u5DE5\u7A0B",
3646
3691
  "extension.create.argDirectory": "\u76EE\u6807\u5DE5\u7A0B\u76EE\u5F55",
3647
- "extension.create.optionName": "\u6269\u5C55\u5305 ID (package-id)",
3648
- "extension.create.optionCategory": "\u6269\u5C55\u5206\u7C7B",
3649
- "extension.create.optionWithProject": "\u662F\u5426\u5305\u542B\u5DE5\u7A0B\u6A21\u677F",
3692
+ "extension.create.optionName": "\u6A21\u677F ID (template-id)",
3693
+ "extension.create.optionTemplateName": "\u6A21\u677F\u663E\u793A\u540D\u79F0 (name)",
3694
+ "extension.create.optionDescription": "\u6A21\u677F\u63CF\u8FF0",
3695
+ "extension.create.optionCategory": "\u6A21\u677F\u5206\u7C7B",
3696
+ "extension.create.optionWithProject": "\u662F\u5426\u5305\u542B\u9759\u6001\u5DE5\u7A0B\u811A\u624B\u67B6 (project/)",
3697
+ "extension.create.optionWithTasks": "\u662F\u5426\u751F\u6210\u521D\u59CB\u5316\u4EFB\u52A1\u793A\u4F8B",
3650
3698
  "extension.create.optionWithCapability": "\u5305\u542B\u7684\u80FD\u529B\u7279\u6027",
3651
3699
  "extension.create.optionWithPipeline": "\u662F\u5426\u751F\u6210 GitLab CI/CD \u81EA\u52A8\u540C\u6B65\u6D41\u6C34\u7EBF\u914D\u7F6E (.gitlab-ci.yml)",
3652
3700
  "extension.create.optionYes": "\u8DF3\u8FC7\u4EA4\u4E92\u786E\u8BA4\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u503C",
3653
3701
  "extension.create.directoryNotEmpty": "\u76EE\u6807\u76EE\u5F55\u5DF2\u5B58\u5728\u4E14\u975E\u7A7A\uFF1A{0}",
3654
- "extension.pipeline.description": "\u751F\u6210\u6216\u66F4\u65B0\u6269\u5C55\u5305\u7684 GitLab CI/CD \u81EA\u52A8\u540C\u6B65\u6D41\u6C34\u7EBF\u914D\u7F6E (.gitlab-ci.yml)",
3655
- "extension.pipeline.argDirectory": "\u6269\u5C55\u5305\u5DE5\u7A0B\u76EE\u5F55\uFF08\u9ED8\u8BA4\u5F53\u524D\u76EE\u5F55\uFF09",
3702
+ "extension.create.promptName": "\u8BF7\u8F93\u5165\u6A21\u677F ID (Template ID):",
3703
+ "extension.create.promptTemplateName": "\u8BF7\u8F93\u5165\u6A21\u677F\u540D\u79F0 (Name):",
3704
+ "extension.create.promptDescription": "\u8BF7\u8F93\u5165\u6A21\u677F\u7B80\u8981\u63CF\u8FF0 (Description):",
3705
+ "extension.create.promptWithTasks": "\u662F\u5426\u5305\u542B\u9879\u76EE\u811A\u624B\u67B6\u521D\u59CB\u5316\u4EFB\u52A1 (Tasks) \u793A\u4F8B\uFF1F",
3706
+ "extension.create.promptWithProject": "\u662F\u5426\u751F\u6210\u9759\u6001\u5DE5\u7A0B\u811A\u624B\u67B6\u76EE\u5F55 (project/)\uFF1F",
3707
+ "extension.create.promptWithPipeline": "\u662F\u5426\u751F\u6210 GitLab CI/CD \u81EA\u52A8\u540C\u6B65\u6D41\u6C34\u7EBF\u914D\u7F6E (.gitlab-ci.yml)\uFF1F",
3708
+ "extension.create.created": "\u6A21\u677F\u5DE5\u7A0B\u5DF2\u521B\u5EFA\u5728\uFF1A{0}",
3709
+ "extension.create.success": "\u2713 \u6210\u529F\u521D\u59CB\u5316\u6A21\u677F\u5DE5\u7A0B: {0}",
3710
+ "extension.create.generatedFiles": "\u5DF2\u751F\u6210\u6587\u4EF6\u6E05\u5355:",
3711
+ "extension.pipeline.description": "\u751F\u6210\u6216\u66F4\u65B0\u6A21\u677F\u5DE5\u7A0B\u7684 GitLab CI/CD \u81EA\u52A8\u540C\u6B65\u6D41\u6C34\u7EBF\u914D\u7F6E (.gitlab-ci.yml)",
3712
+ "extension.pipeline.argDirectory": "\u6A21\u677F\u5DE5\u7A0B\u76EE\u5F55\uFF08\u9ED8\u8BA4\u5F53\u524D\u76EE\u5F55\uFF09",
3656
3713
  "extension.pipeline.optionForce": "\u82E5\u5DF2\u5B58\u5728 .gitlab-ci.yml \u5219\u5F3A\u5236\u8986\u76D6",
3657
- "extension.pipeline.optionPackageId": "\u6269\u5C55\u5305 ID\uFF08\u9ED8\u8BA4\u4ECE manifest.yaml \u6216 package.json \u89E3\u6790\uFF09"
3714
+ "extension.pipeline.optionTemplateId": "\u6A21\u677F ID\uFF08\u9ED8\u8BA4\u4ECE manifest.yaml \u6216 package.json \u89E3\u6790\uFF09",
3715
+ "extension.pipeline.optionYes": "\u8DF3\u8FC7\u4EA4\u4E92\u786E\u8BA4",
3716
+ "extension.pipeline.idNotFound": "\u672A\u80FD\u81EA\u52A8\u8BC6\u522B\u6A21\u677F ID\u3002\u8BF7\u786E\u4FDD\u5F53\u524D\u76EE\u5F55\u4E0B\u5B58\u5728\u6709\u6548\u7684 manifest.yaml \u6216 package.json\uFF0C\u6216\u4F7F\u7528 --template-id \u663E\u5F0F\u4F20\u5165\u3002",
3717
+ "extension.pipeline.overwritePrompt": "\u68C0\u6D4B\u5230\u5F53\u524D\u76EE\u5F55\u5DF2\u5B58\u5728 .gitlab-ci.yml\uFF0C\u662F\u5426\u8986\u76D6\uFF1F",
3718
+ "extension.pipeline.cancelled": "\u64CD\u4F5C\u5DF2\u53D6\u6D88\uFF0C\u672A\u4FEE\u6539\u73B0\u6709\u6D41\u6C34\u7EBF\u914D\u7F6E\u3002",
3719
+ "extension.pipeline.alreadyExists": "\u5F53\u524D\u76EE\u5F55\u5DF2\u5B58\u5728 .gitlab-ci.yml\uFF0C\u5982\u9700\u8986\u76D6\u8BF7\u4F20\u9012 --force \u53C2\u6570\u3002",
3720
+ "extension.pipeline.success": "\u2713 \u6210\u529F\u751F\u6210 CI/CD \u6D41\u6C34\u7EBF\u914D\u7F6E: {0}",
3721
+ "extension.pipeline.addedReleaseScript": '\u2713 \u5DF2\u5728 package.json \u7684 scripts \u4E2D\u6DFB\u52A0\u53D1\u7248\u547D\u4EE4: "release": "npm version patch"',
3722
+ "extension.pipeline.gitlabNotice": '\n\u2699\uFE0F GitLab \u9879\u76EE\u914D\u7F6E\u63D0\u793A:\n \u8BF7\u5728\u5F53\u524D\u6A21\u677F\u4ED3\u5E93\u7684\u3010Settings -> CI/CD -> Variables\u3011\u4E2D\u914D\u7F6E\u4EE5\u4E0B\u73AF\u5883\u53D8\u91CF\uFF1A\n - REGISTRY_TRIGGER_TOKEN: Registry \u4ED3\u5E93\u751F\u6210\u7684 Pipeline Trigger Token\n - REGISTRY_PROJECT_ID: Registry \u4ED3\u5E93\u5728 GitLab \u4E0A\u7684\u9879\u76EE ID\n\n\u{1F680} \u65E5\u5E38\u53D1\u7248\u5DE5\u4F5C\u6D41:\n 1. \u63D0\u4EA4\u4EE3\u7801: git add . && git commit -m "feat: xxx"\n 2. \u4E00\u952E\u63D0\u5347\u7248\u672C\u5E76\u6253 Tag: npm run release\n 3. \u63A8\u9001\u5230\u8FDC\u7A0B\u89E6\u53D1\u81EA\u52A8\u5408\u5E76: git push --follow-tags origin main\n\n'
3658
3723
  };
3659
3724
  }
3660
3725
  });
@@ -23353,10 +23418,10 @@ async function persistGitCheckout(workDir, targetDir) {
23353
23418
  return targetDir;
23354
23419
  }
23355
23420
  async function copyGitCheckout(src, dest) {
23356
- const { readdir: readdir11, mkdir: mkdir19, copyFile: copyFile2 } = await import("node:fs/promises");
23421
+ const { readdir: readdir12, mkdir: mkdir20, copyFile: copyFile2 } = await import("node:fs/promises");
23357
23422
  const { join: joinPath } = await import("node:path");
23358
- await mkdir19(dest, { recursive: true });
23359
- const entries = await readdir11(src, { withFileTypes: true });
23423
+ await mkdir20(dest, { recursive: true });
23424
+ const entries = await readdir12(src, { withFileTypes: true });
23360
23425
  for (const entry of entries) {
23361
23426
  if (entry.name === ".git") continue;
23362
23427
  const srcPath = joinPath(src, entry.name);
@@ -23549,8 +23614,8 @@ var init_git_resolver = __esm({
23549
23614
  }
23550
23615
  const cacheBase = join6(cacheRoot, "git", encodePackageId(packageId));
23551
23616
  try {
23552
- const { readdir: readdir11 } = await import("node:fs/promises");
23553
- const commits = await readdir11(cacheBase, { withFileTypes: true });
23617
+ const { readdir: readdir12 } = await import("node:fs/promises");
23618
+ const commits = await readdir12(cacheBase, { withFileTypes: true });
23554
23619
  for (const entry of commits) {
23555
23620
  if (!entry.isDirectory()) continue;
23556
23621
  const cacheDir = join6(cacheBase, entry.name);
@@ -26935,10 +27000,10 @@ var init_tarball_loader = __esm({
26935
27000
  return targetDir;
26936
27001
  }
26937
27002
  async copyDirRecursive(src, dest) {
26938
- const { readdir: readdir11, mkdir: mkdir19, copyFile: copyFile2 } = await import("node:fs/promises");
27003
+ const { readdir: readdir12, mkdir: mkdir20, copyFile: copyFile2 } = await import("node:fs/promises");
26939
27004
  const { join: joinPath } = await import("node:path");
26940
- await mkdir19(dest, { recursive: true });
26941
- const entries = await readdir11(src, { withFileTypes: true });
27005
+ await mkdir20(dest, { recursive: true });
27006
+ const entries = await readdir12(src, { withFileTypes: true });
26942
27007
  for (const entry of entries) {
26943
27008
  const srcPath = joinPath(src, entry.name);
26944
27009
  const destPath = joinPath(dest, entry.name);
@@ -27001,14 +27066,14 @@ var init_tarball_loader = __esm({
27001
27066
  return readFile34(join7(packageRoot, "manifest.yaml"), "utf-8");
27002
27067
  }
27003
27068
  async findPackageRoot(workDir, packageId, version) {
27004
- const { access: access12, readdir: readdir11 } = await import("node:fs/promises");
27069
+ const { access: access12, readdir: readdir12 } = await import("node:fs/promises");
27005
27070
  const { resolve: resolvePath10 } = await import("node:path");
27006
27071
  const candidates = [
27007
27072
  resolvePath10(workDir),
27008
27073
  resolvePath10(workDir, "package")
27009
27074
  ];
27010
27075
  try {
27011
- const entries = await readdir11(workDir, { withFileTypes: true });
27076
+ const entries = await readdir12(workDir, { withFileTypes: true });
27012
27077
  for (const entry of entries) {
27013
27078
  if (entry.isDirectory()) {
27014
27079
  candidates.push(resolvePath10(workDir, entry.name));
@@ -30530,10 +30595,27 @@ var init_toml_editor = __esm({
30530
30595
  });
30531
30596
 
30532
30597
  // packages/core/src/execute/executor.ts
30533
- import { readFile as readFile17, writeFile as writeFile5, unlink as unlink7, mkdir as mkdir12, access as access9, rename as rename4, rm as rm4, mkdtemp as mkdtemp4, chmod } from "node:fs/promises";
30598
+ import { readFile as readFile17, writeFile as writeFile5, unlink as unlink7, mkdir as mkdir12, access as access9, rename as rename4, rm as rm4, mkdtemp as mkdtemp4, chmod, readdir as readdir5, rmdir } from "node:fs/promises";
30534
30599
  import { resolve as resolvePath7, dirname as dirname11, join as join12 } from "node:path";
30535
30600
  import { tmpdir as tmpdir4 } from "node:os";
30536
30601
  import { createHash as createHash9 } from "node:crypto";
30602
+ async function cleanEmptyParentDirs(startDir, rootDir) {
30603
+ let current = resolvePath7(startDir);
30604
+ const normalizedRoot = resolvePath7(rootDir);
30605
+ while (current !== normalizedRoot && current.startsWith(normalizedRoot)) {
30606
+ try {
30607
+ const files = await readdir5(current);
30608
+ if (files.length === 0) {
30609
+ await rmdir(current);
30610
+ current = dirname11(current);
30611
+ } else {
30612
+ break;
30613
+ }
30614
+ } catch {
30615
+ break;
30616
+ }
30617
+ }
30618
+ }
30537
30619
  async function getTmpBase() {
30538
30620
  return mkdtemp4(join12(tmpdir4(), "aicoding-tx-"));
30539
30621
  }
@@ -30931,6 +31013,7 @@ var init_executor = __esm({
30931
31013
  throw err;
30932
31014
  }
30933
31015
  });
31016
+ await cleanEmptyParentDirs(dirname11(absPath), projectRoot);
30934
31017
  addFileRollback(absPath, backupPath, rollbackActions, `\u6062\u590D\u5DF2\u5220\u9664\u7684\u6587\u4EF6 ${intent.path}`);
30935
31018
  } else if (intent.type === "config-entry") {
30936
31019
  await removeConfigEntry(absPath, intent.selector, intent.format, backupDir, rollbackActions, intent.path);
@@ -31387,7 +31470,20 @@ var init_execute = __esm({
31387
31470
  // packages/core/src/execute/task-runner.ts
31388
31471
  import { spawn } from "node:child_process";
31389
31472
  import { existsSync as existsSync4 } from "node:fs";
31473
+ import { writeFile as writeFile6, mkdir as mkdir13 } from "node:fs/promises";
31474
+ import { tmpdir as tmpdir5 } from "node:os";
31390
31475
  import { delimiter, isAbsolute as isAbsolute5, join as join13, relative as relative5, resolve as resolve10, sep as sep3 } from "node:path";
31476
+ function sanitizeTaskOutput(text, stagingDir, projectDir) {
31477
+ if (!stagingDir || !projectDir || !text) return text;
31478
+ let res = text;
31479
+ const stagingBack = resolve10(stagingDir);
31480
+ const projectBack = resolve10(projectDir);
31481
+ const stagingForward = stagingBack.replaceAll("\\", "/");
31482
+ const projectForward = projectBack.replaceAll("\\", "/");
31483
+ res = res.replaceAll(stagingBack, projectBack);
31484
+ res = res.replaceAll(stagingForward, projectForward);
31485
+ return res;
31486
+ }
31391
31487
  function filterTasksByHook(items, hook) {
31392
31488
  return items.filter((item) => {
31393
31489
  const task = "task" in item ? item.task : item;
@@ -31639,7 +31735,6 @@ async function executeTasks(tasks, ctx, options = {}) {
31639
31735
  if (!varValidation.valid) {
31640
31736
  throw new TaskExecutionError(varValidation.errors.join("; "), 1);
31641
31737
  }
31642
- const stdio = options.stdio ?? "inherit";
31643
31738
  const allowedRoots = [
31644
31739
  ctx.projectDir,
31645
31740
  ctx.templateDir,
@@ -31672,8 +31767,12 @@ async function executeTasks(tasks, ctx, options = {}) {
31672
31767
  }
31673
31768
  }
31674
31769
  const taskLabel = task.name ? `${task.name} (${task.id})` : task.id;
31770
+ if (options.onTaskStart) {
31771
+ options.onTaskStart(task, i, tasks.length);
31772
+ }
31675
31773
  if (options.onProgress) {
31676
- options.onProgress(`\u6B63\u5728\u6267\u884C\u4EFB\u52A1 [${i + 1}/${tasks.length}] (${taskLabel}): ${command} ${effectiveArgs.join(" ")}`);
31774
+ const sanitizedCmd = sanitizeTaskOutput(`${command} ${effectiveArgs.join(" ")}`, ctx.stagingDir, ctx.projectDir);
31775
+ options.onProgress(`\u6B63\u5728\u6267\u884C\u4EFB\u52A1 [${i + 1}/${tasks.length}] (${taskLabel}): ${sanitizedCmd}`);
31677
31776
  }
31678
31777
  const rawExecutable = resolveTaskExecutable(command, process.platform, env.PATH);
31679
31778
  const { executable, args: spawnArgs } = prepareSpawnCommand(
@@ -31682,35 +31781,96 @@ async function executeTasks(tasks, ctx, options = {}) {
31682
31781
  process.platform
31683
31782
  );
31684
31783
  await new Promise((resolvePromise, reject) => {
31784
+ const isIgnore = options.stdio === "ignore";
31785
+ const isVerbose = Boolean(options.verbose);
31786
+ let childStdio;
31787
+ if (isIgnore) {
31788
+ childStdio = "ignore";
31789
+ } else if (isVerbose) {
31790
+ childStdio = ["inherit", "pipe", "pipe"];
31791
+ } else {
31792
+ childStdio = ["ignore", "pipe", "pipe"];
31793
+ }
31685
31794
  const child = spawn(executable, spawnArgs, {
31686
31795
  cwd: resolvedCwd,
31687
31796
  env,
31688
- stdio,
31797
+ stdio: childStdio,
31689
31798
  shell: false,
31690
31799
  windowsHide: true
31691
31800
  });
31692
- child.on("error", (err) => {
31693
- reject(
31694
- new TaskExecutionError(
31695
- `\u6267\u884C\u4EFB\u52A1 '${task.id}' \u5931\u8D25 (${command}): ${err.message}`,
31696
- 1,
31697
- task.id,
31698
- command
31699
- )
31801
+ const stdoutChunks = [];
31802
+ const stderrChunks = [];
31803
+ if (!isIgnore) {
31804
+ child.stdout?.on("data", (chunk) => {
31805
+ stdoutChunks.push(chunk);
31806
+ if (isVerbose) {
31807
+ process.stdout.write(sanitizeTaskOutput(chunk.toString(), ctx.stagingDir, ctx.projectDir));
31808
+ }
31809
+ });
31810
+ child.stderr?.on("data", (chunk) => {
31811
+ stderrChunks.push(chunk);
31812
+ if (isVerbose) {
31813
+ process.stderr.write(sanitizeTaskOutput(chunk.toString(), ctx.stagingDir, ctx.projectDir));
31814
+ }
31815
+ });
31816
+ }
31817
+ const writeErrorLogAndReject = async (code, rawErrorMessage) => {
31818
+ const now = (/* @__PURE__ */ new Date()).toISOString();
31819
+ const rawStdout = Buffer.concat(stdoutChunks).toString("utf-8");
31820
+ const rawStderr = Buffer.concat(stderrChunks).toString("utf-8");
31821
+ const stdoutStr = sanitizeTaskOutput(rawStdout, ctx.stagingDir, ctx.projectDir);
31822
+ const stderrStr = sanitizeTaskOutput(rawStderr, ctx.stagingDir, ctx.projectDir);
31823
+ const logContent = [
31824
+ `=== Mano Coding \u4EFB\u52A1\u6267\u884C\u9519\u8BEF\u65E5\u5FD7 ===`,
31825
+ `\u65F6\u95F4: ${now}`,
31826
+ `\u4EFB\u52A1 ID: ${task.id}`,
31827
+ `\u4EFB\u52A1\u540D\u79F0: ${task.name ?? task.id}`,
31828
+ `\u5DE5\u4F5C\u76EE\u5F55: ${resolvedCwd}`,
31829
+ `\u547D\u4EE4: ${command} ${effectiveArgs.join(" ")}`,
31830
+ `\u9000\u51FA\u7801: ${code}`,
31831
+ `\u9519\u8BEF\u4FE1\u606F: ${rawErrorMessage}`,
31832
+ `
31833
+ --- \u6807\u51C6\u8F93\u51FA (stdout) ---`,
31834
+ stdoutStr || "(\u65E0\u8F93\u51FA)",
31835
+ `
31836
+ --- \u6807\u51C6\u9519\u8BEF (stderr) ---`,
31837
+ stderrStr || "(\u65E0\u8F93\u51FA)",
31838
+ ""
31839
+ ].join("\n");
31840
+ const logDir = options.logDir ?? join13(ctx.projectDir, ".mano-coding", "logs");
31841
+ let logFilePath;
31842
+ try {
31843
+ await mkdir13(logDir, { recursive: true });
31844
+ logFilePath = join13(logDir, `task-error-${task.id}-${Date.now()}.log`);
31845
+ await writeFile6(logFilePath, logContent, "utf-8");
31846
+ } catch {
31847
+ try {
31848
+ const fallbackDir = join13(tmpdir5(), "mano-coding-logs");
31849
+ await mkdir13(fallbackDir, { recursive: true });
31850
+ logFilePath = join13(fallbackDir, `task-error-${task.id}-${Date.now()}.log`);
31851
+ await writeFile6(logFilePath, logContent, "utf-8");
31852
+ } catch {
31853
+ }
31854
+ }
31855
+ const taskErr = new TaskExecutionError(
31856
+ `\u4EFB\u52A1 '${taskLabel}' \u6267\u884C\u5931\u8D25\uFF0C\u9000\u51FA\u7801: ${code}${logFilePath ? `\u3002\u8BE6\u7EC6\u65E5\u5FD7\u5DF2\u4FDD\u5B58\u81F3: ${logFilePath}` : ""}`,
31857
+ code,
31858
+ task.id,
31859
+ command,
31860
+ logFilePath
31700
31861
  );
31862
+ options.onTaskFail?.(task, i, tasks.length, taskErr, logFilePath);
31863
+ reject(taskErr);
31864
+ };
31865
+ child.on("error", (err) => {
31866
+ void writeErrorLogAndReject(1, err.message);
31701
31867
  });
31702
31868
  child.on("exit", (code) => {
31703
31869
  if (code === 0 || code === null) {
31870
+ options.onTaskSuccess?.(task, i, tasks.length);
31704
31871
  resolvePromise();
31705
31872
  } else {
31706
- reject(
31707
- new TaskExecutionError(
31708
- `\u521D\u59CB\u5316\u4EFB\u52A1 '${task.id}' \u6267\u884C\u5931\u8D25\uFF0C\u9000\u51FA\u7801: ${code}`,
31709
- code,
31710
- task.id,
31711
- command
31712
- )
31713
- );
31873
+ void writeErrorLogAndReject(code, `\u5B50\u8FDB\u7A0B\u9000\u51FA\u7801\u975E 0: ${code}`);
31714
31874
  }
31715
31875
  });
31716
31876
  });
@@ -31721,11 +31881,12 @@ var init_task_runner = __esm({
31721
31881
  "packages/core/src/execute/task-runner.ts"() {
31722
31882
  "use strict";
31723
31883
  TaskExecutionError = class extends Error {
31724
- constructor(message, exitCode, taskId, command) {
31884
+ constructor(message, exitCode, taskId, command, logFile) {
31725
31885
  super(message);
31726
31886
  this.exitCode = exitCode;
31727
31887
  this.taskId = taskId;
31728
31888
  this.command = command;
31889
+ this.logFile = logFile;
31729
31890
  this.name = "TaskExecutionError";
31730
31891
  }
31731
31892
  };
@@ -31753,7 +31914,7 @@ var init_task_runner = __esm({
31753
31914
  });
31754
31915
 
31755
31916
  // packages/core/src/execute/template-contract.ts
31756
- import { readFile as readFile19, readdir as readdir5 } from "node:fs/promises";
31917
+ import { readFile as readFile19, readdir as readdir6 } from "node:fs/promises";
31757
31918
  import { join as join14, relative as relative6 } from "node:path";
31758
31919
  function validateMcpConfig(rawConfig) {
31759
31920
  if (typeof rawConfig !== "object" || rawConfig === null) {
@@ -31896,7 +32057,7 @@ async function scanTemplateDirectoryContract(options) {
31896
32057
  if (shouldIncludeAssetType("skills", filter)) {
31897
32058
  const skillsDir = join14(templateDir, "skills");
31898
32059
  try {
31899
- const skillEntries = await readdir5(skillsDir, { withFileTypes: true });
32060
+ const skillEntries = await readdir6(skillsDir, { withFileTypes: true });
31900
32061
  for (const skillEntry of skillEntries) {
31901
32062
  if (!skillEntry.isDirectory()) continue;
31902
32063
  const skillId = skillEntry.name;
@@ -31923,7 +32084,7 @@ async function scanTemplateDirectoryContract(options) {
31923
32084
  if (shouldIncludeAssetType("rules", filter)) {
31924
32085
  const rulesDir = join14(templateDir, "rules");
31925
32086
  try {
31926
- const ruleIdeEntries = await readdir5(rulesDir, { withFileTypes: true });
32087
+ const ruleIdeEntries = await readdir6(rulesDir, { withFileTypes: true });
31927
32088
  for (const ideEntry of ruleIdeEntries) {
31928
32089
  if (!ideEntry.isDirectory()) continue;
31929
32090
  const ide = ideEntry.name;
@@ -31949,7 +32110,7 @@ async function scanTemplateDirectoryContract(options) {
31949
32110
  if (shouldIncludeAssetType("subagents", filter)) {
31950
32111
  const subagentsDir = join14(templateDir, "subagents");
31951
32112
  try {
31952
- const agentIdeEntries = await readdir5(subagentsDir, { withFileTypes: true });
32113
+ const agentIdeEntries = await readdir6(subagentsDir, { withFileTypes: true });
31953
32114
  for (const ideEntry of agentIdeEntries) {
31954
32115
  if (!ideEntry.isDirectory()) continue;
31955
32116
  const ide = ideEntry.name;
@@ -31997,12 +32158,30 @@ async function scanTemplateDirectoryContract(options) {
31997
32158
  }
31998
32159
  }
31999
32160
  }
32161
+ if (!filter?.skipProjectDir) {
32162
+ const projectDir = join14(templateDir, "project");
32163
+ try {
32164
+ const allProjectFiles = await listAllFilesRecursive(projectDir);
32165
+ for (const relFile of allProjectFiles) {
32166
+ const fileContent = await readFile19(join14(projectDir, relFile));
32167
+ const normalizedRel = relFile.replaceAll("\\", "/");
32168
+ intents.push({
32169
+ action: "upsert",
32170
+ type: "file",
32171
+ path: normalizedRel,
32172
+ content: fileContent,
32173
+ assetType: "project-seed"
32174
+ });
32175
+ }
32176
+ } catch {
32177
+ }
32178
+ }
32000
32179
  return intents;
32001
32180
  }
32002
32181
  async function listAllFilesRecursive(dir, baseDir = dir) {
32003
32182
  const files = [];
32004
32183
  try {
32005
- const entries = await readdir5(dir, { withFileTypes: true });
32184
+ const entries = await readdir6(dir, { withFileTypes: true });
32006
32185
  for (const entry of entries) {
32007
32186
  const full = join14(dir, entry.name);
32008
32187
  if (entry.isDirectory()) {
@@ -32031,7 +32210,7 @@ var init_template_contract = __esm({
32031
32210
  });
32032
32211
 
32033
32212
  // packages/core/src/plugin/plugin-delivery.ts
32034
- import { readFile as readFile20, stat as stat4, readdir as readdir6 } from "node:fs/promises";
32213
+ import { readFile as readFile20, stat as stat4, readdir as readdir7 } from "node:fs/promises";
32035
32214
  import { join as join15, resolve as resolve11 } from "node:path";
32036
32215
  import { createHash as createHash11 } from "node:crypto";
32037
32216
  function isPluginTargetSupported(target) {
@@ -32389,7 +32568,7 @@ function buildSettingsUpdate(plugin, target) {
32389
32568
  }
32390
32569
  async function collectDirectoryCopyIntents(sourceDir, sourceRelPath, destDir, packageRoot, metadata) {
32391
32570
  const intents = [];
32392
- const entries = await readdir6(sourceDir, { withFileTypes: true });
32571
+ const entries = await readdir7(sourceDir, { withFileTypes: true });
32393
32572
  for (const entry of entries) {
32394
32573
  const entrySourcePath = join15(sourceDir, entry.name);
32395
32574
  const entryDestPath = `${destDir}/${entry.name}`;
@@ -32508,7 +32687,7 @@ var init_plugin = __esm({
32508
32687
 
32509
32688
  // packages/core/src/journal.ts
32510
32689
  import { createHash as createHash12, randomUUID as randomUUID3 } from "node:crypto";
32511
- import { chmod as chmod2, cp as cp2, mkdir as mkdir13, open as open4, readdir as readdir7, readFile as readFile21, rename as rename5, rm as rm5, stat as stat5, writeFile as writeFile6 } from "node:fs/promises";
32690
+ import { chmod as chmod2, cp as cp2, mkdir as mkdir14, open as open4, readdir as readdir8, readFile as readFile21, rename as rename5, rm as rm5, stat as stat5, writeFile as writeFile7 } from "node:fs/promises";
32512
32691
  import { dirname as dirname12, join as join16, resolve as resolve12 } from "node:path";
32513
32692
  function projectHash(projectRoot) {
32514
32693
  return createHash12("sha256").update(resolve12(projectRoot)).digest("hex").slice(0, 32);
@@ -32638,9 +32817,9 @@ async function createJournal(userDataDir, projectRoot, options = {}) {
32638
32817
  userDataDir: resolve12(userDataDir),
32639
32818
  ...paths
32640
32819
  };
32641
- await mkdir13(dirname12(paths.transactionPath), { recursive: true });
32642
- await mkdir13(paths.transactionPath);
32643
- await mkdir13(paths.backupPath);
32820
+ await mkdir14(dirname12(paths.transactionPath), { recursive: true });
32821
+ await mkdir14(paths.transactionPath);
32822
+ await mkdir14(paths.backupPath);
32644
32823
  await atomicWrite(paths.journalPath, documentOf(journal));
32645
32824
  return journal;
32646
32825
  }
@@ -32656,7 +32835,7 @@ async function scanJournals(userDataDir, projectRoot) {
32656
32835
  const directory = join16(resolve12(userDataDir), "transactions", projectHash(projectRoot));
32657
32836
  let entries;
32658
32837
  try {
32659
- entries = await readdir7(directory, { withFileTypes: true });
32838
+ entries = await readdir8(directory, { withFileTypes: true });
32660
32839
  } catch (error) {
32661
32840
  if (error.code === "ENOENT") return [];
32662
32841
  throw error;
@@ -32707,7 +32886,7 @@ async function prepareRecoverySnapshots(journal, scope, root, paths) {
32707
32886
  continue;
32708
32887
  }
32709
32888
  if (!info.isFile()) throw new JournalError(`Recovery \u76EE\u6807\u4E0D\u662F\u6587\u4EF6\u6216\u76EE\u5F55: ${path2}`, "JOURNAL_INVALID");
32710
- await writeFile6(join16(journal.backupPath, backupName), await readFile21(absolutePath));
32889
+ await writeFile7(join16(journal.backupPath, backupName), await readFile21(absolutePath));
32711
32890
  snapshots.push({ scope, path: path2, existed: true, backup: backupName, mode: info.mode & 4095, kind: "file" });
32712
32891
  } catch (error) {
32713
32892
  if (error.code === "ENOENT") {
@@ -32737,8 +32916,8 @@ async function restoreRecovery(journal, projectRoot, recovery) {
32737
32916
  if (snapshot2.mode !== void 0 && process.platform !== "win32") await chmod2(absolutePath, snapshot2.mode);
32738
32917
  continue;
32739
32918
  }
32740
- await mkdir13(dirname12(absolutePath), { recursive: true });
32741
- await writeFile6(absolutePath, await readFile21(join16(journal.backupPath, snapshot2.backup)));
32919
+ await mkdir14(dirname12(absolutePath), { recursive: true });
32920
+ await writeFile7(absolutePath, await readFile21(join16(journal.backupPath, snapshot2.backup)));
32742
32921
  if (snapshot2.mode !== void 0 && process.platform !== "win32") await chmod2(absolutePath, snapshot2.mode);
32743
32922
  }
32744
32923
  }
@@ -32807,7 +32986,7 @@ var init_journal = __esm({
32807
32986
 
32808
32987
  // packages/core/src/transaction.ts
32809
32988
  import { randomUUID as randomUUID4 } from "node:crypto";
32810
- import { mkdir as mkdir14, open as open5, lstat as lstat4, readFile as readFile22, readlink, rename as rename6, symlink as symlink2, unlink as unlink8 } from "node:fs/promises";
32989
+ import { mkdir as mkdir15, open as open5, lstat as lstat4, readFile as readFile22, readlink, rename as rename6, symlink as symlink2, unlink as unlink8 } from "node:fs/promises";
32811
32990
  import { dirname as dirname13, resolve as resolve13 } from "node:path";
32812
32991
  function errorCode(error) {
32813
32992
  if (error && typeof error === "object" && "code" in error) {
@@ -32883,7 +33062,7 @@ async function removeIfPresent(path2) {
32883
33062
  }
32884
33063
  }
32885
33064
  async function atomicWrite2(path2, content, mode) {
32886
- await mkdir14(dirname13(path2), { recursive: true });
33065
+ await mkdir15(dirname13(path2), { recursive: true });
32887
33066
  const temporaryPath = `${path2}.${randomUUID4()}.tmp`;
32888
33067
  let handle;
32889
33068
  try {
@@ -32903,7 +33082,7 @@ async function restore(path2, saved) {
32903
33082
  return removeIfPresent(path2);
32904
33083
  }
32905
33084
  await removeIfPresent(path2);
32906
- await mkdir14(dirname13(path2), { recursive: true });
33085
+ await mkdir15(dirname13(path2), { recursive: true });
32907
33086
  if (saved.kind === "symlink") {
32908
33087
  await symlink2(saved.target, path2);
32909
33088
  return;
@@ -33190,7 +33369,7 @@ var init_types5 = __esm({
33190
33369
 
33191
33370
  // packages/core/src/orchestrator/staging-manager.ts
33192
33371
  import { mkdtemp as mkdtemp5, rm as rm6 } from "node:fs/promises";
33193
- import { tmpdir as tmpdir5 } from "node:os";
33372
+ import { tmpdir as tmpdir6 } from "node:os";
33194
33373
  import { join as join17 } from "node:path";
33195
33374
  var StagingManager;
33196
33375
  var init_staging_manager = __esm({
@@ -33204,7 +33383,7 @@ var init_staging_manager = __esm({
33204
33383
  const existing = this.stagingDirs.get(packageId);
33205
33384
  if (existing) return existing;
33206
33385
  if (!this.baseDir) {
33207
- this.baseDir = await mkdtemp5(join17(tmpdir5(), "mano-staging-"));
33386
+ this.baseDir = await mkdtemp5(join17(tmpdir6(), "mano-staging-"));
33208
33387
  }
33209
33388
  const pkgStaging = await mkdtemp5(join17(this.baseDir, `${sanitizedId}-`));
33210
33389
  this.stagingDirs.set(packageId, pkgStaging);
@@ -33229,7 +33408,7 @@ var init_staging_manager = __esm({
33229
33408
  });
33230
33409
 
33231
33410
  // packages/core/src/orchestrator/staging-scanner.ts
33232
- import { readFile as readFile23, readdir as readdir8, stat as stat6 } from "node:fs/promises";
33411
+ import { readFile as readFile23, readdir as readdir9, stat as stat6 } from "node:fs/promises";
33233
33412
  import { join as join18, relative as relative7 } from "node:path";
33234
33413
  async function scanStagingDirectory(options) {
33235
33414
  const { stagingDir, packageId, ownerKind = "template" } = options;
@@ -33238,7 +33417,7 @@ async function scanStagingDirectory(options) {
33238
33417
  async function walk(currentDir) {
33239
33418
  let entries;
33240
33419
  try {
33241
- entries = await readdir8(currentDir, { withFileTypes: true });
33420
+ entries = await readdir9(currentDir, { withFileTypes: true });
33242
33421
  } catch {
33243
33422
  return;
33244
33423
  }
@@ -33380,7 +33559,7 @@ var init_qualification = __esm({
33380
33559
 
33381
33560
  // packages/core/src/orchestrator/lifecycle-orchestrator.ts
33382
33561
  import { randomUUID as randomUUID5 } from "node:crypto";
33383
- import { writeFile as writeFile7, mkdir as mkdir15 } from "node:fs/promises";
33562
+ import { writeFile as writeFile8, mkdir as mkdir16 } from "node:fs/promises";
33384
33563
  import { basename as basename3, dirname as dirname14, join as join19 } from "node:path";
33385
33564
  function resolveStringInputs(globalInputs, packageInputs, packageId) {
33386
33565
  const merged = {};
@@ -33537,8 +33716,8 @@ var init_lifecycle_orchestrator = __esm({
33537
33716
  for (const intent of stagingIntents) {
33538
33717
  if (intent.action === "upsert" && intent.type === "file") {
33539
33718
  const targetPath = join19(options.projectRoot, intent.path);
33540
- await mkdir15(dirname14(targetPath), { recursive: true });
33541
- await writeFile7(targetPath, intent.content);
33719
+ await mkdir16(dirname14(targetPath), { recursive: true });
33720
+ await writeFile8(targetPath, intent.content);
33542
33721
  }
33543
33722
  }
33544
33723
  }
@@ -33781,6 +33960,7 @@ __export(src_exports, {
33781
33960
  resolveTaskExecutable: () => resolveTaskExecutable,
33782
33961
  sanitizeCommand: () => sanitizeCommand,
33783
33962
  sanitizeEnvValue: () => sanitizeEnvValue,
33963
+ sanitizeTaskOutput: () => sanitizeTaskOutput,
33784
33964
  sanitizeUrl: () => sanitizeUrl,
33785
33965
  scanJournals: () => scanJournals,
33786
33966
  scanStagingDirectory: () => scanStagingDirectory,
@@ -43723,7 +43903,7 @@ var require_dist3 = __commonJS({
43723
43903
  });
43724
43904
 
43725
43905
  // packages/cli/src/commands/extension-pipeline.ts
43726
- import { readFile as readFile24, writeFile as writeFile8 } from "node:fs/promises";
43906
+ import { readFile as readFile24, writeFile as writeFile9 } from "node:fs/promises";
43727
43907
  import { existsSync as existsSync5 } from "node:fs";
43728
43908
  import { resolve as resolve14 } from "node:path";
43729
43909
  function generateGitlabCiYaml(packageId) {
@@ -43767,9 +43947,9 @@ notify_registry:
43767
43947
  }
43768
43948
  function createExtensionPipelineCommand() {
43769
43949
  const cmd = new Command("pipeline");
43770
- cmd.alias("ci").description(t("extension.pipeline.description")).argument("[directory]", t("extension.pipeline.argDirectory"), ".").option("--package-id <id>", t("extension.pipeline.optionPackageId")).option("--force", t("extension.pipeline.optionForce")).option("--yes", "\u8DF3\u8FC7\u4EA4\u4E92\u786E\u8BA4").option("--json", t("global.json")).option("--no-color", t("global.noColor")).option("--verbose", t("global.verbose")).action(async (directory, opts) => {
43950
+ cmd.alias("ci").description(t("extension.pipeline.description")).argument("[directory]", t("extension.pipeline.argDirectory"), ".").option("--template-id <id>", t("extension.pipeline.optionTemplateId")).option("--force", t("extension.pipeline.optionForce")).option("--yes", t("extension.pipeline.optionYes")).option("--json", t("global.json")).option("--no-color", t("global.noColor")).option("--verbose", t("global.verbose")).action(async (directory, opts) => {
43771
43951
  const options = {
43772
- packageId: opts.packageId,
43952
+ templateId: opts.templateId ?? opts.packageId,
43773
43953
  force: Boolean(opts.force),
43774
43954
  yes: Boolean(opts.yes),
43775
43955
  json: Boolean(opts.json),
@@ -43801,35 +43981,35 @@ async function executeExtensionPipeline(directory, options) {
43801
43981
  const pkgJsonPath = resolve14(targetDir, "package.json");
43802
43982
  const ciFilePath = resolve14(targetDir, ".gitlab-ci.yml");
43803
43983
  const isInteractive = !options.yes && !options.json && Boolean(process.stdin.isTTY);
43804
- let packageId = options.packageId;
43805
- if (!packageId) {
43984
+ let templateId = options.templateId;
43985
+ if (!templateId) {
43806
43986
  if (existsSync5(manifestPath)) {
43807
43987
  try {
43808
43988
  const manifestContent = await readFile24(manifestPath, "utf-8");
43809
43989
  const parsed = import_yaml4.default.parse(manifestContent);
43810
43990
  if (parsed && typeof parsed.id === "string") {
43811
- packageId = parsed.id;
43991
+ templateId = parsed.id;
43812
43992
  }
43813
43993
  } catch {
43814
43994
  }
43815
43995
  }
43816
- if (!packageId && existsSync5(pkgJsonPath)) {
43996
+ if (!templateId && existsSync5(pkgJsonPath)) {
43817
43997
  try {
43818
43998
  const pkgContent = await readFile24(pkgJsonPath, "utf-8");
43819
43999
  const parsed = JSON.parse(pkgContent);
43820
44000
  if (parsed && typeof parsed.name === "string") {
43821
- packageId = parsed.name;
44001
+ templateId = parsed.name;
43822
44002
  }
43823
44003
  } catch {
43824
44004
  }
43825
44005
  }
43826
44006
  }
43827
- if (!packageId) {
43828
- const errorMsg = "\u672A\u80FD\u81EA\u52A8\u8BC6\u522B\u6269\u5C55\u5305 ID\u3002\u8BF7\u786E\u4FDD\u5F53\u524D\u76EE\u5F55\u4E0B\u5B58\u5728\u6709\u6548\u7684 manifest.yaml \u6216 package.json\uFF0C\u6216\u4F7F\u7528 --package-id \u663E\u5F0F\u4F20\u5165\u3002";
44007
+ if (!templateId) {
44008
+ const errorMsg = t("extension.pipeline.idNotFound");
43829
44009
  if (output.json) {
43830
- emitFailureJson("extension pipeline", "PACKAGE_ID_NOT_FOUND", errorMsg);
44010
+ emitFailureJson("extension pipeline", "TEMPLATE_ID_NOT_FOUND", errorMsg);
43831
44011
  } else {
43832
- process.stderr.write(`error: PACKAGE_ID_NOT_FOUND: ${errorMsg}
44012
+ process.stderr.write(`error: TEMPLATE_ID_NOT_FOUND: ${errorMsg}
43833
44013
  `);
43834
44014
  }
43835
44015
  return ExitCode.ResolveFailed;
@@ -43837,15 +44017,16 @@ async function executeExtensionPipeline(directory, options) {
43837
44017
  if (existsSync5(ciFilePath) && !options.force) {
43838
44018
  if (isInteractive) {
43839
44019
  const overwrite = await dist_default5({
43840
- message: "\u68C0\u6D4B\u5230\u5F53\u524D\u76EE\u5F55\u5DF2\u5B58\u5728 .gitlab-ci.yml\uFF0C\u662F\u5426\u8986\u76D6\uFF1F",
44020
+ message: t("extension.pipeline.overwritePrompt"),
43841
44021
  default: false
43842
44022
  });
43843
44023
  if (!overwrite) {
43844
- process.stdout.write("\u64CD\u4F5C\u5DF2\u53D6\u6D88\uFF0C\u672A\u4FEE\u6539\u73B0\u6709\u6D41\u6C34\u7EBF\u914D\u7F6E\u3002\n");
44024
+ process.stdout.write(`${t("extension.pipeline.cancelled")}
44025
+ `);
43845
44026
  return ExitCode.Success;
43846
44027
  }
43847
44028
  } else {
43848
- const errorMsg = "\u5F53\u524D\u76EE\u5F55\u5DF2\u5B58\u5728 .gitlab-ci.yml\uFF0C\u5982\u9700\u8986\u76D6\u8BF7\u4F20\u9012 --force \u53C2\u6570\u3002";
44029
+ const errorMsg = t("extension.pipeline.alreadyExists");
43849
44030
  if (output.json) {
43850
44031
  emitFailureJson("extension pipeline", "FILE_ALREADY_EXISTS", errorMsg);
43851
44032
  } else {
@@ -43855,8 +44036,8 @@ async function executeExtensionPipeline(directory, options) {
43855
44036
  return ExitCode.ConflictOrDrift;
43856
44037
  }
43857
44038
  }
43858
- const ciContent = generateGitlabCiYaml(packageId);
43859
- await writeFile8(ciFilePath, ciContent, "utf-8");
44039
+ const ciContent = generateGitlabCiYaml(templateId);
44040
+ await writeFile9(ciFilePath, ciContent, "utf-8");
43860
44041
  let addedReleaseScript = false;
43861
44042
  if (existsSync5(pkgJsonPath)) {
43862
44043
  try {
@@ -43865,7 +44046,7 @@ async function executeExtensionPipeline(directory, options) {
43865
44046
  parsed.scripts = parsed.scripts || {};
43866
44047
  if (!parsed.scripts.release) {
43867
44048
  parsed.scripts.release = "npm version patch";
43868
- await writeFile8(pkgJsonPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
44049
+ await writeFile9(pkgJsonPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
43869
44050
  addedReleaseScript = true;
43870
44051
  }
43871
44052
  } catch {
@@ -43874,25 +44055,18 @@ async function executeExtensionPipeline(directory, options) {
43874
44055
  if (output.json) {
43875
44056
  emitSuccessJson("extension pipeline", {
43876
44057
  directory: targetDir,
43877
- packageId,
44058
+ templateId,
43878
44059
  ciFile: ciFilePath,
43879
44060
  addedReleaseScript
43880
44061
  });
43881
44062
  } else {
43882
- process.stdout.write(`\u2713 \u6210\u529F\u751F\u6210 CI/CD \u6D41\u6C34\u7EBF\u914D\u7F6E: ${ciFilePath}
44063
+ process.stdout.write(`${t("extension.pipeline.success", ciFilePath)}
43883
44064
  `);
43884
44065
  if (addedReleaseScript) {
43885
- process.stdout.write(`\u2713 \u5DF2\u5728 package.json \u7684 scripts \u4E2D\u6DFB\u52A0\u53D1\u7248\u547D\u4EE4: "release": "npm version patch"
44066
+ process.stdout.write(`${t("extension.pipeline.addedReleaseScript")}
43886
44067
  `);
43887
44068
  }
43888
- process.stdout.write("\n\u2699\uFE0F GitLab \u9879\u76EE\u914D\u7F6E\u63D0\u793A:\n");
43889
- process.stdout.write(" \u8BF7\u5728\u5F53\u524D\u6269\u5C55\u5305\u4ED3\u5E93\u7684\u3010Settings -> CI/CD -> Variables\u3011\u4E2D\u914D\u7F6E\u4EE5\u4E0B\u73AF\u5883\u53D8\u91CF\uFF1A\n");
43890
- process.stdout.write(" - REGISTRY_TRIGGER_TOKEN: Registry \u4ED3\u5E93\u751F\u6210\u7684 Pipeline Trigger Token\n");
43891
- process.stdout.write(" - REGISTRY_PROJECT_ID: Registry \u4ED3\u5E93\u5728 GitLab \u4E0A\u7684\u9879\u76EE ID\n");
43892
- process.stdout.write("\n\u{1F680} \u65E5\u5E38\u53D1\u7248\u5DE5\u4F5C\u6D41:\n");
43893
- process.stdout.write(' 1. \u63D0\u4EA4\u4EE3\u7801: git add . && git commit -m "feat: xxx"\n');
43894
- process.stdout.write(" 2. \u4E00\u952E\u63D0\u5347\u7248\u672C\u5E76\u6253 Tag: npm run release\n");
43895
- process.stdout.write(" 3. \u63A8\u9001\u5230\u8FDC\u7A0B\u89E6\u53D1\u81EA\u52A8\u5408\u5E76: git push --follow-tags origin main\n\n");
44069
+ process.stdout.write(t("extension.pipeline.gitlabNotice"));
43896
44070
  }
43897
44071
  return ExitCode.Success;
43898
44072
  }
@@ -43909,18 +44083,18 @@ var init_extension_pipeline = __esm({
43909
44083
  });
43910
44084
 
43911
44085
  // packages/cli/src/commands/extension-create.ts
43912
- import { mkdir as mkdir16, writeFile as writeFile9, readdir as readdir9 } from "node:fs/promises";
44086
+ import { mkdir as mkdir17, writeFile as writeFile10, readdir as readdir10 } from "node:fs/promises";
43913
44087
  import { basename as basename4, resolve as resolve15 } from "node:path";
43914
44088
  function createExtensionCreateCommand() {
43915
44089
  const cmd = new Command("create");
43916
- cmd.description(t("extension.create.description")).argument("<directory>", t("extension.create.argDirectory")).option("--name <package-id>", t("extension.create.optionName")).option("--template-name <name>", "\u6A21\u677F\u663E\u793A\u540D\u79F0 (name)").option("--description <description>", "\u6A21\u677F\u63CF\u8FF0").option("--with-tasks", "\u662F\u5426\u751F\u6210\u521D\u59CB\u5316\u4EFB\u52A1\u793A\u4F8B").option("--with-pipeline", t("extension.create.optionWithPipeline")).option("--category <category>", t("extension.create.optionCategory")).option("--with-project", t("extension.create.optionWithProject")).option("--with-capability <type>", t("extension.create.optionWithCapability"), collectCapability, []).option("--yes", t("extension.create.optionYes")).option("--json", t("global.json")).option("--no-color", t("global.noColor")).option("--verbose", t("global.verbose")).action(async (directory, opts) => {
44090
+ cmd.description(t("extension.create.description")).argument("<directory>", t("extension.create.argDirectory")).option("--name <package-id>", t("extension.create.optionName")).option("--template-name <name>", t("extension.create.optionTemplateName")).option("--description <description>", t("extension.create.optionDescription")).option("--with-tasks", t("extension.create.optionWithTasks")).option("--with-pipeline", t("extension.create.optionWithPipeline")).option("--category <category>", t("extension.create.optionCategory")).option("--with-project", t("extension.create.optionWithProject")).option("--with-capability <type>", t("extension.create.optionWithCapability"), collectCapability, []).option("--yes", t("extension.create.optionYes")).option("--json", t("global.json")).option("--no-color", t("global.noColor")).option("--verbose", t("global.verbose")).action(async (directory, opts) => {
43917
44091
  const options = {
43918
44092
  name: opts.name,
43919
44093
  templateName: opts.templateName,
43920
44094
  description: opts.description,
43921
44095
  category: opts.category,
43922
- withProject: Boolean(opts.withProject),
43923
- withTasks: Boolean(opts.withTasks),
44096
+ withProject: opts.withProject !== void 0 ? Boolean(opts.withProject) : void 0,
44097
+ withTasks: opts.withTasks !== void 0 ? Boolean(opts.withTasks) : void 0,
43924
44098
  withPipeline: opts.withPipeline !== void 0 ? Boolean(opts.withPipeline) : void 0,
43925
44099
  withCapability: Array.isArray(opts.withCapability) ? opts.withCapability : [],
43926
44100
  yes: Boolean(opts.yes),
@@ -43958,7 +44132,7 @@ async function executeExtensionCreate(directory, options) {
43958
44132
  const dirBase = basename4(targetDir);
43959
44133
  const isInteractive = !options.yes && !options.json && Boolean(process.stdin.isTTY);
43960
44134
  try {
43961
- const entries = await readdir9(targetDir);
44135
+ const entries = await readdir10(targetDir);
43962
44136
  if (entries.length > 0) {
43963
44137
  if (output.json) {
43964
44138
  emitFailureJson(
@@ -43979,7 +44153,7 @@ async function executeExtensionCreate(directory, options) {
43979
44153
  if (!packageId) {
43980
44154
  if (isInteractive) {
43981
44155
  packageId = await dist_default6({
43982
- message: "\u8BF7\u8F93\u5165\u6A21\u677F\u5305\u540D (Package ID):",
44156
+ message: t("extension.create.promptName"),
43983
44157
  default: sanitizePackageId(dirBase) || "my-template"
43984
44158
  });
43985
44159
  } else {
@@ -43990,7 +44164,7 @@ async function executeExtensionCreate(directory, options) {
43990
44164
  if (!templateName) {
43991
44165
  if (isInteractive) {
43992
44166
  templateName = await dist_default6({
43993
- message: "\u8BF7\u8F93\u5165\u6A21\u677F\u540D\u79F0 (Name):",
44167
+ message: t("extension.create.promptTemplateName"),
43994
44168
  default: packageId.replace(/^@[^/]+\//, "")
43995
44169
  });
43996
44170
  } else {
@@ -44001,34 +44175,52 @@ async function executeExtensionCreate(directory, options) {
44001
44175
  if (!description) {
44002
44176
  if (isInteractive) {
44003
44177
  description = await dist_default6({
44004
- message: "\u8BF7\u8F93\u5165\u6A21\u677F\u7B80\u8981\u63CF\u8FF0 (Description):",
44178
+ message: t("extension.create.promptDescription"),
44005
44179
  default: `${templateName} template for Mano Coding`
44006
44180
  });
44007
44181
  } else {
44008
44182
  description = `${templateName} template for Mano Coding`;
44009
44183
  }
44010
44184
  }
44185
+ let withProject = options.withProject;
44186
+ if (withProject === void 0 && isInteractive) {
44187
+ withProject = await dist_default5({
44188
+ message: t("extension.create.promptWithProject"),
44189
+ default: false
44190
+ });
44191
+ }
44011
44192
  let withTasks = options.withTasks;
44012
44193
  if (withTasks === void 0 && isInteractive) {
44013
44194
  withTasks = await dist_default5({
44014
- message: "\u662F\u5426\u5305\u542B\u9879\u76EE\u811A\u624B\u67B6\u521D\u59CB\u5316\u4EFB\u52A1 (Tasks) \u793A\u4F8B\uFF1F",
44195
+ message: t("extension.create.promptWithTasks"),
44015
44196
  default: true
44016
44197
  });
44017
44198
  }
44018
44199
  let withPipeline = options.withPipeline;
44019
44200
  if (withPipeline === void 0 && isInteractive) {
44020
44201
  withPipeline = await dist_default5({
44021
- message: "\u662F\u5426\u751F\u6210 GitLab CI/CD \u81EA\u52A8\u540C\u6B65\u6D41\u6C34\u7EBF\u914D\u7F6E (.gitlab-ci.yml)\uFF1F",
44202
+ message: t("extension.create.promptWithPipeline"),
44022
44203
  default: true
44023
44204
  });
44024
44205
  }
44025
- await mkdir16(targetDir, { recursive: true });
44206
+ await mkdir17(targetDir, { recursive: true });
44026
44207
  const scripts = {
44027
44208
  test: "vitest"
44028
44209
  };
44029
44210
  if (withPipeline) {
44030
44211
  scripts.release = "npm version patch";
44031
44212
  }
44213
+ const pkgFiles = [
44214
+ "manifest.yaml",
44215
+ "AGENTS.md",
44216
+ "skills",
44217
+ "rules",
44218
+ "mcp",
44219
+ "README.md"
44220
+ ];
44221
+ if (withProject) {
44222
+ pkgFiles.push("project");
44223
+ }
44032
44224
  const pkgJson = {
44033
44225
  name: packageId,
44034
44226
  version: "0.1.0",
@@ -44036,19 +44228,12 @@ async function executeExtensionCreate(directory, options) {
44036
44228
  type: "module",
44037
44229
  engines: { node: ">=22.0.0" },
44038
44230
  scripts,
44039
- files: [
44040
- "manifest.yaml",
44041
- "AGENTS.md",
44042
- "skills",
44043
- "rules",
44044
- "mcp",
44045
- "README.md"
44046
- ],
44231
+ files: pkgFiles,
44047
44232
  devDependencies: {
44048
44233
  vitest: "^3.0.5"
44049
44234
  }
44050
44235
  };
44051
- await writeFile9(resolve15(targetDir, "package.json"), JSON.stringify(pkgJson, null, 2) + "\n", "utf-8");
44236
+ await writeFile10(resolve15(targetDir, "package.json"), JSON.stringify(pkgJson, null, 2) + "\n", "utf-8");
44052
44237
  const manifestLines = [
44053
44238
  `id: "${packageId}"`,
44054
44239
  "version: 0.1.0",
@@ -44070,7 +44255,7 @@ async function executeExtensionCreate(directory, options) {
44070
44255
  manifestLines.push(" on:");
44071
44256
  manifestLines.push(" - after:create");
44072
44257
  }
44073
- await writeFile9(resolve15(targetDir, "manifest.yaml"), manifestLines.join("\n") + "\n", "utf-8");
44258
+ await writeFile10(resolve15(targetDir, "manifest.yaml"), manifestLines.join("\n") + "\n", "utf-8");
44074
44259
  const agentsMdContent = `# ${templateName} Agent \u6307\u5357
44075
44260
 
44076
44261
  \u672C\u9879\u76EE\u57FA\u4E8E ${templateName} \u6A21\u677F\u6784\u5EFA\u3002\u5728\u8FDB\u884C AI \u8F85\u52A9\u7F16\u7801\u65F6\uFF0C\u8BF7\u9075\u5FAA\u4EE5\u4E0B\u6838\u5FC3\u539F\u5219\u4E0E\u7EA6\u5B9A\uFF1A
@@ -44082,9 +44267,9 @@ async function executeExtensionCreate(directory, options) {
44082
44267
  ## 2. \u4EA4\u4E92\u4E0E\u6CE8\u91CA
44083
44268
  - \u4EE3\u7801\u6CE8\u91CA\u4E0E\u56DE\u7B54\u8BF7\u59CB\u7EC8\u4F7F\u7528\u7B80\u4F53\u4E2D\u6587\u3002
44084
44269
  `;
44085
- await writeFile9(resolve15(targetDir, "AGENTS.md"), agentsMdContent, "utf-8");
44270
+ await writeFile10(resolve15(targetDir, "AGENTS.md"), agentsMdContent, "utf-8");
44086
44271
  const skillDir = resolve15(targetDir, "skills", "example-skill");
44087
- await mkdir16(skillDir, { recursive: true });
44272
+ await mkdir17(skillDir, { recursive: true });
44088
44273
  const skillContent = `---
44089
44274
  name: example-skill
44090
44275
  description: ${templateName} \u793A\u4F8B Agent \u6280\u80FD\uFF0C\u6307\u5BFC AI \u6309\u7167\u6700\u4F73\u5B9E\u8DF5\u5B8C\u6210\u7279\u5B9A\u4EFB\u52A1
@@ -44100,9 +44285,9 @@ description: ${templateName} \u793A\u4F8B Agent \u6280\u80FD\uFF0C\u6307\u5BFC A
44100
44285
  2. \u9075\u5FAA\u672C\u9879\u76EE\u7684\u67B6\u6784\u8BBE\u8BA1\u539F\u5219\u5B9E\u73B0\u4EE3\u7801\u3002
44101
44286
  3. \u7F16\u5199\u5BF9\u5E94\u6D4B\u8BD5\u5E76\u9A8C\u8BC1\u3002
44102
44287
  `;
44103
- await writeFile9(resolve15(skillDir, "SKILL.md"), skillContent, "utf-8");
44288
+ await writeFile10(resolve15(skillDir, "SKILL.md"), skillContent, "utf-8");
44104
44289
  const cursorRulesDir = resolve15(targetDir, "rules", "cursor");
44105
- await mkdir16(cursorRulesDir, { recursive: true });
44290
+ await mkdir17(cursorRulesDir, { recursive: true });
44106
44291
  const cursorRuleContent = `---
44107
44292
  description: ${templateName} Cursor \u7F16\u7801\u89C4\u5219
44108
44293
  globs: *
@@ -44114,17 +44299,17 @@ alwaysApply: false
44114
44299
  - \u4F18\u5148\u4F7F\u7528\u73B0\u6709\u7684\u8BBE\u8BA1\u7CFB\u7EDF\u548C\u516C\u5171\u7EC4\u4EF6\u3002
44115
44300
  - \u4FDD\u6301\u51FD\u6570\u4E0E\u6A21\u5757\u7B80\u6D01\uFF0C\u5355\u4E00\u804C\u8D23\u3002
44116
44301
  `;
44117
- await writeFile9(resolve15(cursorRulesDir, "example-rule.mdc"), cursorRuleContent, "utf-8");
44302
+ await writeFile10(resolve15(cursorRulesDir, "example-rule.mdc"), cursorRuleContent, "utf-8");
44118
44303
  const codebuddyRulesDir = resolve15(targetDir, "rules", "codebuddy");
44119
- await mkdir16(codebuddyRulesDir, { recursive: true });
44304
+ await mkdir17(codebuddyRulesDir, { recursive: true });
44120
44305
  const codebuddyRuleContent = `# ${templateName} \u7F16\u7801\u89C4\u5219 (CodeBuddy)
44121
44306
 
44122
44307
  - \u9075\u5FAA\u4EE3\u7801\u8BBE\u8BA1\u539F\u5219\u3002
44123
44308
  - \u5355\u5143\u6D4B\u8BD5\u8986\u76D6\u6838\u5FC3\u903B\u8F91\u5206\u652F\u3002
44124
44309
  `;
44125
- await writeFile9(resolve15(codebuddyRulesDir, "example-rule.md"), codebuddyRuleContent, "utf-8");
44310
+ await writeFile10(resolve15(codebuddyRulesDir, "example-rule.md"), codebuddyRuleContent, "utf-8");
44126
44311
  const mcpDir = resolve15(targetDir, "mcp");
44127
- await mkdir16(mcpDir, { recursive: true });
44312
+ await mkdir17(mcpDir, { recursive: true });
44128
44313
  const mcpJsonContent = {
44129
44314
  mcpServers: {
44130
44315
  "example-server": {
@@ -44133,9 +44318,9 @@ alwaysApply: false
44133
44318
  }
44134
44319
  }
44135
44320
  };
44136
- await writeFile9(resolve15(mcpDir, "mcp.json"), JSON.stringify(mcpJsonContent, null, 2) + "\n", "utf-8");
44321
+ await writeFile10(resolve15(mcpDir, "mcp.json"), JSON.stringify(mcpJsonContent, null, 2) + "\n", "utf-8");
44137
44322
  const testDir = resolve15(targetDir, "test");
44138
- await mkdir16(testDir, { recursive: true });
44323
+ await mkdir17(testDir, { recursive: true });
44139
44324
  const testContent = `import { describe, expect, it } from 'vitest';
44140
44325
  import { readFile } from 'node:fs/promises';
44141
44326
  import { resolve } from 'node:path';
@@ -44148,7 +44333,7 @@ describe('${packageId} template manifest', () => {
44148
44333
  });
44149
44334
  });
44150
44335
  `;
44151
- await writeFile9(resolve15(testDir, "manifest.test.ts"), testContent, "utf-8");
44336
+ await writeFile10(resolve15(testDir, "manifest.test.ts"), testContent, "utf-8");
44152
44337
  const createdFiles = [
44153
44338
  "manifest.yaml",
44154
44339
  "AGENTS.md",
@@ -44160,8 +44345,52 @@ describe('${packageId} template manifest', () => {
44160
44345
  "package.json",
44161
44346
  "test/manifest.test.ts"
44162
44347
  ];
44348
+ if (withProject) {
44349
+ const projectDir = resolve15(targetDir, "project");
44350
+ const projectSrcDir = resolve15(projectDir, "src");
44351
+ await mkdir17(projectSrcDir, { recursive: true });
44352
+ const starterPkgName = `${packageId.replace(/^@[^/]+\//, "")}-starter`;
44353
+ const projectPkgJson = {
44354
+ name: starterPkgName,
44355
+ version: "0.1.0",
44356
+ private: true,
44357
+ type: "module",
44358
+ scripts: {
44359
+ dev: "vite",
44360
+ build: "vite build"
44361
+ }
44362
+ };
44363
+ await writeFile10(
44364
+ resolve15(projectDir, "package.json"),
44365
+ JSON.stringify(projectPkgJson, null, 2) + "\n",
44366
+ "utf-8"
44367
+ );
44368
+ const projectReadme = `# ${starterPkgName}
44369
+
44370
+ \u8FD9\u662F\u4E00\u4E2A\u7531 ${packageId} \u6A21\u677F\u63D0\u4F9B\u7684\u521D\u59CB\u5DE5\u7A0B\u811A\u624B\u67B6\uFF08\u9879\u76EE\u9AA8\u67B6\u79CD\u5B50\uFF09\u3002
44371
+
44372
+ \u5728\u6267\u884C \`mano-coding create\` \u65F6\uFF0C\u6B64\u76EE\u5F55\u4E2D\u7684\u6587\u4EF6\u5C06\u81EA\u52A8\u91CA\u653E\u5230\u76EE\u6807\u5DE5\u7A0B\u6839\u76EE\u5F55\u3002
44373
+ \u6CE8\u610F\uFF1A\u672C\u76EE\u5F55\u4E2D\u7684\u9759\u6001\u5DE5\u7A0B\u811A\u624B\u67B6\u6587\u4EF6\u4E3A bootstrap \u8D44\u6E90\uFF0C\u4E0D\u7EB3\u5165 \`.ai-coding.lock\` \u53D7\u7BA1\u8D44\u4EA7\u8DDF\u8E2A\u3002
44374
+ `;
44375
+ await writeFile10(resolve15(projectDir, "README.md"), projectReadme, "utf-8");
44376
+ const projectIndexTs = `/**
44377
+ * ${starterPkgName} \u5165\u53E3\u6587\u4EF6
44378
+ */
44379
+ export function main(): void {
44380
+ console.log('Hello from ${starterPkgName}!');
44381
+ }
44382
+
44383
+ main();
44384
+ `;
44385
+ await writeFile10(resolve15(projectSrcDir, "index.ts"), projectIndexTs, "utf-8");
44386
+ createdFiles.push(
44387
+ "project/package.json",
44388
+ "project/README.md",
44389
+ "project/src/index.ts"
44390
+ );
44391
+ }
44163
44392
  if (withPipeline) {
44164
- await writeFile9(
44393
+ await writeFile10(
44165
44394
  resolve15(targetDir, ".gitlab-ci.yml"),
44166
44395
  generateGitlabCiYaml(packageId),
44167
44396
  "utf-8"
@@ -44173,9 +44402,10 @@ describe('${packageId} template manifest', () => {
44173
44402
  templateName,
44174
44403
  description,
44175
44404
  withTasks: Boolean(withTasks),
44176
- withPipeline: Boolean(withPipeline)
44405
+ withPipeline: Boolean(withPipeline),
44406
+ withProject: Boolean(withProject)
44177
44407
  });
44178
- await writeFile9(resolve15(targetDir, "README.md"), readmeContent, "utf-8");
44408
+ await writeFile10(resolve15(targetDir, "README.md"), readmeContent, "utf-8");
44179
44409
  if (output.json) {
44180
44410
  emitSuccessJson("extension create", {
44181
44411
  directory: targetDir,
@@ -44183,9 +44413,9 @@ describe('${packageId} template manifest', () => {
44183
44413
  files: createdFiles
44184
44414
  });
44185
44415
  } else {
44186
- process.stdout.write(`\u2713 \u6210\u529F\u521D\u59CB\u5316\u6A21\u677F\u5DE5\u7A0B: ${targetDir}
44416
+ process.stdout.write(`${t("extension.create.success", targetDir)}
44187
44417
  `);
44188
- process.stdout.write(`\u5DF2\u751F\u6210\u6587\u4EF6\u6E05\u5355:
44418
+ process.stdout.write(`${t("extension.create.generatedFiles")}
44189
44419
  - ${createdFiles.join("\n - ")}
44190
44420
  `);
44191
44421
  }
@@ -44220,6 +44450,21 @@ git push --follow-tags origin main
44220
44450
  mano-coding extension pipeline .
44221
44451
  \`\`\`
44222
44452
  `;
44453
+ const projectSection = options.withProject ? `
44454
+ ---
44455
+
44456
+ ## \u9759\u6001\u5DE5\u7A0B\u811A\u624B\u67B6 (project/ \u76EE\u5F55)
44457
+
44458
+ \u672C\u6A21\u677F\u5305\u542B\u9759\u6001\u5DE5\u7A0B\u811A\u624B\u67B6\u76EE\u5F55 \`project/\`\uFF1A
44459
+ - \u6267\u884C \`mano-coding create <\u9879\u76EE\u540D> --template <\u672C\u6A21\u677F>\` \u65F6\uFF0C\`project/\` \u4E0B\u7684\u6587\u4EF6\u5C06\u81EA\u52A8\u590D\u5236\u5230\u65B0\u5EFA\u5DE5\u7A0B\u6839\u76EE\u5F55\uFF0C\u4F5C\u4E3A\u521D\u59CB\u6E90\u4EE3\u7801\u9AA8\u67B6\u3002
44460
+ - \u9759\u6001\u5DE5\u7A0B\u6587\u4EF6\u4F5C\u4E3A bootstrap \u79CD\u5B50\u8D44\u6E90\uFF0C\u4E0D\u4F1A\u8BA1\u5165 \`.ai-coding.lock\` \u53D7\u7BA1\u6E05\u5355\uFF0C\u540E\u7EED\u6267\u884C \`apply\` \u6216 \`sync\` \u65F6\u4E0D\u4F1A\u8986\u76D6\u7528\u6237\u5BF9\u5DE5\u7A0B\u6587\u4EF6\u7684\u4FEE\u6539\u3002
44461
+ ` : "";
44462
+ const projectTree = options.withProject ? `\u251C\u2500\u2500 project/ # [\u53EF\u9009] \u9759\u6001\u5DE5\u7A0B\u811A\u624B\u67B6\u79CD\u5B50\u76EE\u5F55\uFF08\u5728 create \u65F6\u91CA\u653E\u5230\u9879\u76EE\u6839\u76EE\u5F55\uFF0C\u4F5C\u4E3A\u521D\u59CB\u6E90\u7801\u6846\u67B6\uFF09
44463
+ \u2502 \u251C\u2500\u2500 package.json
44464
+ \u2502 \u251C\u2500\u2500 README.md
44465
+ \u2502 \u2514\u2500\u2500 src/
44466
+ \u2502 \u2514\u2500\u2500 index.ts
44467
+ ` : "";
44223
44468
  return `# ${options.templateName} (\`${options.packageId}\`)
44224
44469
 
44225
44470
  ${options.description}
@@ -44235,7 +44480,7 @@ ${options.description}
44235
44480
  \`\`\`text
44236
44481
  \u251C\u2500\u2500 manifest.yaml # \u6A21\u677F\u58F0\u660E\u6E05\u5355\uFF08\u5143\u6570\u636E\u4E0E\u53EF\u9009\u7684\u4EFB\u52A1\uFF09
44237
44482
  \u251C\u2500\u2500 AGENTS.md # \u9879\u76EE\u7EA7\u901A\u7528 AI \u7F16\u7801\u6307\u5BFC\uFF0C\u5B89\u88C5\u65F6\u81EA\u52A8\u590D\u5236\u5230\u9879\u76EE\u6839\u76EE\u5F55
44238
- \u251C\u2500\u2500 skills/ # \u8DE8 IDE \u53EF\u590D\u7528\u7684 Agent Skills\uFF08\u4E00\u9879 Skill \u4E00\u4E2A\u5B50\u76EE\u5F55\uFF09
44483
+ ${projectTree}\u251C\u2500\u2500 skills/ # \u8DE8 IDE \u53EF\u590D\u7528\u7684 Agent Skills\uFF08\u4E00\u9879 Skill \u4E00\u4E2A\u5B50\u76EE\u5F55\uFF09
44239
44484
  \u2502 \u2514\u2500\u2500 example-skill/
44240
44485
  \u2502 \u2514\u2500\u2500 SKILL.md
44241
44486
  \u251C\u2500\u2500 rules/ # IDE \u539F\u751F\u89C4\u5219\u76EE\u5F55
@@ -44246,7 +44491,7 @@ ${options.description}
44246
44491
  \u2502 \u2514\u2500\u2500 mcp.json # \u8FDC\u7AEF Streamable HTTP MCP \u670D\u52A1\u5668\u914D\u7F6E
44247
44492
  \u251C\u2500\u2500 README.md # \u6A21\u677F\u4F7F\u7528\u4E0E\u5F00\u53D1\u6587\u6863
44248
44493
  \u2514\u2500\u2500 package.json # \u6A21\u677F\u5305\u914D\u7F6E
44249
- \`\`\`
44494
+ \`\`\`${projectSection}
44250
44495
 
44251
44496
  ---
44252
44497
 
@@ -44481,7 +44726,7 @@ var init_shared_options = __esm({
44481
44726
 
44482
44727
  // packages/cli/src/commands/extension-dev.ts
44483
44728
  import { mkdtemp as mkdtemp6, readFile as readFile25 } from "node:fs/promises";
44484
- import { tmpdir as tmpdir6 } from "node:os";
44729
+ import { tmpdir as tmpdir7 } from "node:os";
44485
44730
  import { join as join20, resolve as resolvePath9, relative as relative8, isAbsolute as isAbsolute6, sep as sep4 } from "node:path";
44486
44731
  function createExtensionDevCommand() {
44487
44732
  const cmd = new Command("dev");
@@ -44536,7 +44781,7 @@ async function executeExtensionDev(packageDirectory, options) {
44536
44781
  return ExitCode.SchemaInvalid;
44537
44782
  }
44538
44783
  const effectiveDryRun = options.dryRun || options.watch;
44539
- const isolatedUserData = await mkdtemp6(join20(tmpdir6(), "aicoding-dev-userdata-"));
44784
+ const isolatedUserData = await mkdtemp6(join20(tmpdir7(), "aicoding-dev-userdata-"));
44540
44785
  const prevUserData = process.env["AICODING_USER_DATA"];
44541
44786
  process.env["AICODING_USER_DATA"] = isolatedUserData;
44542
44787
  try {
@@ -44556,7 +44801,7 @@ async function executeExtensionDev(packageDirectory, options) {
44556
44801
  argv.push("--source-type", "local");
44557
44802
  argv.push("--source-path", sourcePath);
44558
44803
  }
44559
- if (options.operation === "remove" && packageId) argv.push("--package", packageId);
44804
+ if (options.operation === "remove" && packageId) argv.push("--template", packageId);
44560
44805
  for (const target of options.target) {
44561
44806
  argv.push("--target", target);
44562
44807
  }
@@ -44776,7 +45021,7 @@ var init_extension_test = __esm({
44776
45021
  });
44777
45022
 
44778
45023
  // packages/cli/src/commands/extension-pack.ts
44779
- import { readFile as readFile27, mkdir as mkdir17 } from "node:fs/promises";
45024
+ import { readFile as readFile27, mkdir as mkdir18 } from "node:fs/promises";
44780
45025
  import { resolve as resolve17, join as join21, dirname as dirname15 } from "node:path";
44781
45026
  import { execFile as execFile4 } from "node:child_process";
44782
45027
  import { promisify as promisify5 } from "node:util";
@@ -44926,7 +45171,7 @@ async function executeExtensionPack(packageDirectory, options, cliVersion) {
44926
45171
  }
44927
45172
  }
44928
45173
  const outputDir = options.output ? resolve17(options.output) : resolve17(pkgDir, "dist-package");
44929
- await mkdir17(outputDir, { recursive: true });
45174
+ await mkdir18(outputDir, { recursive: true });
44930
45175
  let tarballName;
44931
45176
  let tarballPath;
44932
45177
  tarballName = `${pkgName.replace(/^@/, "").replace(/\//g, "-")}-${pkgVersion}.tgz`;
@@ -45170,7 +45415,7 @@ var init_extension_submit = __esm({
45170
45415
  });
45171
45416
 
45172
45417
  // packages/cli/src/commands/extension-adapter.ts
45173
- import { readFile as readFile29, mkdir as mkdir18 } from "node:fs/promises";
45418
+ import { readFile as readFile29, mkdir as mkdir19 } from "node:fs/promises";
45174
45419
  import { dirname as dirname16, resolve as resolve19 } from "node:path";
45175
45420
  import { execFile as execFile5 } from "node:child_process";
45176
45421
  import { promisify as promisify6 } from "node:util";
@@ -45514,7 +45759,7 @@ async function executeAdapterPack(packageDirectory, options) {
45514
45759
  return ExitCode.SchemaInvalid;
45515
45760
  }
45516
45761
  const outputDir = options.output ? resolve19(options.output) : resolve19(pkgDir, "dist-package");
45517
- await mkdir18(outputDir, { recursive: true });
45762
+ await mkdir19(outputDir, { recursive: true });
45518
45763
  const tarballName = `${pkgName.replace(/^@/, "").replace(/\//g, "-")}-${pkgVersion}.tgz`;
45519
45764
  const tarballPath = resolve19(outputDir, tarballName);
45520
45765
  try {
@@ -45910,7 +46155,7 @@ var init_service_locator = __esm({
45910
46155
  });
45911
46156
 
45912
46157
  // packages/cli/src/commands/plan-execution.ts
45913
- import { readFile as readFile30, readdir as readdir10, stat as stat7 } from "node:fs/promises";
46158
+ import { readFile as readFile30, readdir as readdir11, stat as stat7 } from "node:fs/promises";
45914
46159
  import { join as join23, resolve as resolve21 } from "node:path";
45915
46160
  import { createHash as createHash15 } from "node:crypto";
45916
46161
  async function buildIntentsFromPlan(_plan, resolutions, service, projectTargets, _userInstallationKeys, options) {
@@ -45925,9 +46170,15 @@ async function buildIntentsFromPlan(_plan, resolutions, service, projectTargets,
45925
46170
  templateDir: packageRoot,
45926
46171
  projectRoot: service.projectRoot,
45927
46172
  targets: projectTargets.map((t2) => t2.id),
45928
- filter: options?.filter
46173
+ filter: {
46174
+ ...options?.filter,
46175
+ skipProjectDir: options?.skipProjectDir ?? options?.filter?.skipProjectDir
46176
+ }
45929
46177
  });
45930
- intents.push(...contractIntents);
46178
+ intents.push(...contractIntents.map((intent) => ({
46179
+ ...intent,
46180
+ packageId: manifest.id
46181
+ })));
45931
46182
  for (const asset of manifest.assets ?? []) {
45932
46183
  if (options?.skipProjectDir && (asset.source === "project" || asset.source.startsWith("project/"))) {
45933
46184
  options.onDiscloseSkipped?.(`\u8DF3\u8FC7\u8D44\u4EA7 '${asset.source}' (\u7531\u4E8E\u547D\u4EE4\u8BED\u4E49\u4E0D\u4EA4\u4ED8 project \u76EE\u5F55)`);
@@ -46026,7 +46277,7 @@ async function collectAssetIntents(packageRoot, source, destination, metadata) {
46026
46277
  }
46027
46278
  if (!sourceStat.isDirectory()) throw new Error(`Asset '${source}' \u65E2\u4E0D\u662F\u6587\u4EF6\u4E5F\u4E0D\u662F\u76EE\u5F55`);
46028
46279
  const intents = [];
46029
- for (const entry of await readdir10(sourcePath, { withFileTypes: true })) {
46280
+ for (const entry of await readdir11(sourcePath, { withFileTypes: true })) {
46030
46281
  intents.push(...await collectAssetIntents(packageRoot, join23(source, entry.name), join23(destination, entry.name).replaceAll("\\", "/"), metadata));
46031
46282
  }
46032
46283
  return intents;
@@ -46102,7 +46353,7 @@ function summarizePlan(plan) {
46102
46353
  function printPlanSummary(s3) {
46103
46354
  writeHumanOutput(`\u6267\u884C\u6458\u8981\uFF1A
46104
46355
  \u64CD\u4F5C\uFF1A${s3.operation}
46105
- \u6269\u5C55\u5305\uFF1A${s3.packageCount}
46356
+ \u6A21\u677F\uFF1A${s3.packageCount}
46106
46357
  \u6587\u4EF6\uFF1A${s3.fileCount}
46107
46358
  \u914D\u7F6E\u9879\uFF1A${s3.configEntryCount}
46108
46359
  \u63D2\u4EF6\uFF1A${s3.pluginCount}
@@ -46207,11 +46458,28 @@ async function buildLock(_operation, templateResolution, addonResolutions, proje
46207
46458
  });
46208
46459
  }
46209
46460
  const resources = /* @__PURE__ */ new Map();
46461
+ if (existingLock?.resources) {
46462
+ for (const res of existingLock.resources) {
46463
+ const key = `${res.target}:${res.path}:${res.selector ?? ""}`;
46464
+ resources.set(key, { ...res, owners: [...res.owners] });
46465
+ }
46466
+ }
46210
46467
  for (const intent of intents) {
46211
- if (intent.action === "remove") continue;
46468
+ if (intent.assetType === "project-seed") continue;
46212
46469
  if (!intent.target) continue;
46213
46470
  const targetId = typeof intent.target === "string" ? intent.target : intent.target.id;
46214
46471
  const selector = (intent.type === "config-entry" ? intent.selector : intent.type === "managed-section" ? intent.sectionId : null) ?? null;
46472
+ const key = `${targetId}:${intent.path}:${selector ?? ""}`;
46473
+ if (intent.action === "remove") {
46474
+ const existing2 = resources.get(key);
46475
+ if (existing2) {
46476
+ existing2.owners = existing2.owners.filter((o) => o.packageId !== intent.packageId);
46477
+ if (existing2.owners.length === 0) {
46478
+ resources.delete(key);
46479
+ }
46480
+ }
46481
+ continue;
46482
+ }
46215
46483
  let digest = intent.digest ?? "";
46216
46484
  if (!digest) {
46217
46485
  if (intent.type === "file") {
@@ -46222,7 +46490,6 @@ async function buildLock(_operation, templateResolution, addonResolutions, proje
46222
46490
  digest = computeStringDigest(intent.content ?? "");
46223
46491
  }
46224
46492
  }
46225
- const key = `${targetId}:${intent.path}:${selector ?? ""}`;
46226
46493
  const owner = {
46227
46494
  packageId: intent.packageId ?? templateResolution?.packageId ?? addonResolutions[0]?.packageId ?? "unknown",
46228
46495
  assetType: intent.assetType ?? (intent.type === "file" ? "rule" : "config"),
@@ -46234,6 +46501,11 @@ async function buildLock(_operation, templateResolution, addonResolutions, proje
46234
46501
  if (!existing.owners.some((o) => o.packageId === owner.packageId && o.assetType === owner.assetType && o.assetId === owner.assetId)) {
46235
46502
  existing.owners.push(owner);
46236
46503
  }
46504
+ } else {
46505
+ existing.hash = digest;
46506
+ if (!existing.owners.some((o) => o.packageId === owner.packageId && o.assetType === owner.assetType && o.assetId === owner.assetId)) {
46507
+ existing.owners.push(owner);
46508
+ }
46237
46509
  }
46238
46510
  continue;
46239
46511
  }
@@ -46339,7 +46611,8 @@ function toInquirerChoices(choices) {
46339
46611
  return choices.map((choice) => ({
46340
46612
  value: choice,
46341
46613
  name: choice.label ?? choice.id,
46342
- description: choice.description
46614
+ description: choice.description,
46615
+ checked: choice.checked
46343
46616
  }));
46344
46617
  }
46345
46618
  function toContext(options) {
@@ -46501,6 +46774,85 @@ var init_spinner = __esm({
46501
46774
  }
46502
46775
  });
46503
46776
 
46777
+ // packages/cli/src/commands/task-helper.ts
46778
+ async function runTasksWithDynamicUI(tasks, ctx, options = {}) {
46779
+ if (tasks.length === 0) return;
46780
+ const isInteractive = !options.json && !options.verbose && Boolean(process.stdout.isTTY) && process.env.NODE_ENV !== "test";
46781
+ if (!options.json && options.title) {
46782
+ writeHumanOutput(`
46783
+ ${options.title}
46784
+ `);
46785
+ }
46786
+ if (isInteractive) {
46787
+ let currentSpinner = null;
46788
+ try {
46789
+ await executeTasks(tasks, ctx, {
46790
+ verbose: false,
46791
+ onTaskStart: (task, index, total) => {
46792
+ const taskLabel = task.name ? `${task.name} (${task.id})` : task.id;
46793
+ currentSpinner = new Spinner(`[${index + 1}/${total}] \u6B63\u5728\u6267\u884C\u4EFB\u52A1: ${taskLabel}...`);
46794
+ currentSpinner.start();
46795
+ },
46796
+ onTaskSuccess: (task, index, total) => {
46797
+ const taskLabel = task.name ? `${task.name}` : task.id;
46798
+ if (currentSpinner) {
46799
+ currentSpinner.succeed(`[${index + 1}/${total}] \u4EFB\u52A1\u5B8C\u6210: ${taskLabel}`);
46800
+ }
46801
+ },
46802
+ onTaskFail: (task, index, total, _error, logFile) => {
46803
+ const taskLabel = task.name ? `${task.name}` : task.id;
46804
+ if (currentSpinner) {
46805
+ currentSpinner.fail(`[${index + 1}/${total}] \u4EFB\u52A1\u6267\u884C\u5931\u8D25: ${taskLabel}`);
46806
+ }
46807
+ if (logFile) {
46808
+ writeHumanOutput(` \u8BE6\u7EC6\u65E5\u5FD7\u5DF2\u4FDD\u5B58\u81F3: ${logFile}
46809
+ `);
46810
+ }
46811
+ }
46812
+ });
46813
+ } catch (err) {
46814
+ currentSpinner?.stop();
46815
+ throw err;
46816
+ }
46817
+ } else {
46818
+ await executeTasks(tasks, ctx, {
46819
+ verbose: Boolean(options.verbose),
46820
+ stdio: options.json ? "ignore" : void 0,
46821
+ onTaskStart: (task, index, total) => {
46822
+ if (!options.json && options.verbose) {
46823
+ writeHumanOutput(`
46824
+ > [${index + 1}/${total}] \u5F00\u59CB\u6267\u884C\u4EFB\u52A1: ${task.name ?? task.id}
46825
+ `);
46826
+ }
46827
+ },
46828
+ onTaskSuccess: (task, index, total) => {
46829
+ if (!options.json && !options.verbose) {
46830
+ writeHumanOutput(`\u2714 [${index + 1}/${total}] \u4EFB\u52A1\u5B8C\u6210: ${task.name ?? task.id}
46831
+ `);
46832
+ }
46833
+ },
46834
+ onTaskFail: (task, index, total, _err, logFile) => {
46835
+ if (!options.json) {
46836
+ writeHumanOutput(`\u2716 [${index + 1}/${total}] \u4EFB\u52A1\u6267\u884C\u5931\u8D25: ${task.name ?? task.id}
46837
+ `);
46838
+ if (logFile) {
46839
+ writeHumanOutput(` \u8BE6\u7EC6\u65E5\u5FD7\u5DF2\u4FDD\u5B58\u81F3: ${logFile}
46840
+ `);
46841
+ }
46842
+ }
46843
+ }
46844
+ });
46845
+ }
46846
+ }
46847
+ var init_task_helper = __esm({
46848
+ "packages/cli/src/commands/task-helper.ts"() {
46849
+ "use strict";
46850
+ init_spinner();
46851
+ init_src2();
46852
+ init_cli_output();
46853
+ }
46854
+ });
46855
+
46504
46856
  // packages/cli/src/commands/tty-confirm.ts
46505
46857
  var tty_confirm_exports = {};
46506
46858
  __export(tty_confirm_exports, {
@@ -46646,10 +46998,11 @@ import { randomUUID as randomUUID6 } from "node:crypto";
46646
46998
  import { unlink as unlink9 } from "node:fs/promises";
46647
46999
  function createCreateCommand(cliVersion) {
46648
47000
  const cmd = new Command("create");
46649
- cmd.description(t("create.description")).argument("[package-spec]", t("create.argPackageSpec")).argument("[directory]", t("create.argDirectory")).option("--package <package-spec>", t("create.optionPackage"), collectPackage, []).option("--template <package-spec>", t("create.optionTemplate")).option("--addon <package-spec>", t("create.optionAddon"), collectPackage, []).action(async (packageSpec, directory, opts) => {
47001
+ cmd.description(t("create.description")).argument("[template-spec]", t("create.argTemplateSpec")).argument("[directory]", t("create.argDirectory")).option("--template <template-spec>", t("create.optionTemplate"), collectTemplate, []).action(async (templateSpec, directory, opts) => {
47002
+ const templateOptions = Array.isArray(opts.template) ? opts.template : [];
46650
47003
  const options = {
46651
47004
  ...extractMutationOptions(opts),
46652
- packages: Array.isArray(opts.package) ? opts.package : []
47005
+ templates: templateOptions
46653
47006
  };
46654
47007
  const output = {
46655
47008
  json: options.json,
@@ -46659,7 +47012,7 @@ function createCreateCommand(cliVersion) {
46659
47012
  if (options.only || options.skip) {
46660
47013
  reportCliError(
46661
47014
  new CliError(
46662
- "create \u547D\u4EE4\u4E0D\u652F\u6301 --only / --skip \u8D44\u4EA7\u8FC7\u6EE4\uFF0C\u4EE5\u4FDD\u8BC1\u6A21\u677F\u5B8C\u6574\u4EA4\u4ED8\u3002\u5982\u9700\u5B9A\u5236\u53D7\u7BA1\u8D44\u4EA7\u8BF7\u4F7F\u7528 apply \u547D\u4EE4\u3002",
47015
+ t("create.filterUnsupported"),
46663
47016
  ExitCode.SchemaInvalid,
46664
47017
  "UNSUPPORTED_OPTION"
46665
47018
  ),
@@ -46669,27 +47022,21 @@ function createCreateCommand(cliVersion) {
46669
47022
  process.exitCode = ExitCode.SchemaInvalid;
46670
47023
  return;
46671
47024
  }
46672
- const rawPackages = [
46673
- ...Array.isArray(opts.package) ? opts.package : [],
46674
- ...Array.isArray(opts.addon) ? opts.addon : []
46675
- ];
46676
- if (typeof opts.template === "string" && opts.template.trim().length > 0) {
46677
- rawPackages.push(opts.template.trim());
46678
- }
46679
- let effectivePackages = [...rawPackages];
47025
+ const rawTemplates = [...templateOptions];
47026
+ let effectiveTemplates = [...rawTemplates];
46680
47027
  let effectiveDirectory = directory;
46681
- if (rawPackages.length > 0) {
46682
- if (packageSpec && !directory) {
46683
- effectiveDirectory = packageSpec;
47028
+ if (rawTemplates.length > 0) {
47029
+ if (templateSpec && !directory) {
47030
+ effectiveDirectory = templateSpec;
46684
47031
  }
46685
47032
  } else {
46686
- if (packageSpec) {
46687
- effectivePackages.push(packageSpec);
47033
+ if (templateSpec) {
47034
+ effectiveTemplates.push(templateSpec);
46688
47035
  }
46689
47036
  }
46690
47037
  const events = createEventEmitter("create", output);
46691
47038
  const exitCode = await executeCreate(
46692
- effectivePackages,
47039
+ effectiveTemplates,
46693
47040
  effectiveDirectory,
46694
47041
  options,
46695
47042
  cliVersion,
@@ -46707,7 +47054,7 @@ function createCreateCommand(cliVersion) {
46707
47054
  addMutationOptions(cmd);
46708
47055
  return cmd;
46709
47056
  }
46710
- function collectPackage(value, previous = []) {
47057
+ function collectTemplate(value, previous = []) {
46711
47058
  return previous.concat(value);
46712
47059
  }
46713
47060
  async function executeCreate(packageSpecs, directory, options, cliVersion, events) {
@@ -46748,7 +47095,7 @@ async function executeCreate(packageSpecs, directory, options, cliVersion, event
46748
47095
  const allResolutions = [];
46749
47096
  for (const spec of packageSpecs) {
46750
47097
  const resolution = await events.measure("resolve", () => withSpinner(
46751
- `\u6B63\u5728\u62C9\u53D6\u5E76\u89E3\u6790\u6269\u5C55\u5305 (${spec})...`,
47098
+ t("template.resolving", spec),
46752
47099
  () => resolvePackageWith(
46753
47100
  service,
46754
47101
  spec,
@@ -46757,8 +47104,8 @@ async function executeCreate(packageSpecs, directory, options, cliVersion, event
46757
47104
  ),
46758
47105
  {
46759
47106
  enabled: spinnerEnabled,
46760
- successText: (res) => `\u2714 \u6269\u5C55\u5305\u89E3\u6790\u5B8C\u6210: ${res.manifest.displayName ?? res.manifest.name ?? res.manifest.id ?? spec} (v${res.manifest.version ?? "0.0.0"})`,
46761
- failText: `\u2716 \u6269\u5C55\u5305\u89E3\u6790\u5931\u8D25: ${spec}`
47107
+ successText: (res) => t("template.resolved", res.manifest.displayName ?? res.manifest.name ?? res.manifest.id ?? spec, res.manifest.version ?? "0.0.0"),
47108
+ failText: t("template.resolveFailed", spec)
46762
47109
  }
46763
47110
  ), { packageId: spec });
46764
47111
  allResolutions.push(resolution);
@@ -46796,14 +47143,14 @@ async function executeCreate(packageSpecs, directory, options, cliVersion, event
46796
47143
  for (const res of allResolutions) {
46797
47144
  if (existingPkgIds.has(res.manifest.id)) {
46798
47145
  throw new CliError(
46799
- `\u5305 '${res.manifest.id}' \u5DF2\u7ECF\u5B89\u88C5\u5728\u5F53\u524D\u5DE5\u7A0B\u4E2D\u3002\u4E0D\u80FD\u901A\u8FC7 create \u91CD\u65B0\u5B89\u88C5\u3002\u5982\u9700\u66F4\u65B0\u914D\u7F6E\u6216\u540C\u6B65\u8D44\u4EA7\u8BF7\u4F7F\u7528 'apply'\u3001'sync' \u6216 'upgrade' \u547D\u4EE4\u3002`,
47146
+ t("create.templateAlreadyInstalled", res.manifest.id),
46800
47147
  ExitCode.ConflictOrDrift,
46801
47148
  "PACKAGE_ALREADY_INSTALLED"
46802
47149
  );
46803
47150
  }
46804
47151
  }
46805
47152
  }
46806
- const { parseInputFlags: parseInputFlags3, validateTaskInputs: validateTaskInputs2, executeTasks: executeTasks2, filterTasksByHook: filterTasksByHook2 } = await Promise.resolve().then(() => (init_src2(), src_exports));
47153
+ const { parseInputFlags: parseInputFlags3, validateTaskInputs: validateTaskInputs2, filterTasksByHook: filterTasksByHook2 } = await Promise.resolve().then(() => (init_src2(), src_exports));
46807
47154
  const rawInputs = [...options.input ?? [], ...options.set ?? []];
46808
47155
  const { values: inputValues, packageValues, warnings: inputWarnings } = parseInputFlags3(rawInputs);
46809
47156
  writeWarnings(inputWarnings, output);
@@ -46817,20 +47164,19 @@ async function executeCreate(packageSpecs, directory, options, cliVersion, event
46817
47164
  if (options.noInput || options.json || !process.stdin.isTTY) {
46818
47165
  const missing = taskValidation.missingInputs.join(", ");
46819
47166
  throw new CliError(
46820
- `\u5305 '${pkgId}' \u7F3A\u5C11\u521D\u59CB\u5316\u53C2\u6570: ${missing}\uFF0C\u8BF7\u4F7F\u7528\uFF1A
46821
- ${taskValidation.missingInputs.map((k2) => `--input ${pkgId}:${k2}=<value>`).join("\n")}`,
47167
+ t("create.missingTaskInputs", pkgId, missing, taskValidation.missingInputs.map((k2) => `--input ${pkgId}:${k2}=<value>`).join("\n")),
46822
47168
  ExitCode.NeedsInputOrDenied,
46823
47169
  "INPUT_REQUIRED",
46824
47170
  { inputs: taskValidation.missingInputs }
46825
47171
  );
46826
47172
  }
46827
47173
  for (const missingKey of taskValidation.missingInputs) {
46828
- const val = await dist_default6({ message: `[${pkgId}] \u8BF7\u8F93\u5165\u521D\u59CB\u5316\u53C2\u6570 '${missingKey}':` });
47174
+ const val = await dist_default6({ message: t("create.promptTaskInput", pkgId, missingKey) });
46829
47175
  inputValues[missingKey] = val;
46830
47176
  }
46831
47177
  } else {
46832
47178
  throw new CliError(
46833
- taskValidation.error ?? "\u53C2\u6570\u6821\u9A8C\u5931\u8D25",
47179
+ taskValidation.error ?? t("create.taskValidationFailed"),
46834
47180
  ExitCode.SchemaInvalid,
46835
47181
  "INVALID_OPTIONS"
46836
47182
  );
@@ -46890,12 +47236,12 @@ ${taskValidation.missingInputs.map((k2) => `--input ${pkgId}:${k2}=<value>`).joi
46890
47236
  );
46891
47237
  const userInstallationKeys = /* @__PURE__ */ new Set();
46892
47238
  let staticIntents = await withSpinner(
46893
- "\u6B63\u5728\u8BA1\u7B97\u53D7\u7BA1\u8D44\u6E90\u5E76\u751F\u6210\u6267\u884C\u8BA1\u5212...",
47239
+ t("create.computingPlan"),
46894
47240
  () => buildIntentsFromPlan(planResult.plan, allResolutions, service, projectTargets, userInstallationKeys),
46895
47241
  {
46896
47242
  enabled: spinnerEnabled,
46897
- successText: (res) => `\u2714 \u6267\u884C\u8BA1\u5212\u5DF2\u5C31\u7EEA (\u5171 ${res.length} \u9879\u8D44\u6E90\u53D8\u66F4)`,
46898
- failText: "\u2716 \u6267\u884C\u8BA1\u5212\u751F\u6210\u5931\u8D25"
47243
+ successText: (res) => t("create.planReady", res.length),
47244
+ failText: t("create.planFailed")
46899
47245
  }
46900
47246
  );
46901
47247
  planResult = materializePlan(planResult.plan, staticIntents);
@@ -46994,18 +47340,12 @@ ${taskValidation.missingInputs.map((k2) => `--input ${pkgId}:${k2}=<value>`).joi
46994
47340
  operation: "create",
46995
47341
  version: resolution.manifest.version
46996
47342
  };
46997
- if (!output.json) {
46998
- writeHumanOutput(`
46999
- \u6B63\u5728\u6267\u884C\u524D\u7F6E\u521B\u5EFA\u4EFB\u52A1 (before:create) [${pkgIdx + 1}/${allResolutions.length}] (${resolution.manifest.id}):
47000
- `);
47001
- }
47343
+ const title = t("task.runningBeforeCreate", pkgIdx + 1, allResolutions.length, resolution.manifest.id);
47002
47344
  try {
47003
- await executeTasks2(pkgTasks, taskContext, {
47004
- onProgress: (msg) => {
47005
- if (!output.json) writeHumanOutput(`> ${msg}
47006
- `);
47007
- },
47008
- stdio: output.json ? "ignore" : "inherit"
47345
+ await runTasksWithDynamicUI(pkgTasks, taskContext, {
47346
+ title,
47347
+ verbose: options.verbose,
47348
+ json: options.json
47009
47349
  });
47010
47350
  } catch (err) {
47011
47351
  if (err instanceof Error) {
@@ -47124,18 +47464,12 @@ ${taskValidation.missingInputs.map((k2) => `--input ${pkgId}:${k2}=<value>`).joi
47124
47464
  operation: "create",
47125
47465
  version: resolution.manifest.version
47126
47466
  };
47127
- if (!output.json) {
47128
- writeHumanOutput(`
47129
- \u6B63\u5728\u6267\u884C\u540E\u7F6E\u521D\u59CB\u5316\u4EFB\u52A1 (after:create) [${pkgIdx + 1}/${allResolutions.length}] (${resolution.manifest.id}):
47130
- `);
47131
- }
47467
+ const title = t("task.runningAfterCreate", pkgIdx + 1, allResolutions.length, resolution.manifest.id);
47132
47468
  try {
47133
- await executeTasks2(pkgTasks, taskContext, {
47134
- onProgress: (msg) => {
47135
- if (!output.json) writeHumanOutput(`> [${resolution.manifest.id}] ${msg}
47136
- `);
47137
- },
47138
- stdio: output.json ? "ignore" : "inherit"
47469
+ await runTasksWithDynamicUI(pkgTasks, taskContext, {
47470
+ title,
47471
+ verbose: options.verbose,
47472
+ json: options.json
47139
47473
  });
47140
47474
  } catch (err) {
47141
47475
  if (err instanceof Error) {
@@ -47161,18 +47495,14 @@ ${taskValidation.missingInputs.map((k2) => `--input ${pkgId}:${k2}=<value>`).joi
47161
47495
  });
47162
47496
  }
47163
47497
  function formatElapsed(startedAt) {
47164
- return `${((Date.now() - startedAt) / 1e3).toFixed(1)} \u79D2`;
47498
+ return t("common.seconds", ((Date.now() - startedAt) / 1e3).toFixed(1));
47165
47499
  }
47166
47500
  function writeUserInstallationProgress(progress) {
47167
47501
  const name = progress.displayName ?? `${progress.packageId}/${progress.capabilityId}`;
47168
- if (progress.status === "installing") writeHumanOutput(`\u6B63\u5728\u5B89\u88C5\uFF1A${name}
47169
- `);
47170
- else if (progress.status === "installed") writeHumanOutput(`\u2713 \u5DF2\u5B89\u88C5\uFF1A${name}
47171
- `);
47172
- else if (progress.status === "reused") writeHumanOutput(`\u2713 \u5DF2\u590D\u7528\uFF1A${name}
47173
- `);
47174
- else writeHumanOutput(`- \u65E0\u9700\u5B89\u88C5\uFF1A${name}
47175
- `);
47502
+ if (progress.status === "installing") writeHumanOutput(t("create.installing", name));
47503
+ else if (progress.status === "installed") writeHumanOutput(t("create.installed", name));
47504
+ else if (progress.status === "reused") writeHumanOutput(t("create.reused", name));
47505
+ else writeHumanOutput(t("create.skipped", name));
47176
47506
  }
47177
47507
  async function resolvePackageWith(service, spec, options, cliVersion) {
47178
47508
  const req = {
@@ -47215,6 +47545,7 @@ var init_create = __esm({
47215
47545
  init_plan_execution();
47216
47546
  init_searchable_select();
47217
47547
  init_spinner();
47548
+ init_task_helper();
47218
47549
  init_i18n();
47219
47550
  }
47220
47551
  });
@@ -47224,7 +47555,7 @@ import { unlink as unlink10 } from "node:fs/promises";
47224
47555
  import { randomUUID as randomUUID7 } from "node:crypto";
47225
47556
  function createApplyCommand(cliVersion) {
47226
47557
  const cmd = new Command("apply");
47227
- cmd.description("Apply an Addon package to an existing project").argument("[package-spec]", "Addon package spec (required if no project lock)").action(async (packageSpec, opts) => {
47558
+ cmd.description(t("apply.description")).argument("[template-spec]", t("apply.argTemplateSpec")).option("--template <template-spec>", t("apply.optionTemplate")).action(async (templateSpecArg, opts) => {
47228
47559
  const options = extractMutationOptions(opts);
47229
47560
  const output = {
47230
47561
  json: options.json,
@@ -47232,7 +47563,8 @@ function createApplyCommand(cliVersion) {
47232
47563
  noColor: options.noColor
47233
47564
  };
47234
47565
  const events = createEventEmitter("apply", output);
47235
- const exitCode = await executeApply(packageSpec, options, cliVersion, events).catch(
47566
+ const templateSpec = (typeof opts.template === "string" ? opts.template : void 0) ?? (typeof templateSpecArg === "string" ? templateSpecArg : void 0);
47567
+ const exitCode = await executeApply(templateSpec, options, cliVersion, events).catch(
47236
47568
  (err) => reportCliError(err, "apply", output, options.json && options.verbose ? getRedactedEvents(events) : void 0)
47237
47569
  );
47238
47570
  if (exitCode !== 0) {
@@ -47242,7 +47574,7 @@ function createApplyCommand(cliVersion) {
47242
47574
  addMutationOptions(cmd);
47243
47575
  return cmd;
47244
47576
  }
47245
- async function executeApply(packageSpec, options, cliVersion, events) {
47577
+ async function executeApply(templateSpec, options, cliVersion, events) {
47246
47578
  const output = {
47247
47579
  json: options.json,
47248
47580
  verbose: options.verbose,
@@ -47250,13 +47582,6 @@ async function executeApply(packageSpec, options, cliVersion, events) {
47250
47582
  };
47251
47583
  const jsonEvents = () => options.json && options.verbose ? getRedactedEvents(events) : void 0;
47252
47584
  const isInteractive = !options.noInput && !options.json && Boolean(process.stdin.isTTY);
47253
- if (!packageSpec) {
47254
- throw new CliError(
47255
- t("apply.packageRequired"),
47256
- ExitCode.SchemaInvalid,
47257
- "PACKAGE_SPEC_REQUIRED"
47258
- );
47259
- }
47260
47585
  if (options.only && options.skip) {
47261
47586
  throw new CliError(
47262
47587
  t("apply.onlySkipExclusive"),
@@ -47318,28 +47643,72 @@ async function executeApply(packageSpec, options, cliVersion, events) {
47318
47643
  const spinnerEnabled = !output.json && Boolean(process.stdout.isTTY) && process.env.NODE_ENV !== "test";
47319
47644
  if (existingLock) {
47320
47645
  const existing = await withSpinner(
47321
- "\u6B63\u5728\u4ECE\u9501\u5B9A\u6587\u4EF6\u89E3\u6790\u5DF2\u5B89\u88C5\u5305...",
47646
+ t("template.resolving", "lock"),
47322
47647
  () => resolveLockedPackages(existingLock, service),
47323
47648
  {
47324
47649
  enabled: spinnerEnabled,
47325
- successText: "\u2714 \u5DF2\u52A0\u8F7D\u9501\u5B9A\u914D\u7F6E"
47650
+ successText: t("apply.lockedConfigLoaded")
47326
47651
  }
47327
47652
  );
47328
47653
  templateResolution = existing.template;
47329
47654
  addonResolutions = existing.addons;
47330
47655
  }
47656
+ let effectiveTemplateSpec = templateSpec;
47657
+ if (!effectiveTemplateSpec) {
47658
+ if (!isInteractive) {
47659
+ throw new CliError(
47660
+ t("apply.templateRequired"),
47661
+ ExitCode.SchemaInvalid,
47662
+ "PACKAGE_SPEC_REQUIRED"
47663
+ );
47664
+ }
47665
+ const client = service.getRegistryClient();
47666
+ if (!client.getIndex) {
47667
+ throw new CliError(t("create.registryIndexUnsupported"), ExitCode.ResolveFailed, "REGISTRY_INDEX_UNSUPPORTED");
47668
+ }
47669
+ const indexResult = await client.getIndex({ offline: options.offline });
47670
+ const installedIds = /* @__PURE__ */ new Set();
47671
+ if (existingLock) {
47672
+ for (const p2 of existingLock.desired?.packages ?? []) installedIds.add(p2.id);
47673
+ for (const p2 of existingLock.resolved?.packages ?? []) installedIds.add(p2.id);
47674
+ if (existingLock.desired?.template?.id) installedIds.add(existingLock.desired.template.id);
47675
+ for (const t2 of existingLock.desired?.templates ?? []) installedIds.add(t2.id);
47676
+ for (const a of existingLock.desired?.addons ?? []) installedIds.add(a.id);
47677
+ if (existingLock.resolved?.template?.id) installedIds.add(existingLock.resolved.template.id);
47678
+ for (const t2 of existingLock.resolved?.templates ?? []) installedIds.add(t2.id);
47679
+ for (const a of existingLock.resolved?.addons ?? []) installedIds.add(a.id);
47680
+ }
47681
+ const availableChoices = indexResult.packages.filter((entry) => !installedIds.has(entry.id)).map((entry) => ({
47682
+ id: entry.id,
47683
+ label: entry.name ?? entry.displayName ?? entry.id,
47684
+ description: entry.description ?? "",
47685
+ tags: entry.tags ?? []
47686
+ }));
47687
+ if (availableChoices.length === 0) {
47688
+ throw new CliError(t("apply.noAvailableTemplates"), ExitCode.NeedsInputOrDenied, "NO_TEMPLATES_AVAILABLE");
47689
+ }
47690
+ try {
47691
+ const chosen = await selectSearchable({ message: t("apply.chooseTemplate"), choices: availableChoices });
47692
+ effectiveTemplateSpec = chosen.id;
47693
+ } catch (error) {
47694
+ if (error instanceof SearchableSelectCancelled) {
47695
+ throw new CliError(t("apply.templateSelectionCancelled"), ExitCode.NeedsInputOrDenied, "PERMISSION_DENIED");
47696
+ }
47697
+ throw error;
47698
+ }
47699
+ }
47331
47700
  const newAddonResolution = await withSpinner(
47332
- `\u6B63\u5728\u62C9\u53D6\u5E76\u89E3\u6790\u6269\u5C55 (${packageSpec})...`,
47701
+ t("template.resolving", effectiveTemplateSpec),
47333
47702
  () => resolvePackageWith2(
47334
47703
  service,
47335
- packageSpec,
47704
+ effectiveTemplateSpec,
47336
47705
  options,
47337
47706
  cliVersion
47338
47707
  ),
47339
47708
  {
47340
47709
  enabled: spinnerEnabled,
47341
- successText: (res) => `\u2714 \u6269\u5C55\u89E3\u6790\u5B8C\u6210: ${res.manifest.displayName ?? res.manifest.name ?? res.manifest.id ?? packageSpec} (v${res.manifest.version ?? "0.0.0"})`,
47342
- failText: `\u2716 \u6269\u5C55\u89E3\u6790\u5931\u8D25: ${packageSpec}`
47710
+ successText: (res) => t("template.resolved", res.manifest.displayName ?? res.manifest.name ?? res.manifest.id ?? effectiveTemplateSpec, res.manifest.version ?? "0.0.0"),
47711
+ failText: t("template.resolveFailed", effectiveTemplateSpec)
47343
47712
  }
47344
47713
  );
47345
47714
  addonResolutions = [...addonResolutions.filter((resolution) => resolution.packageId !== newAddonResolution.packageId), newAddonResolution];
@@ -47369,24 +47738,31 @@ async function executeApply(packageSpec, options, cliVersion, events) {
47369
47738
  }
47370
47739
  let cliTargets = options.target;
47371
47740
  if (cliTargets.length === 0) {
47372
- if (existingLock?.desired.targets && existingLock.desired.targets.length > 0) {
47373
- cliTargets = existingLock.desired.targets.map((t2) => typeof t2 === "string" ? t2 : t2.id);
47374
- } else if (isInteractive) {
47741
+ if (isInteractive) {
47742
+ const existingTargetIds = new Set(
47743
+ (existingLock?.desired.targets ?? []).map((t2) => typeof t2 === "string" ? t2 : t2.id)
47744
+ );
47745
+ const choices = OFFICIAL_TARGET_CHOICES.map((choice) => ({
47746
+ ...choice,
47747
+ checked: existingTargetIds.size > 0 ? existingTargetIds.has(choice.id) : void 0
47748
+ }));
47375
47749
  try {
47376
47750
  const selected = await selectSearchableMulti({
47377
- message: t("create.chooseTargets"),
47378
- choices: OFFICIAL_TARGET_CHOICES
47751
+ message: t("apply.chooseTargets"),
47752
+ choices
47379
47753
  });
47380
47754
  if (selected.length === 0) {
47381
- throw new CliError(t("create.targetSelectionCancelled"), ExitCode.NeedsInputOrDenied, "PERMISSION_DENIED");
47755
+ throw new CliError(t("apply.targetSelectionCancelled"), ExitCode.NeedsInputOrDenied, "PERMISSION_DENIED");
47382
47756
  }
47383
47757
  cliTargets = selected.map((choice) => choice.id);
47384
47758
  } catch (error) {
47385
47759
  if (error instanceof SearchableSelectCancelled) {
47386
- throw new CliError(t("create.targetSelectionCancelled"), ExitCode.NeedsInputOrDenied, "PERMISSION_DENIED");
47760
+ throw new CliError(t("apply.targetSelectionCancelled"), ExitCode.NeedsInputOrDenied, "PERMISSION_DENIED");
47387
47761
  }
47388
47762
  throw error;
47389
47763
  }
47764
+ } else if (existingLock?.desired.targets && existingLock.desired.targets.length > 0) {
47765
+ cliTargets = existingLock.desired.targets.map((t2) => typeof t2 === "string" ? t2 : t2.id);
47390
47766
  } else {
47391
47767
  cliTargets = ["codebuddy"];
47392
47768
  }
@@ -47397,23 +47773,24 @@ async function executeApply(packageSpec, options, cliVersion, events) {
47397
47773
  );
47398
47774
  const planStartedAt = Date.now();
47399
47775
  const planBuilder = service.getPlanBuilder();
47776
+ const packagesToApply = [newAddonResolution];
47400
47777
  let planResult = planBuilder.build(
47401
47778
  "apply",
47402
47779
  service.projectRoot,
47403
- allResolutions,
47780
+ packagesToApply,
47404
47781
  projectTargets
47405
47782
  );
47406
47783
  const userInstallationKeys = /* @__PURE__ */ new Set();
47407
47784
  const intents = await withSpinner(
47408
- "\u6B63\u5728\u8BA1\u7B97\u53D7\u7BA1\u8D44\u6E90\u5E76\u751F\u6210\u6267\u884C\u8BA1\u5212...",
47785
+ t("apply.computingPlan"),
47409
47786
  () => buildIntentsFromPlan(
47410
47787
  planResult.plan,
47411
- allResolutions,
47788
+ packagesToApply,
47412
47789
  service,
47413
47790
  projectTargets,
47414
47791
  userInstallationKeys,
47415
47792
  {
47416
- filter: { only: onlyTypes, skip: skipTypes },
47793
+ filter: { only: onlyTypes, skip: skipTypes, skipProjectDir: true },
47417
47794
  skipProjectDir: true,
47418
47795
  onDiscloseSkipped: (msg) => {
47419
47796
  if (!output.json) writeHumanOutput(`- ${msg}
@@ -47423,18 +47800,39 @@ async function executeApply(packageSpec, options, cliVersion, events) {
47423
47800
  ),
47424
47801
  {
47425
47802
  enabled: spinnerEnabled,
47426
- successText: (res) => `\u2714 \u6267\u884C\u8BA1\u5212\u5DF2\u5C31\u7EEA (\u5171 ${res.length} \u9879\u8D44\u6E90\u53D8\u66F4)`,
47427
- failText: "\u2716 \u6267\u884C\u8BA1\u5212\u751F\u6210\u5931\u8D25"
47803
+ successText: (res) => t("apply.planReady", res.length),
47804
+ failText: t("apply.planFailed")
47428
47805
  }
47429
47806
  );
47807
+ if (existingLock?.resources) {
47808
+ for (const intent of intents) {
47809
+ if (intent.action === "remove" || !intent.target) continue;
47810
+ const targetId = typeof intent.target === "string" ? intent.target : intent.target.id;
47811
+ const selector = (intent.type === "config-entry" ? intent.selector : intent.type === "managed-section" ? intent.sectionId : null) ?? null;
47812
+ const matched = existingLock.resources.find((r) => r.target === targetId && r.path === intent.path && (r.selector ?? null) === selector);
47813
+ if (matched && matched.owners.every((o) => o.packageId !== newAddonResolution.packageId)) {
47814
+ let newDigest = intent.digest ?? "";
47815
+ if (!newDigest && intent.type === "file" && intent.content) {
47816
+ const { computeStringDigest: computeStringDigest2 } = await Promise.resolve().then(() => (init_src2(), src_exports));
47817
+ newDigest = computeStringDigest2(intent.content);
47818
+ }
47819
+ if (newDigest && matched.hash && newDigest !== matched.hash) {
47820
+ throw new CliError(
47821
+ t("apply.resourceConflict", intent.path),
47822
+ ExitCode.ConflictOrDrift,
47823
+ "PLAN_CONFLICT"
47824
+ );
47825
+ }
47826
+ }
47827
+ }
47828
+ }
47430
47829
  const { filterTasksByHook: filterTasksByHook2 } = await Promise.resolve().then(() => (init_src2(), src_exports));
47431
47830
  const skippedCreateTasks = [
47432
47831
  ...filterTasksByHook2(newAddonResolution.manifest.tasks ?? [], "before:create"),
47433
47832
  ...filterTasksByHook2(newAddonResolution.manifest.tasks ?? [], "after:create")
47434
47833
  ];
47435
47834
  if (skippedCreateTasks.length > 0 && !output.json) {
47436
- writeHumanOutput(`- \u5DF2\u8DF3\u8FC7 ${skippedCreateTasks.length} \u4E2A create \u751F\u547D\u5468\u671F\u94A9\u5B50\u4EFB\u52A1\uFF08apply \u8BED\u4E49\u4E0D\u6267\u884C before:create / after:create \u94A9\u5B50\uFF09
47437
- `);
47835
+ writeHumanOutput(t("apply.skippedCreateTasks", skippedCreateTasks.length));
47438
47836
  }
47439
47837
  const beforeApplyTasksForCheck = filterTasksByHook2(newAddonResolution.manifest.tasks ?? [], "before:apply");
47440
47838
  const afterApplyTasksForCheck = filterTasksByHook2(newAddonResolution.manifest.tasks ?? [], "after:apply");
@@ -47452,7 +47850,7 @@ async function executeApply(packageSpec, options, cliVersion, events) {
47452
47850
  if (existingResolved.version === newAddonResolution.resolvedVersion && existingResolved.integrity && newAddonResolution.integrity) {
47453
47851
  if (existingResolved.integrity !== newAddonResolution.integrity) {
47454
47852
  throw new CliError(
47455
- `\u5305 '${newAddonResolution.packageId}' \u7248\u672C\u76F8\u540C\u4F46\u5185\u5BB9\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u4F7F\u7528 upgrade \u547D\u4EE4\u8FDB\u884C\u66F4\u65B0`,
47853
+ t("apply.templateUpdatedNeedsUpgrade", newAddonResolution.packageId),
47456
47854
  ExitCode.ConflictOrDrift,
47457
47855
  "PACKAGE_UPDATE_REQUIRES_UPGRADE"
47458
47856
  );
@@ -47461,9 +47859,9 @@ async function executeApply(packageSpec, options, cliVersion, events) {
47461
47859
  const hasChanges = planResult.plan.files.length > 0 || planResult.plan.configEntries.length > 0 || planResult.plan.managedSections.length > 0 || planResult.plan.plugins.length > 0 || planResult.plan.userInstallations.length > 0;
47462
47860
  if (sameAssetTypes && !hasChanges) {
47463
47861
  if (output.json) {
47464
- emitSuccessJson("apply", { dryRun: false, message: "\u5DF2\u5E94\u7528\uFF0C\u65E0\u53D8\u5316", lockPath: lockRepo.path }, [], [], jsonEvents());
47862
+ emitSuccessJson("apply", { dryRun: false, message: t("apply.alreadyUpToDate"), lockPath: lockRepo.path }, [], [], jsonEvents());
47465
47863
  } else {
47466
- writeHumanOutput("\u5DF2\u5E94\u7528\uFF0C\u65E0\u53D8\u5316\n");
47864
+ writeHumanOutput(t("apply.alreadyUpToDate") + "\n");
47467
47865
  }
47468
47866
  return ExitCode.Success;
47469
47867
  }
@@ -47546,14 +47944,11 @@ async function executeApply(packageSpec, options, cliVersion, events) {
47546
47944
  }
47547
47945
  return ExitCode.Success;
47548
47946
  }
47549
- const allTasksWithContext = allResolutions.flatMap((resolution) => {
47550
- const tTasks = resolution.manifest.tasks ?? [];
47551
- return tTasks.map((task) => ({
47552
- task,
47553
- templateDir: service.getPackageRoot(resolution) ?? service.projectRoot
47554
- }));
47555
- });
47556
- const beforeApplyTasks = allTasksWithContext.filter(({ task }) => {
47947
+ const newTasksWithContext = (newAddonResolution.manifest.tasks ?? []).map((task) => ({
47948
+ task,
47949
+ templateDir: service.getPackageRoot(newAddonResolution) ?? service.projectRoot
47950
+ }));
47951
+ const beforeApplyTasks = newTasksWithContext.filter(({ task }) => {
47557
47952
  return filterTasksByHook2([task], "before:apply").length > 0;
47558
47953
  });
47559
47954
  if (beforeApplyTasks.length > 0) {
@@ -47569,16 +47964,11 @@ async function executeApply(packageSpec, options, cliVersion, events) {
47569
47964
  target: projectTargets[0]?.id,
47570
47965
  targets: projectTargets.map((t2) => t2.id)
47571
47966
  };
47572
- if (!output.json && i === 0) {
47573
- writeHumanOutput("\n\u6B63\u5728\u6267\u884C\u524D\u7F6E\u5E94\u7528\u4EFB\u52A1 (before:apply):\n");
47574
- }
47575
47967
  try {
47576
- await executeTasks([task], taskContext, {
47577
- onProgress: (msg) => {
47578
- if (!output.json) writeHumanOutput(`> ${msg}
47579
- `);
47580
- },
47581
- stdio: output.json ? "ignore" : "inherit"
47968
+ await runTasksWithDynamicUI([task], taskContext, {
47969
+ title: i === 0 ? t("task.runningBeforeApply", 1, 1, newAddonResolution.packageId) : void 0,
47970
+ verbose: options.verbose,
47971
+ json: options.json
47582
47972
  });
47583
47973
  } catch (err) {
47584
47974
  if (err instanceof Error) {
@@ -47624,7 +48014,7 @@ async function executeApply(packageSpec, options, cliVersion, events) {
47624
48014
  addRollback(userLifecycle.rollback);
47625
48015
  const activeAssetTypes = onlyTypes ?? (skipTypes ? ["skills", "rules", "subagents", "mcp", "agents-md"].filter((t2) => !skipTypes.includes(t2)) : void 0);
47626
48016
  const packageAssetTypes = activeAssetTypes ? { [newAddonResolution.packageId]: activeAssetTypes } : void 0;
47627
- const lock = await buildLock("apply", templateResolution, addonResolutions, projectTargets, planResult.plan, service.cliVersion, inputValues, service, intents, userInstallationKeys, packageAssetTypes);
48017
+ const lock = await buildLock("apply", templateResolution, addonResolutions, projectTargets, planResult.plan, service.cliVersion, inputValues, service, intents, userInstallationKeys, packageAssetTypes, existingLock);
47628
48018
  for (const desired of [lock.desired.template, ...lock.desired.addons ?? []]) {
47629
48019
  if (!desired) continue;
47630
48020
  const previous = [existingLock?.desired.template, ...existingLock?.desired.addons ?? []].find((item) => item?.id === desired.id);
@@ -47636,7 +48026,7 @@ async function executeApply(packageSpec, options, cliVersion, events) {
47636
48026
  await finishJournal(journal);
47637
48027
  });
47638
48028
  events.report("record", "success", Date.now() - recordStartedAt, { planDigest: planResult.plan.planDigest });
47639
- const afterApplyTasks = allTasksWithContext.filter(({ task }) => {
48029
+ const afterApplyTasks = newTasksWithContext.filter(({ task }) => {
47640
48030
  return filterTasksByHook2([task], "after:apply").length > 0;
47641
48031
  });
47642
48032
  if (afterApplyTasks.length > 0) {
@@ -47652,16 +48042,11 @@ async function executeApply(packageSpec, options, cliVersion, events) {
47652
48042
  target: projectTargets[0]?.id,
47653
48043
  targets: projectTargets.map((t2) => t2.id)
47654
48044
  };
47655
- if (!output.json && i === 0) {
47656
- writeHumanOutput("\n\u6B63\u5728\u6267\u884C\u540E\u7F6E\u5E94\u7528\u4EFB\u52A1 (after:apply):\n");
47657
- }
47658
48045
  try {
47659
- await executeTasks([task], taskContext, {
47660
- onProgress: (msg) => {
47661
- if (!output.json) writeHumanOutput(`> ${msg}
47662
- `);
47663
- },
47664
- stdio: output.json ? "ignore" : "inherit"
48046
+ await runTasksWithDynamicUI([task], taskContext, {
48047
+ title: i === 0 ? t("task.runningAfterApply", 1, 1, newAddonResolution.packageId) : void 0,
48048
+ verbose: options.verbose,
48049
+ json: options.json
47665
48050
  });
47666
48051
  } catch (err) {
47667
48052
  if (err instanceof Error) {
@@ -47721,6 +48106,7 @@ var init_apply = __esm({
47721
48106
  init_cli_output();
47722
48107
  init_service_locator();
47723
48108
  init_spinner();
48109
+ init_task_helper();
47724
48110
  init_i18n();
47725
48111
  init_plan_execution();
47726
48112
  init_searchable_select();
@@ -47732,10 +48118,10 @@ import { randomUUID as randomUUID8 } from "node:crypto";
47732
48118
  import { basename as basename5, dirname as dirname17, resolve as resolve22 } from "node:path";
47733
48119
  function createSyncCommand(cliVersion) {
47734
48120
  const cmd = new Command("sync");
47735
- cmd.description(t("sync.description")).option("--package <packageId>", "\u4EC5\u540C\u6B65\u6307\u5B9A\u7684\u5DF2\u5B89\u88C5\u5305").action(async (opts) => {
48121
+ cmd.description(t("sync.description")).option("--template <templateId>", t("sync.optionTemplate")).action(async (opts) => {
47736
48122
  const options = extractMutationOptions(opts);
47737
- if (typeof opts.package === "string") {
47738
- options.package = opts.package;
48123
+ if (typeof opts.template === "string") {
48124
+ options.template = opts.template;
47739
48125
  }
47740
48126
  const output = {
47741
48127
  json: options.json,
@@ -47780,11 +48166,11 @@ async function executeSync(options, cliVersion, silent = false, events = new Lif
47780
48166
  }
47781
48167
  const locked = await events.measure("resolve", () => resolveLockedPackages(lock, service));
47782
48168
  let allResolutions = [...locked.template ? [locked.template] : [], ...locked.addons];
47783
- if (options.package) {
47784
- allResolutions = allResolutions.filter((r) => r.packageId === options.package);
48169
+ if (options.template) {
48170
+ allResolutions = allResolutions.filter((r) => r.packageId === options.template);
47785
48171
  if (allResolutions.length === 0) {
47786
48172
  throw new CliError(
47787
- `\u672A\u5728 Lock \u6587\u4EF6\u4E2D\u627E\u5230\u5305 '${options.package}'\u3002\u8BE5\u5305\u672A\u5B89\u88C5\u6216\u65E0\u6CD5\u540C\u6B65\u3002`,
48173
+ t("sync.templateNotFound", options.template),
47788
48174
  ExitCode.SchemaInvalid,
47789
48175
  "PACKAGE_NOT_FOUND"
47790
48176
  );
@@ -47969,18 +48355,12 @@ async function executeSync(options, cliVersion, silent = false, events = new Lif
47969
48355
  operation: "sync",
47970
48356
  version: resolution.manifest.version
47971
48357
  };
47972
- if (!output.json) {
47973
- writeHumanOutput(`
47974
- \u6B63\u5728\u6267\u884C\u524D\u7F6E\u540C\u6B65\u4EFB\u52A1 (before:sync) [${pkgIdx + 1}/${allResolutions.length}] (${resolution.manifest.id}):
47975
- `);
47976
- }
48358
+ const title = `\u6B63\u5728\u6267\u884C\u524D\u7F6E\u540C\u6B65\u4EFB\u52A1 (before:sync) [${pkgIdx + 1}/${allResolutions.length}] (${resolution.manifest.id}):`;
47977
48359
  try {
47978
- await executeTasks(pkgTasks, taskContext, {
47979
- onProgress: (msg) => {
47980
- if (!output.json) writeHumanOutput(`> [${resolution.manifest.id}] ${msg}
47981
- `);
47982
- },
47983
- stdio: output.json ? "ignore" : "inherit"
48360
+ await runTasksWithDynamicUI(pkgTasks, taskContext, {
48361
+ title,
48362
+ verbose: options.verbose,
48363
+ json: options.json
47984
48364
  });
47985
48365
  } catch (err) {
47986
48366
  if (err instanceof Error) {
@@ -48037,18 +48417,12 @@ async function executeSync(options, cliVersion, silent = false, events = new Lif
48037
48417
  operation: "sync",
48038
48418
  version: resolution.manifest.version
48039
48419
  };
48040
- if (!output.json) {
48041
- writeHumanOutput(`
48042
- \u6B63\u5728\u6267\u884C\u540E\u7F6E\u540C\u6B65\u4EFB\u52A1 (after:sync) [${pkgIdx + 1}/${allResolutions.length}] (${resolution.manifest.id}):
48043
- `);
48044
- }
48420
+ const title = `\u6B63\u5728\u6267\u884C\u540E\u7F6E\u540C\u6B65\u4EFB\u52A1 (after:sync) [${pkgIdx + 1}/${allResolutions.length}] (${resolution.manifest.id}):`;
48045
48421
  try {
48046
- await executeTasks(pkgTasks, taskContext, {
48047
- onProgress: (msg) => {
48048
- if (!output.json) writeHumanOutput(`> [${resolution.manifest.id}] ${msg}
48049
- `);
48050
- },
48051
- stdio: output.json ? "ignore" : "inherit"
48422
+ await runTasksWithDynamicUI(pkgTasks, taskContext, {
48423
+ title,
48424
+ verbose: options.verbose,
48425
+ json: options.json
48052
48426
  });
48053
48427
  } catch (err) {
48054
48428
  if (err instanceof Error) {
@@ -48083,6 +48457,7 @@ var init_sync = __esm({
48083
48457
  init_cli_output();
48084
48458
  init_service_locator();
48085
48459
  init_plan_execution();
48460
+ init_task_helper();
48086
48461
  init_i18n();
48087
48462
  }
48088
48463
  });
@@ -48144,7 +48519,7 @@ import { unlink as unlink11, readFile as readFile31 } from "node:fs/promises";
48144
48519
  import { basename as basename6, dirname as dirname18, join as join24, resolve as resolve23 } from "node:path";
48145
48520
  function createRemoveCommand(cliVersion) {
48146
48521
  const cmd = new Command("remove");
48147
- cmd.description(t("remove.description")).option("--package <package-id>", t("remove.optionPackage")).action(async (opts) => {
48522
+ cmd.description(t("remove.description")).argument("[template-id]", t("remove.argTemplate")).option("--template <template-id>", t("remove.optionTemplate")).action(async (templateArg, opts) => {
48148
48523
  const options = extractMutationOptions(opts);
48149
48524
  const output = {
48150
48525
  json: options.json,
@@ -48152,8 +48527,8 @@ function createRemoveCommand(cliVersion) {
48152
48527
  noColor: options.noColor
48153
48528
  };
48154
48529
  const events = createEventEmitter("remove", output);
48155
- const packageId = typeof opts.package === "string" ? opts.package : void 0;
48156
- const exitCode = await executeRemove(packageId, options, cliVersion, events).catch(
48530
+ const templateId = (typeof opts.template === "string" ? opts.template : void 0) ?? (typeof templateArg === "string" ? templateArg : void 0);
48531
+ const exitCode = await executeRemove(templateId, options, cliVersion, events).catch(
48157
48532
  (err) => reportCliError(err, "remove", output, options.json && options.verbose ? getRedactedEvents(events) : void 0)
48158
48533
  );
48159
48534
  if (exitCode !== 0) {
@@ -48163,7 +48538,7 @@ function createRemoveCommand(cliVersion) {
48163
48538
  addMutationOptions(cmd);
48164
48539
  return cmd;
48165
48540
  }
48166
- async function executeRemove(packageId, options, cliVersion, events) {
48541
+ async function executeRemove(templateId, options, cliVersion, events) {
48167
48542
  const output = {
48168
48543
  json: options.json,
48169
48544
  verbose: options.verbose,
@@ -48189,47 +48564,56 @@ async function executeRemove(packageId, options, cliVersion, events) {
48189
48564
  "LOCK_NOT_FOUND"
48190
48565
  );
48191
48566
  }
48192
- if (packageId) {
48193
- const allPackages = [
48567
+ if (templateId) {
48568
+ const allTemplates = [
48194
48569
  ...lock.desired?.packages ? lock.desired.packages.map((p2) => p2.id) : [],
48195
48570
  ...lock.resolved?.packages ? lock.resolved.packages.map((p2) => p2.id) : [],
48196
48571
  ...lock.resolved.template ? [lock.resolved.template.id] : [],
48197
48572
  ...lock.resolved.templates ? lock.resolved.templates.map((t2) => t2.id) : [],
48198
48573
  ...lock.resolved.addons ? lock.resolved.addons.map((a) => a.id) : []
48199
48574
  ];
48200
- if (!allPackages.includes(packageId)) {
48201
- if (lock.createdWith?.packages?.some((p2) => p2.packageId === packageId)) {
48575
+ if (!allTemplates.includes(templateId)) {
48576
+ if (lock.createdWith?.packages?.some((p2) => p2.packageId === templateId)) {
48202
48577
  throw new CliError(
48203
- `\u5305 '${packageId}' \u662F\u9879\u76EE\u7684\u521D\u59CB\u5DE5\u7A0B\u6A21\u677F (bootstrap-only)\uFF0C\u4E0D\u5305\u542B\u53D7\u7BA1\u77E5\u8BC6\u8D44\u4EA7\uFF0C\u65E0\u6CD5\u88AB remove\u3002\u82E5\u9700\u5220\u9664\u6574\u4E2A\u9879\u76EE\uFF0C\u8BF7\u76F4\u63A5\u5220\u9664\u9879\u76EE\u76EE\u5F55\u3002`,
48578
+ t("remove.bootstrapTemplateCannotBeRemoved", templateId),
48204
48579
  ExitCode.SchemaInvalid,
48205
48580
  "BOOTSTRAP_PACKAGE_CANNOT_BE_REMOVED"
48206
48581
  );
48207
48582
  }
48208
48583
  throw new CliError(
48209
- t("remove.packageNotInLock", packageId, allPackages.join(", ") || "none"),
48584
+ t("remove.templateNotInLock", templateId, allTemplates.join(", ") || "none"),
48210
48585
  ExitCode.SchemaInvalid,
48211
48586
  "PACKAGE_NOT_IN_LOCK",
48212
- { packageId, available: allPackages }
48587
+ { templateId, available: allTemplates }
48213
48588
  );
48214
48589
  }
48215
48590
  }
48216
48591
  events.report("resolve", "success", Date.now() - resolveStartedAt, {
48217
48592
  details: { packageCount: (lock.resolved.template ? 1 : 0) + (lock.resolved.addons?.length ?? 0) }
48218
48593
  });
48594
+ const ownerMatches = (owner) => !templateId || owner.packageId === templateId;
48595
+ const intents = lock.resources.filter((resource) => resource.owners.every(ownerMatches)).map((resource) => {
48596
+ const targetId = typeof resource.target === "string" ? resource.target : resource.target?.id;
48597
+ const metadata = { target: targetId, packageId: resource.owners[0]?.packageId };
48598
+ if (resource.type === "file" || !resource.type) return { action: "remove", type: "file", path: resource.path, ...metadata };
48599
+ if (resource.type === "managed-section") return { action: "remove", type: "managed-section", path: resource.path, sectionId: resource.sectionId ?? resource.selector ?? "", ...metadata };
48600
+ return { action: "remove", type: "config-entry", path: resource.path, selector: resource.selector ?? "", format: resource.format ?? "json", ...metadata };
48601
+ });
48219
48602
  const planStartedAt = Date.now();
48220
48603
  const planBuilder = service.getPlanBuilder();
48221
48604
  const projectTargets = lock.desired.targets.map((t2) => typeof t2 === "string" ? { id: t2, scope: "project" } : t2);
48222
- const planResult = planBuilder.build(
48605
+ let planResult = planBuilder.build(
48223
48606
  "remove",
48224
48607
  service.projectRoot,
48225
48608
  [],
48226
48609
  projectTargets
48227
48610
  );
48611
+ planResult = materializePlan(planResult.plan, intents);
48228
48612
  events.report("plan", "success", Date.now() - planStartedAt, { planDigest: planResult.plan.planDigest });
48229
48613
  const driftDetector = new DriftDetector({ projectRoot: service.projectRoot, driftMode: options.drift });
48230
48614
  const drift = await driftDetector.detect(lock);
48231
48615
  if (driftDetector.shouldAbort(drift)) {
48232
- throw new CliError(`\u68C0\u6D4B\u5230 ${drift.length} \u9879\u8D44\u6E90\u6F02\u79FB\uFF1B\u5982\u786E\u8BA4\u5220\u9664\u5DF2\u4FEE\u6539\u5185\u5BB9\uFF0C\u8BF7\u4F7F\u7528 --drift accept`, ExitCode.ConflictOrDrift, "RESOURCE_DRIFT", { drift });
48616
+ throw new CliError(t("remove.driftDetected", drift.length), ExitCode.ConflictOrDrift, "RESOURCE_DRIFT", { drift });
48233
48617
  }
48234
48618
  if (!options.dryRun && !options.yes) {
48235
48619
  if (options.noInput || !process.stdin.isTTY) {
@@ -48288,23 +48672,15 @@ async function executeRemove(packageId, options, cliVersion, events) {
48288
48672
  }
48289
48673
  return ExitCode.Success;
48290
48674
  }
48291
- const ownerMatches = (owner) => !packageId || owner.packageId === packageId;
48292
- const intents = lock.resources.filter((resource) => resource.owners.every(ownerMatches)).map((resource) => {
48293
- const targetId = typeof resource.target === "string" ? resource.target : resource.target?.id;
48294
- const metadata = { target: targetId, packageId: resource.owners[0]?.packageId };
48295
- if (resource.type === "file" || !resource.type) return { action: "remove", type: "file", path: resource.path, ...metadata };
48296
- if (resource.type === "managed-section") return { action: "remove", type: "managed-section", path: resource.path, sectionId: resource.sectionId ?? resource.selector ?? "", ...metadata };
48297
- return { action: "remove", type: "config-entry", path: resource.path, selector: resource.selector ?? "", format: resource.format ?? "json", ...metadata };
48298
- });
48299
- const packagesToRemove = packageId ? [packageId] : [
48675
+ const templatesToRemove = templateId ? [templateId] : [
48300
48676
  ...lock.desired?.packages ? lock.desired.packages.map((p2) => p2.id) : [],
48301
48677
  ...lock.resolved?.packages ? lock.resolved.packages.map((p2) => p2.id) : [],
48302
48678
  ...lock.resolved.template ? [lock.resolved.template.id] : [],
48303
48679
  ...lock.resolved.addons ? lock.resolved.addons.map((a) => a.id) : []
48304
48680
  ];
48305
- const uniquePackagesToRemove = [...new Set(packagesToRemove)];
48306
- const packageManifests = [];
48307
- for (const pkg of uniquePackagesToRemove) {
48681
+ const uniqueTemplatesToRemove = [...new Set(templatesToRemove)];
48682
+ const templateManifests = [];
48683
+ for (const pkg of uniqueTemplatesToRemove) {
48308
48684
  const resolved = lock.resolved?.packages?.find((p2) => p2.id === pkg) ?? (lock.resolved?.template?.id === pkg ? lock.resolved.template : void 0);
48309
48685
  const desired = lock.desired?.packages?.find((p2) => p2.id === pkg) ?? (lock.desired?.template?.id === pkg ? lock.desired.template : void 0);
48310
48686
  let templateDir;
@@ -48321,8 +48697,8 @@ async function executeRemove(packageId, options, cliVersion, events) {
48321
48697
  const manifestContent = await readFile31(join24(templateDir, "manifest.yaml"), "utf-8");
48322
48698
  const parsed = parseManifest(manifestContent);
48323
48699
  if (parsed.manifest) {
48324
- packageManifests.push({
48325
- packageId: pkg,
48700
+ templateManifests.push({
48701
+ templateId: pkg,
48326
48702
  manifest: parsed.manifest,
48327
48703
  templateDir,
48328
48704
  inputs: Object.fromEntries(Object.entries(desired?.inputs ?? {}).map(([k2, v2]) => [k2, String(v2)]))
@@ -48331,8 +48707,8 @@ async function executeRemove(packageId, options, cliVersion, events) {
48331
48707
  } catch {
48332
48708
  }
48333
48709
  }
48334
- for (let pkgIdx = 0; pkgIdx < packageManifests.length; pkgIdx++) {
48335
- const item = packageManifests[pkgIdx];
48710
+ for (let pkgIdx = 0; pkgIdx < templateManifests.length; pkgIdx++) {
48711
+ const item = templateManifests[pkgIdx];
48336
48712
  const pkgTasks = filterTasksByHook(item.manifest.tasks ?? [], "before:remove");
48337
48713
  if (pkgTasks.length > 0) {
48338
48714
  const taskContext = {
@@ -48346,18 +48722,12 @@ async function executeRemove(packageId, options, cliVersion, events) {
48346
48722
  operation: "remove",
48347
48723
  version: item.manifest.version
48348
48724
  };
48349
- if (!output.json) {
48350
- writeHumanOutput(`
48351
- \u6B63\u5728\u6267\u884C\u524D\u7F6E\u79FB\u9664\u4EFB\u52A1 (before:remove) [${pkgIdx + 1}/${packageManifests.length}] (${item.packageId}):
48352
- `);
48353
- }
48725
+ const title = t("task.runningBeforeRemove", pkgIdx + 1, templateManifests.length, item.templateId);
48354
48726
  try {
48355
- await executeTasks(pkgTasks, taskContext, {
48356
- onProgress: (msg) => {
48357
- if (!output.json) writeHumanOutput(`> [${item.packageId}] ${msg}
48358
- `);
48359
- },
48360
- stdio: output.json ? "ignore" : "inherit"
48727
+ await runTasksWithDynamicUI(pkgTasks, taskContext, {
48728
+ title,
48729
+ verbose: options.verbose,
48730
+ json: options.json
48361
48731
  });
48362
48732
  } catch (err) {
48363
48733
  if (err instanceof Error) {
@@ -48383,36 +48753,36 @@ async function executeRemove(packageId, options, cliVersion, events) {
48383
48753
  }
48384
48754
  events.report("execute", "success", Date.now() - executeStartedAt, { planDigest: planResult.plan.planDigest, details: { intentCount: intents.length } });
48385
48755
  const remainingLock = structuredClone(lock);
48386
- if (packageId) {
48387
- if (remainingLock.desired.packages) remainingLock.desired.packages = remainingLock.desired.packages.filter((item) => item.id !== packageId);
48388
- if (remainingLock.resolved.packages) remainingLock.resolved.packages = remainingLock.resolved.packages.filter((item) => item.id !== packageId);
48389
- if (remainingLock.desired.template?.id === packageId) delete remainingLock.desired.template;
48390
- if (remainingLock.resolved.template?.id === packageId) delete remainingLock.resolved.template;
48391
- if (remainingLock.desired.templates) remainingLock.desired.templates = remainingLock.desired.templates.filter((item) => item.id !== packageId);
48392
- if (remainingLock.resolved.templates) remainingLock.resolved.templates = remainingLock.resolved.templates.filter((item) => item.id !== packageId);
48393
- if (remainingLock.desired.addons) remainingLock.desired.addons = remainingLock.desired.addons.filter((item) => item.id !== packageId);
48394
- if (remainingLock.resolved.addons) remainingLock.resolved.addons = remainingLock.resolved.addons.filter((item) => item.id !== packageId);
48395
- if (remainingLock.desired.capabilities) remainingLock.desired.capabilities = remainingLock.desired.capabilities.filter((item) => item.packageId !== packageId);
48396
- if (remainingLock.resolved.projects) remainingLock.resolved.projects = remainingLock.resolved.projects.filter((item) => item.packageId !== packageId);
48397
- if (remainingLock.resolved.capabilities) remainingLock.resolved.capabilities = remainingLock.resolved.capabilities.filter((item) => item.packageId !== packageId);
48398
- if (remainingLock.resolved.plugins) remainingLock.resolved.plugins = remainingLock.resolved.plugins.filter((item) => item.packageId !== packageId);
48399
- remainingLock.resources = remainingLock.resources.map((resource) => ({ ...resource, owners: resource.owners.filter((owner) => owner.packageId !== packageId) })).filter((resource) => resource.owners.length > 0);
48756
+ if (templateId) {
48757
+ if (remainingLock.desired.packages) remainingLock.desired.packages = remainingLock.desired.packages.filter((item) => item.id !== templateId);
48758
+ if (remainingLock.resolved.packages) remainingLock.resolved.packages = remainingLock.resolved.packages.filter((item) => item.id !== templateId);
48759
+ if (remainingLock.desired.template?.id === templateId) delete remainingLock.desired.template;
48760
+ if (remainingLock.resolved.template?.id === templateId) delete remainingLock.resolved.template;
48761
+ if (remainingLock.desired.templates) remainingLock.desired.templates = remainingLock.desired.templates.filter((item) => item.id !== templateId);
48762
+ if (remainingLock.resolved.templates) remainingLock.resolved.templates = remainingLock.resolved.templates.filter((item) => item.id !== templateId);
48763
+ if (remainingLock.desired.addons) remainingLock.desired.addons = remainingLock.desired.addons.filter((item) => item.id !== templateId);
48764
+ if (remainingLock.resolved.addons) remainingLock.resolved.addons = remainingLock.resolved.addons.filter((item) => item.id !== templateId);
48765
+ if (remainingLock.desired.capabilities) remainingLock.desired.capabilities = remainingLock.desired.capabilities.filter((item) => item.packageId !== templateId);
48766
+ if (remainingLock.resolved.projects) remainingLock.resolved.projects = remainingLock.resolved.projects.filter((item) => item.packageId !== templateId);
48767
+ if (remainingLock.resolved.capabilities) remainingLock.resolved.capabilities = remainingLock.resolved.capabilities.filter((item) => item.packageId !== templateId);
48768
+ if (remainingLock.resolved.plugins) remainingLock.resolved.plugins = remainingLock.resolved.plugins.filter((item) => item.packageId !== templateId);
48769
+ remainingLock.resources = remainingLock.resources.map((resource) => ({ ...resource, owners: resource.owners.filter((owner) => owner.packageId !== templateId) })).filter((resource) => resource.owners.length > 0);
48400
48770
  }
48401
48771
  const hasPackages = (remainingLock.resolved.packages?.length ?? 0) > 0 || Boolean(remainingLock.resolved.template) || (remainingLock.resolved.templates?.length ?? 0) > 0 || (remainingLock.resolved.addons?.length ?? 0) > 0;
48402
48772
  const recordStartedAt = Date.now();
48403
48773
  await commitExecution(executor, executeResult, async (addRollback) => {
48404
- if (packageId && hasPackages) await lockRepo.write(remainingLock);
48774
+ if (templateId && hasPackages) await lockRepo.write(remainingLock);
48405
48775
  else await unlink11(lockRepo.path).catch((error) => {
48406
48776
  if (error.code !== "ENOENT") throw error;
48407
48777
  });
48408
48778
  addRollback(() => lockRepo.write(lock));
48409
48779
  await prepareUserDataRecovery(journal, service.getUserDataDir(), ["installations.json"]);
48410
- await removeUserReferences(lock, packageId, service, output);
48780
+ await removeUserReferences(lock, templateId, service, output);
48411
48781
  await finishJournal(journal);
48412
48782
  });
48413
48783
  events.report("record", "success", Date.now() - recordStartedAt, { planDigest: planResult.plan.planDigest });
48414
- for (let pkgIdx = 0; pkgIdx < packageManifests.length; pkgIdx++) {
48415
- const item = packageManifests[pkgIdx];
48784
+ for (let pkgIdx = 0; pkgIdx < templateManifests.length; pkgIdx++) {
48785
+ const item = templateManifests[pkgIdx];
48416
48786
  const pkgTasks = filterTasksByHook(item.manifest.tasks ?? [], "after:remove");
48417
48787
  if (pkgTasks.length > 0) {
48418
48788
  const taskContext = {
@@ -48426,18 +48796,12 @@ async function executeRemove(packageId, options, cliVersion, events) {
48426
48796
  operation: "remove",
48427
48797
  version: item.manifest.version
48428
48798
  };
48429
- if (!output.json) {
48430
- writeHumanOutput(`
48431
- \u6B63\u5728\u6267\u884C\u540E\u7F6E\u79FB\u9664\u4EFB\u52A1 (after:remove) [${pkgIdx + 1}/${packageManifests.length}] (${item.packageId}):
48432
- `);
48433
- }
48799
+ const title = t("task.runningAfterRemove", pkgIdx + 1, templateManifests.length, item.templateId);
48434
48800
  try {
48435
- await executeTasks(pkgTasks, taskContext, {
48436
- onProgress: (msg) => {
48437
- if (!output.json) writeHumanOutput(`> [${item.packageId}] ${msg}
48438
- `);
48439
- },
48440
- stdio: output.json ? "ignore" : "inherit"
48801
+ await runTasksWithDynamicUI(pkgTasks, taskContext, {
48802
+ title,
48803
+ verbose: options.verbose,
48804
+ json: options.json
48441
48805
  });
48442
48806
  } catch (err) {
48443
48807
  if (err instanceof Error) {
@@ -48452,18 +48816,18 @@ async function executeRemove(packageId, options, cliVersion, events) {
48452
48816
  emitSuccessJson("remove", {
48453
48817
  dryRun: false,
48454
48818
  ...summary,
48455
- removedLock: !packageId || !hasPackages,
48456
- packageId: packageId ?? "*"
48819
+ removedLock: !templateId || !hasPackages,
48820
+ templateId: templateId ?? "*"
48457
48821
  }, [], [], jsonEvents());
48458
48822
  } else {
48459
48823
  printPlanSummary(summary);
48460
- writeHumanOutput(t("remove.removed", packageId ?? t("remove.allPackages"), service.projectRoot) + "\n");
48461
- writeHumanOutput(t(!packageId || !hasPackages ? "remove.lockRemoved" : "remove.lockUpdated") + "\n");
48824
+ writeHumanOutput(t("remove.removed", templateId ?? t("remove.allTemplates"), service.projectRoot) + "\n");
48825
+ writeHumanOutput(t(!templateId || !hasPackages ? "remove.lockRemoved" : "remove.lockUpdated") + "\n");
48462
48826
  }
48463
48827
  return ExitCode.Success;
48464
48828
  });
48465
48829
  }
48466
- async function removeUserReferences(originalLock, packageId, service, output) {
48830
+ async function removeUserReferences(originalLock, templateId, service, output) {
48467
48831
  const installationsRepo = service.getInstallationsRepository();
48468
48832
  const lockRec = originalLock;
48469
48833
  const resolved = lockRec["resolved"];
@@ -48482,10 +48846,10 @@ async function removeUserReferences(originalLock, packageId, service, output) {
48482
48846
  }
48483
48847
  }
48484
48848
  }
48485
- if (packageId) {
48849
+ if (templateId) {
48486
48850
  capabilities = capabilities.filter((cap) => {
48487
48851
  const capPkgId = cap["packageId"];
48488
- return capPkgId === packageId;
48852
+ return capPkgId === templateId;
48489
48853
  });
48490
48854
  }
48491
48855
  const warnings = [];
@@ -48535,6 +48899,7 @@ var init_remove = __esm({
48535
48899
  init_cli_output();
48536
48900
  init_service_locator();
48537
48901
  init_plan_execution();
48902
+ init_task_helper();
48538
48903
  init_i18n();
48539
48904
  }
48540
48905
  });
@@ -49453,7 +49818,7 @@ import { createHash as createHash17, randomUUID as randomUUID10 } from "node:cry
49453
49818
  import { basename as basename7, dirname as dirname19 } from "node:path";
49454
49819
  function createUpgradeCommand(cliVersion) {
49455
49820
  const cmd = new Command("upgrade");
49456
- cmd.description(t("upgrade.description")).option("--project <path>", t("upgrade.optionProject"), process.cwd()).option("--package <package-id>", t("upgrade.optionPackage")).option("--capability <id>", t("upgrade.optionCapability")).option("--version <version>", t("upgrade.optionVersion")).option("--dry-run", t("upgrade.optionDryRun")).option("--yes, -y", t("upgrade.optionYes")).option("--allow <permission>", t("upgrade.optionAllow"), collectPermission, []).action(async (opts) => {
49821
+ cmd.description(t("upgrade.description")).option("--project <path>", t("upgrade.optionProject"), process.cwd()).option("--template <template-id>", t("upgrade.optionTemplate")).option("--capability <id>", t("upgrade.optionCapability")).option("--version <version>", t("upgrade.optionVersion")).option("--dry-run", t("upgrade.optionDryRun")).option("--yes, -y", t("upgrade.optionYes")).option("--allow <permission>", t("upgrade.optionAllow"), collectPermission, []).action(async (opts) => {
49457
49822
  const globalOpts = extractGlobalOptions(opts);
49458
49823
  const output = {
49459
49824
  json: globalOpts.json,
@@ -49472,7 +49837,7 @@ function createUpgradeCommand(cliVersion) {
49472
49837
  }
49473
49838
  async function executeUpgrade(opts, cliVersion) {
49474
49839
  const projectRoot = typeof opts.project === "string" ? opts.project : process.cwd();
49475
- const packageId = typeof opts.package === "string" ? opts.package : void 0;
49840
+ const templateId = typeof opts.template === "string" ? opts.template : void 0;
49476
49841
  const targetVersion = typeof opts.version === "string" ? opts.version : void 0;
49477
49842
  const dryRun = Boolean(opts.dryRun);
49478
49843
  const yes = Boolean(opts.yes);
@@ -49501,7 +49866,7 @@ async function executeUpgrade(opts, cliVersion) {
49501
49866
  { resources: drift.map((item) => ({ type: item.type, path: item.path })) }
49502
49867
  );
49503
49868
  }
49504
- let targetPackageId = packageId;
49869
+ let targetPackageId = templateId;
49505
49870
  const desiredPackages = lock.desired?.packages ?? [];
49506
49871
  if (!targetPackageId) {
49507
49872
  if (desiredPackages.length === 1) {
@@ -49510,9 +49875,9 @@ async function executeUpgrade(opts, cliVersion) {
49510
49875
  targetPackageId = lock.desired.template.id;
49511
49876
  } else {
49512
49877
  throw new CliError(
49513
- "\u8BF7\u901A\u8FC7 --package <package-id> \u6307\u5B9A\u9700\u8981\u5347\u7EA7\u7684\u5305\u3002",
49878
+ t("upgrade.missingTemplate"),
49514
49879
  ExitCode.SchemaInvalid,
49515
- "MISSING_OPTIONS"
49880
+ "PACKAGE_SPEC_REQUIRED"
49516
49881
  );
49517
49882
  }
49518
49883
  }
@@ -49597,12 +49962,7 @@ async function executeUpgrade(opts, cliVersion) {
49597
49962
  if (json) {
49598
49963
  emitSuccessJson("upgrade", { dryRun: true, ...plan });
49599
49964
  } else {
49600
- writeHumanOutput(`\u5347\u7EA7\u8BA1\u5212\uFF1A
49601
- \u5305\uFF1A${targetPackageId}
49602
- \u5F53\u524D\uFF1A${oldVersion}
49603
- \u76EE\u6807\uFF1A${templateResolution.resolvedVersion}
49604
- \u9879\u76EE\uFF1A${projectRoot}
49605
- `);
49965
+ writeHumanOutput(t("upgrade.planSummary", targetPackageId, oldVersion, templateResolution.resolvedVersion, projectRoot));
49606
49966
  }
49607
49967
  return ExitCode.Success;
49608
49968
  }
@@ -49642,18 +50002,12 @@ async function executeUpgrade(opts, cliVersion) {
49642
50002
  previousVersion: oldVersion,
49643
50003
  version: templateResolution.resolvedVersion
49644
50004
  };
49645
- if (!output.json) {
49646
- writeHumanOutput(`
49647
- \u6B63\u5728\u6267\u884C\u524D\u7F6E\u5347\u7EA7\u4EFB\u52A1 (before:upgrade) (${targetPackageId}):
49648
- `);
49649
- }
50005
+ const title = t("task.runningBeforeUpgrade", targetPackageId);
49650
50006
  try {
49651
- await executeTasks(beforeTasks, taskContext, {
49652
- onProgress: (msg) => {
49653
- if (!output.json) writeHumanOutput(`> [${targetPackageId}] ${msg}
49654
- `);
49655
- },
49656
- stdio: output.json ? "ignore" : "inherit"
50007
+ await runTasksWithDynamicUI(beforeTasks, taskContext, {
50008
+ title,
50009
+ verbose: Boolean(opts.verbose),
50010
+ json
49657
50011
  });
49658
50012
  } catch (err) {
49659
50013
  if (err instanceof Error) {
@@ -49704,18 +50058,12 @@ async function executeUpgrade(opts, cliVersion) {
49704
50058
  previousVersion: oldVersion,
49705
50059
  version: templateResolution.resolvedVersion
49706
50060
  };
49707
- if (!output.json) {
49708
- writeHumanOutput(`
49709
- \u6B63\u5728\u6267\u884C\u540E\u7F6E\u5347\u7EA7\u4EFB\u52A1 (after:upgrade) (${targetPackageId}):
49710
- `);
49711
- }
50061
+ const title = t("task.runningAfterUpgrade", targetPackageId);
49712
50062
  try {
49713
- await executeTasks(afterTasks, taskContext, {
49714
- onProgress: (msg) => {
49715
- if (!output.json) writeHumanOutput(`> [${targetPackageId}] ${msg}
49716
- `);
49717
- },
49718
- stdio: output.json ? "ignore" : "inherit"
50063
+ await runTasksWithDynamicUI(afterTasks, taskContext, {
50064
+ title,
50065
+ verbose: Boolean(opts.verbose),
50066
+ json
49719
50067
  });
49720
50068
  } catch (err) {
49721
50069
  if (err instanceof Error) {
@@ -49784,6 +50132,7 @@ var init_upgrade = __esm({
49784
50132
  init_service_locator();
49785
50133
  init_journal_helper();
49786
50134
  init_plan_execution();
50135
+ init_task_helper();
49787
50136
  init_i18n();
49788
50137
  }
49789
50138
  });
@@ -50122,11 +50471,12 @@ import { homedir as homedir4 } from "node:os";
50122
50471
  import { join as join26 } from "node:path";
50123
50472
  function createLaunchCommand() {
50124
50473
  const cmd = new Command("_launch");
50125
- cmd.description(t("launch.description")).option("--kind <kind>", t("launch.optionKind")).option("--package <package-id>", t("launch.optionPackage")).option("--id <id>", t("launch.optionId")).option("--version <version>", t("launch.optionVersion")).option("--command <name>", t("launch.optionCommand")).allowUnknownOption(true).allowExcessArguments(true).action(async (_opts, command) => {
50474
+ cmd.description(t("launch.description")).option("--kind <kind>", t("launch.optionKind")).option("--template <template-id>", t("launch.optionTemplate")).option("--id <id>", t("launch.optionId")).option("--version <version>", t("launch.optionVersion")).option("--command <name>", t("launch.optionCommand")).allowUnknownOption(true).allowExcessArguments(true).action(async (_opts, command) => {
50126
50475
  const opts = command.opts();
50127
50476
  const launcherArgs = [];
50128
50477
  if (opts.kind) launcherArgs.push("--kind", opts.kind);
50129
- if (opts.package) launcherArgs.push("--package", opts.package);
50478
+ const pkgOrTemplate = opts.template ?? opts.package;
50479
+ if (pkgOrTemplate) launcherArgs.push("--package", pkgOrTemplate);
50130
50480
  if (opts.id) launcherArgs.push("--id", opts.id);
50131
50481
  if (opts.version) launcherArgs.push("--version", opts.version);
50132
50482
  if (opts.command) launcherArgs.push("--command", opts.command);
@@ -50563,7 +50913,7 @@ import { createRequire as createRequire2 } from "node:module";
50563
50913
  import { readFileSync as readFileSync4 } from "node:fs";
50564
50914
  import { fileURLToPath as fileURLToPath5 } from "node:url";
50565
50915
  function resolveVersion() {
50566
- if (true) return "0.1.32";
50916
+ if (true) return "0.1.34";
50567
50917
  const candidates = [
50568
50918
  new URL("../package.json", import.meta.url),
50569
50919
  new URL("../../package.json", import.meta.url),