mancode 0.3.5 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -7,9 +7,9 @@ import {
7
7
  import { program } from "commander";
8
8
 
9
9
  // src/commands/init.ts
10
- import { promises as fs3 } from "fs";
10
+ import { promises as fs4 } from "fs";
11
11
  import os from "os";
12
- import path14 from "path";
12
+ import path15 from "path";
13
13
  import process5 from "process";
14
14
 
15
15
  // src/installers/claude-code.ts
@@ -308,8 +308,8 @@ var HEAD_COACH_AGENT = {
308
308
  - \u5C06\u5173\u952E\u51B3\u7B56\u4EA4\u7ED9\u8C03\u7528\u65B9 appendTeamDecision\uFF0C\u5E76\u66F4\u65B0 Active Plans\u3002
309
309
  - \u5408\u5E76 worktree \u524D\u53D6\u5F97\u7528\u6237\u786E\u8BA4\uFF1B\u6E05\u7406\u4E34\u65F6\u6587\u4EF6\u3002
310
310
 
311
- **/mamba \u4EA4\u63A5\u9636\u6BB5**\uFF1A
312
- - \u5F53\u771F\u5B9E\u6D4F\u89C8\u5668\u9A8C\u8BC1\u3001\u590D\u6742\u590D\u73B0\u6216\u56DE\u5F52\u9700\u8981\u4E13\u95E8\u8BCA\u65AD\u65F6\uFF0C\u901A\u8FC7 \`mancode workflow create mamba ... --parent-task <taskId>\` \u521B\u5EFA\u5B50 workflow\uFF1B\u6240\u6709 metadata \u53D8\u5316\u90FD\u8D70 workflow CLI\u3002
311
+ **/manba \u4EA4\u63A5\u9636\u6BB5**\uFF1A
312
+ - \u5F53\u771F\u5B9E\u6D4F\u89C8\u5668\u9A8C\u8BC1\u3001\u590D\u6742\u590D\u73B0\u6216\u56DE\u5F52\u9700\u8981\u4E13\u95E8\u8BCA\u65AD\u65F6\uFF0C\u901A\u8FC7 \`mancode workflow create manba ... --parent-task <taskId>\` \u521B\u5EFA\u5B50 workflow\uFF1B\u6240\u6709 metadata \u53D8\u5316\u90FD\u8D70 workflow CLI\u3002
313
313
  - \u5B50\u4EFB\u52A1 fixed/verified/no_repro \u540E\u56DE\u5230\u7236 /man Step 6\uFF1B\u82E5\u7236\u66FE\u56E0\u8BE5\u5B50\u4EFB\u52A1 blocked\uFF0C\u5148\u7528 workflow CLI \u6062\u590D\u4E3A in_progress\u3002blocked \u6216 manual_test_required \u65F6\u8BA9\u7236 workflow \u540C\u6B65 blocked\uFF0C\u540E\u8005\u4E0D\u5F97\u81EA\u52A8\u6062\u590D\u3002
314
314
 
315
315
  \u4E3B\u89C1\u5F3A\uFF0C\u5FC5\u8981\u65F6\u624D\u95EE\u7528\u6237\u3002\u5F00\u5E72\u3002`
@@ -531,7 +531,8 @@ if (!state) {
531
531
  process.exit(0);
532
532
  }
533
533
 
534
- const mode = text(state.currentMode) || 'solo';
534
+ const storedMode = text(state.currentMode) || 'solo';
535
+ const mode = storedMode === 'mamba' ? 'manba' : storedMode;
535
536
  const techStack = sanitize(state.techStack);
536
537
  const uiLibrary = sanitize(state.uiLibrary);
537
538
  const output = [
@@ -848,7 +849,7 @@ var MAN_SKILL = {
848
849
 
849
850
  ### Step 6: \u81EA\u6D4B\u3001\u8BCA\u65AD\u4E0E\u56DE\u5F52
850
851
 
851
- \u8FD0\u884C\u5B9E\u9645 build/lint/typecheck/test \u548C smoke test\u3002\u76F8\u540C\u4EE3\u7801\u3001\u73AF\u5883\u3001\u547D\u4EE4\u4E0B\u76F8\u540C\u9519\u8BEF\u7B7E\u540D\u5931\u8D25\u4E24\u6B21\uFF0C\u505C\u6B62\u76F2\u8BD5\u5E76\u8BCA\u65AD\u6839\u56E0\u3002\u9700\u8981\u771F\u5B9E\u6D4F\u89C8\u5668\u3001\u590D\u6742\u590D\u73B0\u6216\u56DE\u5F52\u65F6\uFF0C\u7528 \`mancode workflow create mamba "<\u95EE\u9898>" --parent-task <taskId> --json\` \u521B\u5EFA\u5B50 workflow\uFF1B\u7236\u4EFB\u52A1\u4FDD\u6301 Step 6\u3002\u5B50\u4EFB\u52A1 fixed/verified/no_repro \u540E\u6062\u590D\u672C\u4EFB\u52A1\uFF1B\u82E5\u7236\u66FE\u56E0\u8BE5\u5B50\u4EFB\u52A1 blocked\uFF0C\u5148\u901A\u8FC7 \`workflow update --status in_progress\` \u6062\u590D\uFF0C\u518D\u66F4\u65B0\u81F3 Step 7\u3002blocked \u6216 manual_test_required \u4F1A\u7531 CLI \u81EA\u52A8\u963B\u585E\u7236\u4EFB\u52A1\uFF0C\u4E0D\u5F97\u624B\u6539\u7236 metadata\uFF0C\u4E5F\u4E0D\u5F97\u81EA\u52A8\u8D8A\u8FC7\u4EBA\u5DE5\u9A8C\u8BC1\u8981\u6C42\u3002
852
+ \u8FD0\u884C\u5B9E\u9645 build/lint/typecheck/test \u548C smoke test\u3002\u76F8\u540C\u4EE3\u7801\u3001\u73AF\u5883\u3001\u547D\u4EE4\u4E0B\u76F8\u540C\u9519\u8BEF\u7B7E\u540D\u5931\u8D25\u4E24\u6B21\uFF0C\u505C\u6B62\u76F2\u8BD5\u5E76\u8BCA\u65AD\u6839\u56E0\u3002\u9700\u8981\u771F\u5B9E\u6D4F\u89C8\u5668\u3001\u590D\u6742\u590D\u73B0\u6216\u56DE\u5F52\u65F6\uFF0C\u7528 \`mancode workflow create manba "<\u95EE\u9898>" --parent-task <taskId> --json\` \u521B\u5EFA\u5B50 workflow\uFF1B\u7236\u4EFB\u52A1\u4FDD\u6301 Step 6\u3002\u5B50\u4EFB\u52A1 fixed/verified/no_repro \u540E\u6062\u590D\u672C\u4EFB\u52A1\uFF1B\u82E5\u7236\u66FE\u56E0\u8BE5\u5B50\u4EFB\u52A1 blocked\uFF0C\u5148\u901A\u8FC7 \`workflow update --status in_progress\` \u6062\u590D\uFF0C\u518D\u66F4\u65B0\u81F3 Step 7\u3002blocked \u6216 manual_test_required \u4F1A\u7531 CLI \u81EA\u52A8\u963B\u585E\u7236\u4EFB\u52A1\uFF0C\u4E0D\u5F97\u624B\u6539\u7236 metadata\uFF0C\u4E5F\u4E0D\u5F97\u81EA\u52A8\u8D8A\u8FC7\u4EBA\u5DE5\u9A8C\u8BC1\u8981\u6C42\u3002
852
853
 
853
854
  \u9A8C\u8BC1\u540E\u57FA\u4E8E**\u5B9E\u9645 diff**\u5199 \`review-scope.md\`\uFF1Abase\u3001\u6539\u52A8\u6587\u4EF6\u3001\u9700\u6C42\u3001\u5DF2\u8DD1\u9A8C\u8BC1\u3001\u786C\u98CE\u9669\u548C\u5BA1\u67E5\u6DF1\u5EA6\u3002\u9274\u6743\u3001\u652F\u4ED8\u3001\u654F\u611F\u6570\u636E\u3001\u8FC1\u79FB/\u5220\u9664\u3001\u516C\u5F00 API\u3001\u672A\u53EF\u4FE1\u8F93\u5165\u3001\u5E76\u53D1\u3001\u8DE8\u670D\u52A1\u6216\u57FA\u7840\u8BBE\u65BD\u547D\u4E2D\u4EFB\u4E00\u9879\u65F6\u7528\u5B8C\u6574\u5BA1\u67E5 \`full\`\uFF1B\u5426\u5219\u7528\u5B9A\u5411\u5BA1\u67E5 \`targeted\`\u3002\u8FD0\u884C \`mancode workflow review <taskId> init --review-depth targeted --review-domain quality\` \u6216 \`--review-depth full\`\u3002\u7528\u6237\u660E\u786E\u8DF3\u8FC7\u5BA1\u67E5\u65F6\u624D\u628A \`review\` \u5199\u5165\u7D2F\u8BA1 skippedSteps\uFF0C\u5E76\u8BB0\u5F55\u6B8B\u4F59\u98CE\u9669\u3002
854
855
 
@@ -877,15 +878,15 @@ ${CORE_CODING_PRINCIPLES}
877
878
 
878
879
  // src/templates/skills/mamba.ts
879
880
  var MAMBA_SKILL = {
880
- name: "mamba",
881
+ name: "manba",
881
882
  description: "Diagnose bugs and validate real user flows. Reproduce, find the root cause, run targeted regression checks, and use browser automation when the platform supports it.",
882
- body: `# mancode \xB7 /mamba (Diagnosis & Real Validation)
883
+ body: `# mancode \xB7 /manba (Diagnosis & Real Validation)
883
884
 
884
- \u7528\u6237\u7528 \`/mamba <\u95EE\u9898\u6216\u6A21\u5757>\` \u89E6\u53D1\u4F60\u3002\u76EE\u6807\u662F\u7528\u8BC1\u636E\u56DE\u7B54\uFF1A\u80FD\u5426\u590D\u73B0\u3001\u6839\u56E0\u5728\u54EA\u91CC\u3001\u4FEE\u590D\u662F\u5426\u6709\u6548\u3001\u5173\u952E\u8DEF\u5F84\u662F\u5426\u56DE\u5F52\u3002
885
+ \u7528\u6237\u7528 \`/manba <\u95EE\u9898\u6216\u6A21\u5757>\` \u89E6\u53D1\u4F60\u3002\u76EE\u6807\u662F\u7528\u8BC1\u636E\u56DE\u7B54\uFF1A\u80FD\u5426\u590D\u73B0\u3001\u6839\u56E0\u5728\u54EA\u91CC\u3001\u4FEE\u590D\u662F\u5426\u6709\u6548\u3001\u5173\u952E\u8DEF\u5F84\u662F\u5426\u56DE\u5F52\u3002\u5BF9\u5916\u6A21\u5F0F\u540D\u662F manba\uFF1B\u6301\u4E45\u5316 workflow/state \u4E3A\u517C\u5BB9\u5386\u53F2\u6570\u636E\u7EE7\u7EED\u4F7F\u7528\u5185\u90E8\u503C mamba\u3002
885
886
 
886
887
  ## 1. \u5EFA\u7ACB\u4EFB\u52A1
887
888
 
888
- \u5148\u8BFB state\u3002\u82E5 \`currentTask\` \u6307\u5411 unrelated active workflow\uFF0C\u505C\u6B62\u5E76\u8BA9\u7528\u6237\u9009\u62E9\u6062\u590D\u8BE5\u6D41\u7A0B\u6216\u5148\u7528 /mansolo \u653E\u5F03\uFF1B\u4E0D\u5F97\u8986\u76D6\u65E7\u6307\u9488\u3002\u72EC\u7ACB\u4EFB\u52A1\u8FD0\u884C \`mancode workflow create mamba "<\u95EE\u9898\u6216\u6A21\u5757>" --json\`\uFF1B\u7531 /man \u6216 /manteam Step 6 \u8F6C\u5165\u65F6\u8FD0\u884C \`mancode workflow create mamba "<\u95EE\u9898\u6216\u6A21\u5757>" --parent-task <\u7236taskId> --json\`\u3002\u8BFB\u53D6\u8FD4\u56DE taskId \u540E\uFF0C\u5C06 state \u7684 currentMode/currentTask/currentWorkflowMode \u6307\u5411 mamba\u3002\u4E0D\u5F97\u76F4\u63A5\u521B\u5EFA\u6216\u6539\u5199 metadata.json\u3002
889
+ \u5148\u8BFB state\u3002\u82E5 \`currentTask\` \u6307\u5411 unrelated active workflow\uFF0C\u505C\u6B62\u5E76\u8BA9\u7528\u6237\u9009\u62E9\u6062\u590D\u8BE5\u6D41\u7A0B\u6216\u5148\u7528 /mansolo \u653E\u5F03\uFF1B\u4E0D\u5F97\u8986\u76D6\u65E7\u6307\u9488\u3002\u72EC\u7ACB\u4EFB\u52A1\u8FD0\u884C \`mancode workflow create manba "<\u95EE\u9898\u6216\u6A21\u5757>" --json\`\uFF1B\u7531 /man \u6216 /manteam Step 6 \u8F6C\u5165\u65F6\u8FD0\u884C \`mancode workflow create manba "<\u95EE\u9898\u6216\u6A21\u5757>" --parent-task <\u7236taskId> --json\`\u3002\u8BFB\u53D6\u8FD4\u56DE taskId \u540E\uFF0C\u5C06 state \u7684 currentMode/currentTask/currentWorkflowMode \u6307\u5411\u5185\u90E8\u517C\u5BB9\u503C mamba\u3002\u4E0D\u5F97\u76F4\u63A5\u521B\u5EFA\u6216\u6539\u5199 metadata.json\u3002
889
890
 
890
891
  \u8BB0\u5F55\u73B0\u8C61\u3001\u73AF\u5883\u3001\u590D\u73B0\u6761\u4EF6\u3001\u9884\u671F\u4E0E\u5B9E\u9645\u7ED3\u679C\u3001\u4E0D\u53EF\u89E6\u78B0\u7684\u6570\u636E\u3002\u5148\u68C0\u67E5\u5DF2\u6709\u6D4B\u8BD5\u3001\u8DEF\u7531\u3001\u6A21\u5757\u5165\u53E3\u548C README\uFF1B\u4ECD\u65E0\u6CD5\u786E\u5B9A\u6700\u5C0F\u8DEF\u5F84\u65F6\u53EA\u95EE\u5173\u952E\u8DEF\u5F84\u95EE\u9898\u3002\u5B8C\u6210\u540E\u7528 CLI \u66F4\u65B0\u81F3 Step 2\u3002
891
892
 
@@ -900,7 +901,7 @@ var MAMBA_SKILL = {
900
901
 
901
902
  \u4EC5\u5F53 profile \u786E\u8BA4 Web UI \u4E14\u6D4F\u89C8\u5668\u80FD\u529B\u53EF\u7528\u65F6\uFF0C\u68C0\u67E5 \`npx\` \u5E76\u4F7F\u7528\u9879\u76EE\u7684 Playwright CLI wrapper\u3002\u5176\u4ED6\u9879\u76EE\u7C7B\u578B\u4F7F\u7528\u5DF2\u68C0\u6D4B\u5230\u7684 API\u3001\u6A21\u62DF\u5668\u3001\u8BBE\u5907\u3001\u547D\u4EE4\u6216\u5951\u7EA6\u9A8C\u8BC1\u65B9\u5F0F\u3002\u6D4F\u89C8\u5668\u9A8C\u8BC1\u65F6\u5148 snapshot \u518D\u4F7F\u7528\u5143\u7D20\u5F15\u7528\uFF1B\u5BFC\u822A\u3001\u5F39\u7A97\u6216 UI \u5927\u53D8\u5316\u540E\u91CD\u65B0 snapshot\u3002\u622A\u56FE\u3001trace \u548C\u6D4F\u89C8\u5668\u65E5\u5FD7\u5199\u5165 \`.mancode/workflows/<taskId>/artifacts/playwright/\`\uFF0C\u62A5\u544A\u53EA\u5199\u76F8\u5BF9\u8DEF\u5F84\uFF0C\u5E76\u8131\u654F Token\u3001Cookie\u3001\u4E2A\u4EBA\u6216\u4E1A\u52A1\u654F\u611F\u6570\u636E\u3002
902
903
 
903
- \u73AF\u5883\u5C31\u7EEA\u540E\u7528 CLI \u66F4\u65B0\u81F3 Step 3\uFF1B\u7F3A\u5C11\u73AF\u5883\u3001\u6743\u9650\u6216\u6570\u636E\u5219\u76F4\u63A5\u5199 blocked + blockingReason\uFF0C\u5E76\u4FDD\u7559 state \u6307\u5411\u5F53\u524D mamba \u4EE5\u4FBF\u6062\u590D\u3002
904
+ \u73AF\u5883\u5C31\u7EEA\u540E\u7528 CLI \u66F4\u65B0\u81F3 Step 3\uFF1B\u7F3A\u5C11\u73AF\u5883\u3001\u6743\u9650\u6216\u6570\u636E\u5219\u76F4\u63A5\u5199 blocked + blockingReason\uFF0C\u5E76\u4FDD\u7559 state \u6307\u5411\u5F53\u524D manba \u4EE5\u4FBF\u6062\u590D\u3002
904
905
 
905
906
  ## 3. \u590D\u73B0\u4E0E\u8BCA\u65AD
906
907
 
@@ -920,7 +921,7 @@ var MAMBA_SKILL = {
920
921
  - \u7F3A\u5C11\u73AF\u5883\u3001\u6743\u9650\u6216\u6570\u636E\uFF0C\u6216\u4FEE\u590D\u4ECD\u5931\u8D25\uFF1A\`status: "blocked"\` + \`blockingReason\`
921
922
  - \u53D7\u9650\u5E73\u53F0\u53EA\u80FD\u751F\u6210\u624B\u6D4B\u65B9\u6848\uFF1A\`status: "completed", outcome: "manual_test_required"\`\uFF1B\u5FC5\u987B\u660E\u786E\u6CA1\u6709\u6267\u884C\u771F\u5B9E\u6D4B\u8BD5
922
923
 
923
- \u7528 \`mancode workflow update <taskId> --status <status> [--outcome <outcome>] [--blocking-reason <\u539F\u56E0>]\` \u5199\u7ED3\u8BBA\u3002\u7236\u5B50\u4EFB\u52A1\u7684 blocked/manual_test_required \u4F20\u64AD\u7531 CLI \u8D1F\u8D23\u3002\u5173\u8054\u5B50\u4EFB\u52A1\u4EE5 fixed/verified/no_repro \u5B8C\u6210\u540E\uFF0C\u5148\u8BFB\u53D6\u7236 workflow\uFF1B\u82E5\u7236\u4ECD\u56E0\u672C\u5B50\u4EFB\u52A1 blocked\uFF0C\u8FD0\u884C \`mancode workflow update <parentTaskId> --status in_progress\` \u6E05\u9664\u963B\u585E\uFF0C\u518D\u628A state \u6062\u590D\u5230\u7236 workflow \u7684 Step 6\u3002manual_test_required \u4E0D\u5F97\u81EA\u52A8\u6062\u590D\u7236\u4EFB\u52A1\u3002\u72EC\u7ACB\u4EFB\u52A1\u5B8C\u6210\u540E\u56DE solo\uFF1Bblocked \u7684\u72EC\u7ACB\u4EFB\u52A1\u7EE7\u7EED\u4FDD\u6301 mamba state\u3002\u4EFB\u4F55\u60C5\u51B5\u4E0B\u90FD\u4E0D\u5F97\u76F4\u63A5\u7F16\u8F91 metadata \u7ED5\u8FC7 CLI\u3002
924
+ \u7528 \`mancode workflow update <taskId> --status <status> [--outcome <outcome>] [--blocking-reason <\u539F\u56E0>]\` \u5199\u7ED3\u8BBA\u3002\u7236\u5B50\u4EFB\u52A1\u7684 blocked/manual_test_required \u4F20\u64AD\u7531 CLI \u8D1F\u8D23\u3002\u5173\u8054\u5B50\u4EFB\u52A1\u4EE5 fixed/verified/no_repro \u5B8C\u6210\u540E\uFF0C\u5148\u8BFB\u53D6\u7236 workflow\uFF1B\u82E5\u7236\u4ECD\u56E0\u672C\u5B50\u4EFB\u52A1 blocked\uFF0C\u8FD0\u884C \`mancode workflow update <parentTaskId> --status in_progress\` \u6E05\u9664\u963B\u585E\uFF0C\u518D\u628A state \u6062\u590D\u5230\u7236 workflow \u7684 Step 6\u3002manual_test_required \u4E0D\u5F97\u81EA\u52A8\u6062\u590D\u7236\u4EFB\u52A1\u3002\u72EC\u7ACB\u4EFB\u52A1\u5B8C\u6210\u540E\u56DE solo\uFF1Bblocked \u7684\u72EC\u7ACB\u4EFB\u52A1\u7EE7\u7EED\u4FDD\u6301 manba \u6A21\u5F0F\uFF08state \u5185\u90E8\u503C\u4E3A mamba\uFF09\u3002\u4EFB\u4F55\u60C5\u51B5\u4E0B\u90FD\u4E0D\u5F97\u76F4\u63A5\u7F16\u8F91 metadata \u7ED5\u8FC7 CLI\u3002
924
925
 
925
926
  ${CORE_CODING_PRINCIPLES}
926
927
  `
@@ -1121,8 +1122,8 @@ var MANSOLO_SKILL = {
1121
1122
 
1122
1123
  - **\u6CA1\u6709 .mancode/state.json**\uFF1A\u544A\u8BC9\u7528\u6237\uFF1A"\u9879\u76EE\u672A\u521D\u59CB\u5316\uFF0C\u8FD0\u884C \`mancode init\`\u3002"
1123
1124
  - **state.json \u5DF2\u662F solo**\uFF1A\u4ECD\u6B63\u5E38\u6267\u884C\uFF0C\u544A\u77E5\u7528\u6237\u5F53\u524D\u5DF2\u662F solo\u3002
1124
- - **\u5F53\u524D task \u5DF2\u662F completed/abandoned**\uFF1A\u4E0D\u8981\u5C1D\u8BD5\u628A\u7EC8\u6001\u6539\u6210 abandoned\uFF1B\u76F4\u63A5\u6E05\u7406 state\u3002\u82E5\u5B83\u662F\u5173\u8054 mamba \u4E14\u7236\u4EFB\u52A1\u4ECD active\uFF0C\u5148\u5C55\u793A\u7236\u4EFB\u52A1\u5E76\u6309\u4E0B\u4E00\u6761\u786E\u8BA4\u662F\u5426\u4E00\u5E76\u653E\u5F03\u3002
1125
- - **\u5F53\u524D\u5728 active /man /mamba /manteam \u6D41\u7A0B\u4E2D**\uFF1A\u7528 AskUserQuestion \u95EE\u7528\u6237\uFF1A
1125
+ - **\u5F53\u524D task \u5DF2\u662F completed/abandoned**\uFF1A\u4E0D\u8981\u5C1D\u8BD5\u628A\u7EC8\u6001\u6539\u6210 abandoned\uFF1B\u76F4\u63A5\u6E05\u7406 state\u3002\u82E5\u5B83\u662F\u5173\u8054 manba \u4E14\u7236\u4EFB\u52A1\u4ECD active\uFF0C\u5148\u5C55\u793A\u7236\u4EFB\u52A1\u5E76\u6309\u4E0B\u4E00\u6761\u786E\u8BA4\u662F\u5426\u4E00\u5E76\u653E\u5F03\u3002
1126
+ - **\u5F53\u524D\u5728 active /man /manba /manteam \u6D41\u7A0B\u4E2D**\uFF1A\u7528 AskUserQuestion \u95EE\u7528\u6237\uFF1A
1126
1127
  \`\`\`
1127
1128
  AskUserQuestion({
1128
1129
  questions: [{
@@ -1138,7 +1139,7 @@ var MANSOLO_SKILL = {
1138
1139
  \`\`\`
1139
1140
  \u7528\u6237\u786E\u8BA4\u540E\uFF1A
1140
1141
  - \u5148\u7528 \`mancode workflow show <taskId> --json\` \u68C0\u67E5\u7236\u5B50\u5173\u7CFB\u548C activeChildren\u3002
1141
- - \u82E5\u5B58\u5728\u6D3B\u8DC3\u5B50\u4EFB\u52A1\u6216\u5F53\u524D\u662F\u5E26 parentTaskId \u7684 mamba\uFF0C\u660E\u786E\u8BF4\u660E\u5C06\u653E\u5F03\u7684 workflow \u94FE\uFF1B\u5148\u9010\u4E2A\u7528 CLI \u6807\u8BB0\u5B50\u4EFB\u52A1 abandoned\uFF0C\u518D\u6807\u8BB0\u7236/\u5F53\u524D\u4EFB\u52A1 abandoned\u3002
1142
+ - \u82E5\u5B58\u5728\u6D3B\u8DC3\u5B50\u4EFB\u52A1\u6216\u5F53\u524D\u662F\u5E26 parentTaskId \u7684 manba\uFF0C\u660E\u786E\u8BF4\u660E\u5C06\u653E\u5F03\u7684 workflow \u94FE\uFF1B\u5148\u9010\u4E2A\u7528 CLI \u6807\u8BB0\u5B50\u4EFB\u52A1 abandoned\uFF0C\u518D\u6807\u8BB0\u7236/\u5F53\u524D\u4EFB\u52A1 abandoned\u3002
1142
1143
  - \u6240\u6709 metadata \u72B6\u6001\u90FD\u5FC5\u987B\u901A\u8FC7 \`mancode workflow update <taskId> --status abandoned\` \u66F4\u65B0\uFF1BCLI \u62D2\u7EDD\u65F6\u505C\u6B62\uFF0C\u4E0D\u5F97\u76F4\u63A5 Edit \u7ED5\u8FC7\u3002
1143
1144
  - \u6210\u529F\u540E\u518D\u66F4\u65B0 state.json \u5207\u56DE solo\uFF1BCLI \u4F1A\u540C\u6B65\u6E05\u7406 Active Plans\u3002
1144
1145
 
@@ -1193,12 +1194,12 @@ var MANTEAM_SKILL = {
1193
1194
  3. Game Plan\uFF1A\u8BA1\u5212\u91CC\u5FC5\u987B\u5305\u542B\u53D8\u66F4\u8FB9\u754C\u3001\u517C\u5BB9\u6027\u98CE\u9669\u3001\u56DE\u6EDA\u65B9\u5F0F\uFF1BPlan Coach \u53EA\u8FD4\u56DE\u8BA1\u5212\u6587\u672C\uFF0C\u7981\u6B62\u63D0\u524D\u4FEE\u6539\u4E1A\u52A1\u6587\u4EF6\u6216\u56E2\u961F memory\u3002
1194
1195
  4. \u8BA1\u5212\u5173\u5361\uFF1A\u7528\u6237\u53EF\u53EA\u4FDD\u7559\u8BA1\u5212\u3001\u7EE7\u7EED\u6267\u884C\u6216\u91CD\u5199\u8BA1\u5212\uFF1BActive Plans \u6309 taskId \u66F4\u65B0\u3002
1195
1196
  5. \u5B9E\u65BD\uFF1A\u6539\u52A8\u524D\u518D\u6B21\u68C0\u67E5 \`git status --short\`\uFF0C\u907F\u514D\u8E29\u7528\u6237\u6216\u961F\u53CB\u6539\u52A8\u3002
1196
- 6. Self-test\uFF1A\u4F18\u5148\u8DD1\u9879\u76EE\u5DF2\u6709\u9A8C\u8BC1\u547D\u4EE4\uFF1B\u5931\u8D25\u4E24\u6B21\u505C\u4E0B\u8BCA\u65AD\u6839\u56E0\u3002\u9700\u8981\u771F\u5B9E\u9A8C\u8BC1\u65F6\u521B\u5EFA\u5E26 parentTaskId \u7684 /mamba \u5B50\u4EFB\u52A1\u3002\u5B50\u4EFB\u52A1\u4FEE\u590D\u540E\u82E5\u7236\u4EFB\u52A1\u66FE\u56E0\u6B64 blocked\uFF0C\u5148\u7528 workflow CLI \u6062\u590D\u7236\u4EFB\u52A1\u4E3A in_progress\uFF1Bmanual_test_required \u4E0D\u5F97\u81EA\u52A8\u6062\u590D\u3002
1197
+ 6. Self-test\uFF1A\u4F18\u5148\u8DD1\u9879\u76EE\u5DF2\u6709\u9A8C\u8BC1\u547D\u4EE4\uFF1B\u5931\u8D25\u4E24\u6B21\u505C\u4E0B\u8BCA\u65AD\u6839\u56E0\u3002\u9700\u8981\u771F\u5B9E\u9A8C\u8BC1\u65F6\u521B\u5EFA\u5E26 parentTaskId \u7684 /manba \u5B50\u4EFB\u52A1\u3002\u5B50\u4EFB\u52A1\u4FEE\u590D\u540E\u82E5\u7236\u4EFB\u52A1\u66FE\u56E0\u6B64 blocked\uFF0C\u5148\u7528 workflow CLI \u6062\u590D\u7236\u4EFB\u52A1\u4E3A in_progress\uFF1Bmanual_test_required \u4E0D\u5F97\u81EA\u52A8\u6062\u590D\u3002
1197
1198
  7. Review scope + Film #1\uFF1A\u57FA\u4E8E\u5B9E\u9645 diff \u5199 \`review-scope.md\`\uFF0C\u7528 \`workflow review ... init\` \u9009\u62E9 targeted \u6216 full\uFF1B\u91CD\u70B9\u5BA1\u67E5\u884C\u4E3A\u3001\u53EF\u7EF4\u62A4\u6027\u3001\u56E2\u961F\u98CE\u683C\u4E0E\u6D4B\u8BD5\uFF0Cfinding \u5FC5\u987B\u6709\u8BC1\u636E\u548C\u7A33\u5B9A ID\u3002
1198
1199
  8. Film #2\uFF1A\u4EC5 full \u6267\u884C\uFF0C\u5148\u8BFB Film #1 \u62A5\u544A\u5E76\u53BB\u91CD\uFF0C\u53EA\u5BA1\u67E5\u8FB9\u754C\u3001\u5B89\u5168\u3001\u6027\u80FD\u3001\u5E76\u53D1\u548C\u517C\u5BB9\u6027\u3002\u7528\u6237\u660E\u786E\u8981\u6C42\u624D\u53EF\u8DF3\u8FC7\u5168\u90E8 review\uFF0C\u5E76\u5199\u5165 \`skippedSteps\` \u548C\u6B8B\u4F59\u98CE\u9669\u3002
1199
1200
  9. Post-game\uFF1A\u6C47\u603B blocker\uFF0C\u53EA\u505A\u4E00\u8F6E\u4FEE\u590D\u5E76\u7528 \`workflow review ... remediate\` \u8BB0\u5F55\uFF1B\u590D\u9A8C\u540E\u5199 summary \u4E0E hand-off\u3002\u9A8C\u8BC1\u5931\u8D25\u3001\u5BA1\u67E5\u4E0D\u5B8C\u6574\u6216\u4ECD\u6709 blocker \u65F6\u6807\u8BB0 blocked\uFF0C\u4E0D\u5F97\u6807 completed\u3002
1200
1201
 
1201
- \u5982\u679C\u7528\u6237\u5728\u786E\u8BA4\u9636\u6BB5\u9009\u62E9"\u9000\u51FA"\u6216\u653E\u5F03\u56E2\u961F workflow\uFF1A\u7528 \`mancode workflow update <taskId> --status abandoned\` \u66F4\u65B0\u5E76\u6E05\u7406 Active Plans\uFF1B\u82E5\u6709\u6D3B\u8DC3 mamba \u5B50\u4EFB\u52A1\uFF0C\u5148\u53D6\u5F97\u786E\u8BA4\u5E76\u9010\u4E2A abandoned\u3002\u6210\u529F\u540E\u518D\u7528 Edit \u66F4\u65B0 state \u56DE solo\u3002\u4E0D\u8981\u76F4\u63A5\u6539 metadata\uFF0C\u4E5F\u4E0D\u8981\u628A abandoned workflow \u7559\u5728 active state\u3002
1202
+ \u5982\u679C\u7528\u6237\u5728\u786E\u8BA4\u9636\u6BB5\u9009\u62E9"\u9000\u51FA"\u6216\u653E\u5F03\u56E2\u961F workflow\uFF1A\u7528 \`mancode workflow update <taskId> --status abandoned\` \u66F4\u65B0\u5E76\u6E05\u7406 Active Plans\uFF1B\u82E5\u6709\u6D3B\u8DC3 manba \u5B50\u4EFB\u52A1\uFF0C\u5148\u53D6\u5F97\u786E\u8BA4\u5E76\u9010\u4E2A abandoned\u3002\u6210\u529F\u540E\u518D\u7528 Edit \u66F4\u65B0 state \u56DE solo\u3002\u4E0D\u8981\u76F4\u63A5\u6539 metadata\uFF0C\u4E5F\u4E0D\u8981\u628A abandoned workflow \u7559\u5728 active state\u3002
1202
1203
 
1203
1204
  ## Team Hand-off Summary
1204
1205
 
@@ -1493,6 +1494,7 @@ var LEGACY_CLAUDE_SKILL_SETTINGS = {
1493
1494
  man: ".claude/skills/mancode-man.md",
1494
1495
  mansolo: ".claude/skills/mancode-mansolo.md"
1495
1496
  };
1497
+ var LEGACY_MVP2_SKILL_NAMES = ["mamba", "man8"];
1496
1498
  async function validateClaudeCodeSettings(projectRoot) {
1497
1499
  await readClaudeSettings(path3.join(projectRoot, ".claude"));
1498
1500
  }
@@ -1500,6 +1502,7 @@ async function installClaudeCode(projectRoot, options) {
1500
1502
  const claudeDir = path3.join(projectRoot, ".claude");
1501
1503
  const settings = await readClaudeSettings(claudeDir);
1502
1504
  const force = options.force ?? false;
1505
+ await validateClaudeWriteTargets(claudeDir, options.minimal ?? false, force);
1503
1506
  await installMancodeCore(projectRoot);
1504
1507
  await mkdir3(path3.join(claudeDir, "skills"), { recursive: true });
1505
1508
  await installSoloSkill(path3.join(claudeDir, "skills"), force);
@@ -1516,6 +1519,33 @@ async function installClaudeCode(projectRoot, options) {
1516
1519
  await updateClaudeSettings(claudeDir, settings);
1517
1520
  await removeLegacyHookFiles(projectRoot);
1518
1521
  }
1522
+ async function validateClaudeWriteTargets(claudeDir, minimal, force) {
1523
+ if (!force) return;
1524
+ const skillsDir = path3.join(claudeDir, "skills");
1525
+ await assertWritableClaudeSkill(skillsDir, "solo");
1526
+ if (minimal) return;
1527
+ for (const skill of MVP2_SKILLS) {
1528
+ await assertWritableClaudeSkill(skillsDir, skill.name);
1529
+ }
1530
+ for (const agent of ALL_AGENTS) {
1531
+ const agentPath = path3.join(claudeDir, "agents", `${agent.name}.md`);
1532
+ const existing = await readTextIfExists2(agentPath);
1533
+ if (existing !== null && !isGeneratedClaudeAgent(existing, agent.name)) {
1534
+ throw new Error(
1535
+ `refusing to overwrite user-authored Claude Code agent: ${agentPath}`
1536
+ );
1537
+ }
1538
+ }
1539
+ }
1540
+ async function assertWritableClaudeSkill(skillsDir, modeName) {
1541
+ const skillPath = path3.join(skillsDir, modeName, "SKILL.md");
1542
+ const existing = await readTextIfExists2(skillPath);
1543
+ if (existing !== null && !isGeneratedClaudeSkill(existing, modeName)) {
1544
+ throw new Error(
1545
+ `refusing to overwrite user-authored Claude Code skill: ${skillPath}`
1546
+ );
1547
+ }
1548
+ }
1519
1549
  async function removeLegacyHookFiles(projectRoot) {
1520
1550
  const hooksDir = path3.join(projectRoot, ".mancode", "hooks");
1521
1551
  await Promise.all([
@@ -1536,20 +1566,24 @@ async function installSoloSkill(skillsDir, force) {
1536
1566
  await removeLegacyFlatSkill(skillsDir, "mancode-solo", "solo");
1537
1567
  }
1538
1568
  async function installMvp2Skills(skillsDir, force) {
1539
- await removeManagedLegacyMan8Skill(skillsDir);
1540
1569
  for (const skill of MVP2_SKILLS) {
1541
1570
  await installProjectSkill(skillsDir, skill, force);
1542
1571
  await removeLegacyFlatSkill(skillsDir, `mancode-${skill.name}`, skill.name);
1543
1572
  }
1573
+ await removeManagedLegacyMvp2Skills(skillsDir);
1544
1574
  }
1545
- async function removeManagedLegacyMan8Skill(skillsDir) {
1546
- await removeGeneratedSkillDir(skillsDir, "man8");
1575
+ async function removeManagedLegacyMvp2Skills(skillsDir) {
1576
+ for (const modeName of LEGACY_MVP2_SKILL_NAMES) {
1577
+ await removeGeneratedSkillDir(skillsDir, modeName);
1578
+ await removeLegacyFlatSkill(skillsDir, `mancode-${modeName}`, modeName);
1579
+ }
1547
1580
  }
1548
1581
  async function uninstallMvp2Skills(skillsDir) {
1549
1582
  for (const skill of MVP2_SKILLS) {
1550
1583
  await removeGeneratedSkillDir(skillsDir, skill.name);
1551
1584
  await removeLegacyFlatSkill(skillsDir, `mancode-${skill.name}`, skill.name);
1552
1585
  }
1586
+ await removeManagedLegacyMvp2Skills(skillsDir);
1553
1587
  }
1554
1588
  async function installProjectSkill(skillsDir, skill, force = true) {
1555
1589
  const skillDir = path3.join(skillsDir, skill.name);
@@ -1615,7 +1649,7 @@ async function removeClaudeGeneratedContent(projectRoot) {
1615
1649
  const skillsDir = path3.join(claudeDir, "skills");
1616
1650
  for (const modeName of [
1617
1651
  "solo",
1618
- "man8",
1652
+ ...LEGACY_MVP2_SKILL_NAMES,
1619
1653
  ...MVP2_SKILLS.map((skill) => skill.name)
1620
1654
  ]) {
1621
1655
  await removeGeneratedSkillDir(skillsDir, modeName);
@@ -1650,8 +1684,9 @@ ${marker}
1650
1684
  async function readTextIfExists2(filePath) {
1651
1685
  try {
1652
1686
  return await readFile3(filePath, "utf-8");
1653
- } catch {
1654
- return null;
1687
+ } catch (error) {
1688
+ if (isNodeError2(error) && error.code === "ENOENT") return null;
1689
+ throw error;
1655
1690
  }
1656
1691
  }
1657
1692
  async function removeIfEmpty(dir) {
@@ -1783,13 +1818,13 @@ import path6 from "path";
1783
1818
  import { mkdir as mkdir4, readFile as readFile4, readdir as readdir2, rm as rm2, writeFile as writeFile4 } from "fs/promises";
1784
1819
  import path4 from "path";
1785
1820
  var MODE_NAMES = [
1786
- "mamba",
1821
+ "manba",
1787
1822
  "man",
1788
1823
  "manteam",
1789
1824
  "manps",
1790
1825
  "mansolo"
1791
1826
  ];
1792
- var LEGACY_MODE_NAMES = ["man8"];
1827
+ var LEGACY_MODE_NAMES = ["mamba", "man8"];
1793
1828
  var CODEX_SKILL_MANAGED_MARKER = "<!-- Managed by mancode:codex-skill. Do not edit this file manually. -->";
1794
1829
  var ZCODE_SKILL_MANAGED_MARKER = "<!-- Managed by mancode:zcode-skill. Do not edit this file manually. -->";
1795
1830
  var MODE_FILE_MANAGED_MARKER = "<!-- Managed by mancode:mode-file. Do not edit this file manually. -->";
@@ -1799,7 +1834,7 @@ var MANCODE_AGENT_SKILL_MARKERS = [
1799
1834
  ];
1800
1835
  function renderModeSkill(mode, commandPrefix = "$") {
1801
1836
  const meta = MODE_META[mode];
1802
- const stateMode = mode === "mansolo" ? "solo" : mode;
1837
+ const stateMode = mode === "mansolo" ? "solo" : mode === "manba" ? "mamba" : mode;
1803
1838
  const modesList = MODE_NAMES.map((m) => `${commandPrefix}${m}`).join(", ");
1804
1839
  return [
1805
1840
  meta.intro,
@@ -1840,7 +1875,6 @@ async function installCodexSkills(projectRoot, minimal) {
1840
1875
  return;
1841
1876
  }
1842
1877
  const skillsDir = path4.join(projectRoot, ".agents", "skills");
1843
- await removeLegacyManagedSkills(skillsDir, MANCODE_AGENT_SKILL_MARKERS);
1844
1878
  for (const mode of MODE_NAMES) {
1845
1879
  const modeDir = path4.join(skillsDir, mode);
1846
1880
  await mkdir4(modeDir, { recursive: true });
@@ -1864,6 +1898,7 @@ async function installCodexSkills(projectRoot, minimal) {
1864
1898
  MANCODE_AGENT_SKILL_MARKERS
1865
1899
  );
1866
1900
  }
1901
+ await removeLegacyManagedSkills(skillsDir, MANCODE_AGENT_SKILL_MARKERS);
1867
1902
  }
1868
1903
  async function installZcodeSkills(projectRoot, minimal) {
1869
1904
  if (minimal) {
@@ -1871,7 +1906,6 @@ async function installZcodeSkills(projectRoot, minimal) {
1871
1906
  return;
1872
1907
  }
1873
1908
  const skillsDir = path4.join(projectRoot, ".agents", "skills");
1874
- await removeLegacyManagedSkills(skillsDir, MANCODE_AGENT_SKILL_MARKERS);
1875
1909
  for (const mode of MODE_NAMES) {
1876
1910
  const modeDir = path4.join(skillsDir, mode);
1877
1911
  await mkdir4(modeDir, { recursive: true });
@@ -1895,6 +1929,7 @@ async function installZcodeSkills(projectRoot, minimal) {
1895
1929
  MANCODE_AGENT_SKILL_MARKERS
1896
1930
  );
1897
1931
  }
1932
+ await removeLegacyManagedSkills(skillsDir, MANCODE_AGENT_SKILL_MARKERS);
1898
1933
  }
1899
1934
  async function installCursorCommands(projectRoot, minimal) {
1900
1935
  if (minimal) {
@@ -1903,7 +1938,6 @@ async function installCursorCommands(projectRoot, minimal) {
1903
1938
  }
1904
1939
  const commandsDir = path4.join(projectRoot, ".cursor", "commands");
1905
1940
  await mkdir4(commandsDir, { recursive: true });
1906
- await removeLegacyGeneratedModeFile(path4.join(commandsDir, "man8.md"));
1907
1941
  for (const mode of MODE_NAMES) {
1908
1942
  const meta = MODE_META[mode];
1909
1943
  const content = [
@@ -1923,6 +1957,8 @@ async function installCursorCommands(projectRoot, minimal) {
1923
1957
  "Cursor"
1924
1958
  );
1925
1959
  }
1960
+ await removeManagedModeFile(path4.join(commandsDir, "mamba.md"), "mamba");
1961
+ await removeLegacyGeneratedModeFile(path4.join(commandsDir, "man8.md"));
1926
1962
  }
1927
1963
  async function installCopilotPrompts(projectRoot, minimal) {
1928
1964
  if (minimal) {
@@ -1931,7 +1967,6 @@ async function installCopilotPrompts(projectRoot, minimal) {
1931
1967
  }
1932
1968
  const promptsDir = path4.join(projectRoot, ".github", "prompts");
1933
1969
  await mkdir4(promptsDir, { recursive: true });
1934
- await removeLegacyGeneratedModeFile(path4.join(promptsDir, "man8.prompt.md"));
1935
1970
  for (const mode of MODE_NAMES) {
1936
1971
  const meta = MODE_META[mode];
1937
1972
  const content = [
@@ -1952,6 +1987,11 @@ async function installCopilotPrompts(projectRoot, minimal) {
1952
1987
  "GitHub Copilot"
1953
1988
  );
1954
1989
  }
1990
+ await removeManagedModeFile(
1991
+ path4.join(promptsDir, "mamba.prompt.md"),
1992
+ "mamba"
1993
+ );
1994
+ await removeLegacyGeneratedModeFile(path4.join(promptsDir, "man8.prompt.md"));
1955
1995
  }
1956
1996
  async function removeCodexSkills(projectRoot) {
1957
1997
  if (!await platformNeedsSharedSkills(projectRoot, "zcode")) {
@@ -2090,18 +2130,22 @@ function isRecord2(value) {
2090
2130
  async function readTextIfExists3(filePath) {
2091
2131
  try {
2092
2132
  return await readFile4(filePath, "utf-8");
2093
- } catch {
2094
- return null;
2133
+ } catch (error) {
2134
+ if (isNodeError3(error) && error.code === "ENOENT") return null;
2135
+ throw error;
2095
2136
  }
2096
2137
  }
2138
+ function isNodeError3(error) {
2139
+ return error instanceof Error && "code" in error;
2140
+ }
2097
2141
  var MODE_META = {
2098
- mamba: {
2142
+ manba: {
2099
2143
  description: "Diagnose bugs and validate real user flows with targeted regression checks.",
2100
- intro: "# mancode mamba \u2014 Diagnosis and Real Validation",
2144
+ intro: "# mancode manba \u2014 Diagnosis and Real Validation",
2101
2145
  workflow: [
2102
2146
  "## Five-step workflow (simulate roles in one conversation)",
2103
2147
  "",
2104
- 'Use `mancode workflow create mamba "<task>" --json`; when called from',
2148
+ 'Use `mancode workflow create manba "<task>" --json`; when called from',
2105
2149
  "a /man or /manteam Step 6 workflow, add `--parent-task <taskId>`. Persist the returned",
2106
2150
  "taskId in `.mancode/state.json` as currentTask; set currentMode and",
2107
2151
  "currentWorkflowMode to mamba. Never edit metadata.json directly; use",
@@ -2137,7 +2181,7 @@ var MODE_META = {
2137
2181
  "Step 3 \u2014 Plan: write `plan.md` with scope, reuse, exclusions, risks, completion criteria, and real validation. First plan is v1; revisions use `--plan-version <current+1>` and Active Plans is updated by the CLI.",
2138
2182
  "Step 4 \u2014 Plan gate: the user chooses plan-only (`status planned`), continue to execution, or revise the plan. Do not implement before this choice.",
2139
2183
  "Step 5 \u2014 Implement the confirmed minimum change.",
2140
- "Step 6 \u2014 Run detected build/lint/typecheck/test and smoke checks. A real or complex diagnosis creates a linked mamba child while the parent remains at Step 6. After a resolved child, restore a parent blocked by that child with `workflow update --status in_progress` before Step 7; never auto-resume manual_test_required. Then write `review-scope.md` from the actual diff, verification evidence, and hard-risk triggers. Initialize a targeted review for routine governed changes or a full review for auth, payment, sensitive data, migrations/deletion, public APIs, untrusted input, concurrency, cross-service, or infrastructure changes using `mancode workflow review <taskId> init ...`.",
2184
+ "Step 6 \u2014 Run detected build/lint/typecheck/test and smoke checks. A real or complex diagnosis creates a linked manba child while the parent remains at Step 6. After a resolved child, restore a parent blocked by that child with `workflow update --status in_progress` before Step 7; never auto-resume manual_test_required. Then write `review-scope.md` from the actual diff, verification evidence, and hard-risk triggers. Initialize a targeted review for routine governed changes or a full review for auth, payment, sensitive data, migrations/deletion, public APIs, untrusted input, concurrency, cross-service, or infrastructure changes using `mancode workflow review <taskId> init ...`.",
2141
2185
  "Step 7 \u2014 Run one quality review limited to the changed diff and direct impact. Findings require changed-line evidence and user impact, with at most three new findings. Record stable blocker IDs through `workflow review ... complete`; do not fix yet.",
2142
2186
  "Step 8 \u2014 Only full review runs the security/boundary reviewer. It must read Film #1, mark the same root cause duplicate, and stay within security, permissions, recovery, resources, and boundaries. A targeted review ends after Film #1.",
2143
2187
  "Step 9 \u2014 If open blockers exist, fix them in one remediation round and record resolved IDs through `workflow review ... remediate`; with no blockers, do not create a remediation round. Re-run affected verification without re-running completed reviewers. Write `summary.md` and set completed only when required domains are complete and blockers are zero; otherwise set blocked+blockingReason.",
@@ -2158,9 +2202,9 @@ var MODE_META = {
2158
2202
  "",
2159
2203
  "Then execute every /man Step 1 through Step 9, including clarification,",
2160
2204
  "plan gate, validation, bounded risk-based review, conditional completion, planVersion,",
2161
- "Active Plans, and linked mamba child behavior. Add compatibility, rollback,",
2205
+ "Active Plans, and linked manba child behavior. Add compatibility, rollback,",
2162
2206
  "ownership, conflict, and handoff notes at each relevant step.",
2163
- "When a resolved mamba child had blocked the parent, restore the parent through",
2207
+ "When a resolved manba child had blocked the parent, restore the parent through",
2164
2208
  "`workflow update --status in_progress`; never auto-resume manual_test_required.",
2165
2209
  "",
2166
2210
  "Read `.mancode/memory/prd.md`, `spec.md`, and `decisions.md`; append durable",
@@ -2234,7 +2278,7 @@ function renderProjectContext(state, tokens, profile, options) {
2234
2278
  const currentProfile = options.projectProfile ?? profile;
2235
2279
  const techStack = options.projectProfile ? options.techStack.join(" + ") || "Unknown" : state?.techStack || options.techStack.join(" + ") || "Unknown";
2236
2280
  const uiLibrary = options.projectProfile ? options.uiLibrary || "None" : state?.uiLibrary || tokens?.uiLibrary || options.uiLibrary || "None";
2237
- const mode = state?.currentMode || "solo";
2281
+ const mode = state?.currentMode === "mamba" ? "manba" : state?.currentMode || "solo";
2238
2282
  return [
2239
2283
  "## mancode Project Context",
2240
2284
  "",
@@ -2298,7 +2342,7 @@ function renderAesthetics(tokens) {
2298
2342
  function renderModes(options) {
2299
2343
  let commandLabel;
2300
2344
  if (options.capabilities.skills === "agents-skills") {
2301
- commandLabel = "Invoke mode skills with `$man`, `$mamba`, `$manteam`, `$manps`, `$mansolo`.";
2345
+ commandLabel = "Invoke mode skills with `$man`, `$manba`, `$manteam`, `$manps`, `$mansolo`.";
2302
2346
  } else if (options.capabilities.slashCommands === "native") {
2303
2347
  commandLabel = "Use the named commands directly when available.";
2304
2348
  } else {
@@ -2309,7 +2353,7 @@ function renderModes(options) {
2309
2353
  "",
2310
2354
  `- solo: default lightweight mode. ${commandLabel}`,
2311
2355
  "- man: progressive governance workflow with planning and optional full execution.",
2312
- "- mamba: diagnose bugs and validate real user flows or regressions.",
2356
+ "- manba: diagnose bugs and validate real user flows or regressions.",
2313
2357
  "- manteam: use team memory and leave handoff-friendly summaries.",
2314
2358
  "- manps: run project health and cleanup scans before remediation.",
2315
2359
  "- mansolo: return to solo mode."
@@ -2371,11 +2415,15 @@ var MANCODE_CURSOR_CORE_RULE_FILES = [
2371
2415
  "mancode-solo.mdc"
2372
2416
  ];
2373
2417
  var MANCODE_CURSOR_ADVANCED_RULE_FILES = [
2374
- "mancode-mamba.mdc",
2418
+ "mancode-manba.mdc",
2375
2419
  "mancode-man.mdc",
2376
2420
  "mancode-manteam.mdc",
2377
2421
  "mancode-manps.mdc"
2378
2422
  ];
2423
+ var MANCODE_CURSOR_LEGACY_RULE_FILES = [
2424
+ "mancode-mamba.mdc",
2425
+ "mancode-man8.mdc"
2426
+ ];
2379
2427
  var CURSOR_RULE_MANAGED_MARKER = "<!-- Managed by mancode:cursor-rule. Do not edit this marker. -->";
2380
2428
  var MANCODE_CURSOR_RULE_FILES = [
2381
2429
  ...MANCODE_CURSOR_CORE_RULE_FILES,
@@ -2427,13 +2475,12 @@ async function installCursor(projectRoot, options) {
2427
2475
  await installCursorCommands(projectRoot, true);
2428
2476
  return;
2429
2477
  }
2430
- await removeLegacyCursorRules(projectRoot);
2431
2478
  await writeRule(
2432
2479
  rulesDir,
2433
- "mancode-mamba.mdc",
2480
+ "mancode-manba.mdc",
2434
2481
  "Use for bug diagnosis and real regression testing",
2435
2482
  false,
2436
- renderMambaRule()
2483
+ renderManbaRule()
2437
2484
  );
2438
2485
  await writeRule(
2439
2486
  rulesDir,
@@ -2456,6 +2503,7 @@ async function installCursor(projectRoot, options) {
2456
2503
  false,
2457
2504
  renderManpsRule()
2458
2505
  );
2506
+ await removeLegacyCursorRules(projectRoot);
2459
2507
  await installCursorCommands(projectRoot, options.minimal ?? false);
2460
2508
  }
2461
2509
  async function writeRule(rulesDir, fileName, description, alwaysApply, body) {
@@ -2503,18 +2551,9 @@ async function removeCursorGeneratedRules(projectRoot) {
2503
2551
  await removeLegacyCursorRules(projectRoot);
2504
2552
  }
2505
2553
  async function removeLegacyCursorRules(projectRoot) {
2506
- const legacyPath = path6.join(
2507
- projectRoot,
2508
- ".cursor",
2509
- "rules",
2510
- "mancode-man8.mdc"
2511
- );
2512
- try {
2513
- const content = await readFile6(legacyPath, "utf-8");
2514
- if (content.includes("# mancode man8 \u2014 Investigate and Plan") && content.includes("## Mode Persistence")) {
2515
- await rm3(legacyPath, { force: true });
2516
- }
2517
- } catch {
2554
+ const rulesDir = path6.join(projectRoot, ".cursor", "rules");
2555
+ for (const fileName of MANCODE_CURSOR_LEGACY_RULE_FILES) {
2556
+ await removeGeneratedCursorRule(rulesDir, fileName);
2518
2557
  }
2519
2558
  }
2520
2559
  async function removeGeneratedCursorRule(rulesDir, fileName) {
@@ -2541,10 +2580,14 @@ function isGeneratedCursorRule(content, fileName) {
2541
2580
  async function readTextIfExists4(filePath) {
2542
2581
  try {
2543
2582
  return await readFile6(filePath, "utf-8");
2544
- } catch {
2545
- return null;
2583
+ } catch (error) {
2584
+ if (isNodeError4(error) && error.code === "ENOENT") return null;
2585
+ throw error;
2546
2586
  }
2547
2587
  }
2588
+ function isNodeError4(error) {
2589
+ return error instanceof Error && "code" in error;
2590
+ }
2548
2591
  function renderPracticeRule() {
2549
2592
  return [
2550
2593
  "# mancode Practice",
@@ -2575,8 +2618,8 @@ function renderSoloRule() {
2575
2618
  "- Recommend /man only for auth, payment, sensitive data, migrations/deletion, public APIs, untrusted input, concurrency, or infrastructure risk."
2576
2619
  ].join("\n");
2577
2620
  }
2578
- function renderMambaRule() {
2579
- return renderModeSkill("mamba", "/");
2621
+ function renderManbaRule() {
2622
+ return renderModeSkill("manba", "/");
2580
2623
  }
2581
2624
  function renderManRule() {
2582
2625
  return renderModeSkill("man", "/");
@@ -2588,9 +2631,9 @@ function renderManpsRule() {
2588
2631
  return renderModeSkill("manps", "/");
2589
2632
  }
2590
2633
 
2591
- // src/installers/codex.ts
2592
- import { writeFile as writeFile6 } from "fs/promises";
2593
- import path7 from "path";
2634
+ // src/installers/platform-status.ts
2635
+ import { promises as fs } from "fs";
2636
+ import path8 from "path";
2594
2637
 
2595
2638
  // src/installers/managed-block.ts
2596
2639
  var DEFAULT_MANCODE_START_MARKER = "<!-- mancode:start -->";
@@ -2682,104 +2725,14 @@ function findMarkerLine(content, marker) {
2682
2725
  return null;
2683
2726
  }
2684
2727
 
2685
- // src/installers/codex.ts
2686
- async function installCodex(projectRoot, options) {
2687
- await installMancodeCore(projectRoot);
2688
- const agentsPath = path7.join(projectRoot, "AGENTS.md");
2689
- const existing = await readTextIfExists(agentsPath);
2690
- const sharedContent = await generateSharedContent(projectRoot, {
2691
- platform: "codex",
2692
- displayName: "Codex (ChatGPT desktop/CLI)",
2693
- capabilities: {
2694
- slashCommands: "partial",
2695
- subagents: false,
2696
- hooks: false,
2697
- skills: "agents-skills"
2698
- },
2699
- minimal: options.minimal,
2700
- techStack: options.techStack,
2701
- uiLibrary: options.uiLibrary,
2702
- projectProfile: options.projectProfile
2703
- });
2704
- const block = [
2705
- DEFAULT_MANCODE_START_MARKER,
2706
- "<!-- Managed by mancode. Do not edit this block manually. -->",
2707
- "",
2708
- "# mancode Configuration",
2709
- "",
2710
- sharedContent.trim(),
2711
- DEFAULT_MANCODE_END_MARKER
2712
- ].join("\n");
2713
- await writeFile6(agentsPath, replaceManagedBlock(existing, block), "utf-8");
2714
- await installCodexSkills(projectRoot, options.minimal ?? false);
2715
- }
2716
-
2717
- // src/installers/copilot.ts
2718
- import { mkdir as mkdir6, writeFile as writeFile7 } from "fs/promises";
2719
- import path8 from "path";
2720
- async function installCopilot(projectRoot, options) {
2721
- await installMancodeCore(projectRoot);
2722
- const githubDir = path8.join(projectRoot, ".github");
2723
- await mkdir6(githubDir, { recursive: true });
2724
- const instructionsPath = path8.join(githubDir, "copilot-instructions.md");
2725
- const existing = await readTextIfExists(instructionsPath);
2726
- const sharedContent = await generateSharedContent(projectRoot, {
2727
- platform: "copilot",
2728
- displayName: "GitHub Copilot",
2729
- capabilities: {
2730
- slashCommands: "none",
2731
- subagents: false,
2732
- hooks: false,
2733
- skills: "instructions"
2734
- },
2735
- minimal: true,
2736
- techStack: options.techStack,
2737
- uiLibrary: options.uiLibrary,
2738
- projectProfile: options.projectProfile
2739
- });
2740
- const sections = [
2741
- DEFAULT_MANCODE_START_MARKER,
2742
- "<!-- Managed by mancode. Do not edit this block manually. -->",
2743
- "",
2744
- "# mancode for GitHub Copilot",
2745
- "",
2746
- sharedContent.trim()
2747
- ];
2748
- if (!options.minimal) {
2749
- sections.push("", renderCopilotPromptConventions());
2750
- }
2751
- sections.push(DEFAULT_MANCODE_END_MARKER);
2752
- await writeFile7(
2753
- instructionsPath,
2754
- replaceManagedBlock(existing, sections.join("\n")),
2755
- "utf-8"
2756
- );
2757
- await installCopilotPrompts(projectRoot, options.minimal ?? false);
2758
- }
2759
- function renderCopilotPromptConventions() {
2760
- return [
2761
- "## mancode Prompt Conventions",
2762
- "",
2763
- "GitHub Copilot does not provide native mancode slash commands, hooks, or isolated subagents. Treat these names as user prompt conventions:",
2764
- "",
2765
- "- man: use progressive research, planning, implementation, verification, and bounded risk-based review.",
2766
- "- mamba: diagnose bugs and validate real user flows or regressions.",
2767
- "- manteam: read team memory and write handoff-friendly summaries.",
2768
- "- manps: prefer `mancode manps [area]` before cleanup.",
2769
- "- mansolo: exit any active mode and return to default solo behavior.",
2770
- "",
2771
- "These correspond to prompt files in `.github/prompts/`. Select the matching prompt to activate a mode."
2772
- ].join("\n");
2773
- }
2774
-
2775
2728
  // src/installers/zcode.ts
2776
- import { writeFile as writeFile8 } from "fs/promises";
2777
- import path9 from "path";
2729
+ import { writeFile as writeFile6 } from "fs/promises";
2730
+ import path7 from "path";
2778
2731
  var ZCODE_MANCODE_START_MARKER = "<!-- mancode:zcode:start -->";
2779
2732
  var ZCODE_MANCODE_END_MARKER = "<!-- mancode:zcode:end -->";
2780
2733
  async function installZcode(projectRoot, options) {
2781
2734
  await installMancodeCore(projectRoot);
2782
- const agentsPath = path9.join(projectRoot, "AGENTS.md");
2735
+ const agentsPath = path7.join(projectRoot, "AGENTS.md");
2783
2736
  const existing = await readTextIfExists(agentsPath);
2784
2737
  const sharedContent = await generateSharedContent(projectRoot, {
2785
2738
  platform: "zcode",
@@ -2804,7 +2757,7 @@ async function installZcode(projectRoot, options) {
2804
2757
  sharedContent.trim(),
2805
2758
  ZCODE_MANCODE_END_MARKER
2806
2759
  ].join("\n");
2807
- await writeFile8(
2760
+ await writeFile6(
2808
2761
  agentsPath,
2809
2762
  replaceManagedBlock(
2810
2763
  existing,
@@ -2817,101 +2770,472 @@ async function installZcode(projectRoot, options) {
2817
2770
  await installZcodeSkills(projectRoot, options.minimal ?? false);
2818
2771
  }
2819
2772
 
2820
- // src/installers/registry.ts
2821
- var PLATFORM_INSTALLERS = {
2822
- "claude-code": {
2823
- name: "claude-code",
2824
- displayName: "Claude Code",
2825
- capabilities: {
2826
- slashCommands: "native",
2827
- subagents: true,
2828
- hooks: true,
2829
- skills: "native"
2830
- },
2831
- install: installClaudeCode
2832
- },
2833
- cursor: {
2834
- name: "cursor",
2835
- displayName: "Cursor",
2836
- capabilities: {
2837
- slashCommands: "native",
2838
- subagents: false,
2839
- hooks: false,
2840
- skills: "rules"
2841
- },
2842
- install: installCursor
2843
- },
2844
- codex: {
2845
- name: "codex",
2846
- displayName: "Codex (ChatGPT desktop/CLI)",
2847
- capabilities: {
2848
- slashCommands: "partial",
2849
- subagents: false,
2850
- hooks: false,
2851
- skills: "agents-skills"
2852
- },
2853
- install: installCodex
2854
- },
2855
- copilot: {
2856
- name: "copilot",
2857
- displayName: "GitHub Copilot",
2858
- capabilities: {
2859
- slashCommands: "none",
2860
- subagents: false,
2861
- hooks: false,
2862
- skills: "instructions"
2863
- },
2864
- install: installCopilot
2865
- },
2866
- zcode: {
2867
- name: "zcode",
2868
- displayName: "ZCode",
2869
- capabilities: {
2870
- slashCommands: "partial",
2871
- subagents: false,
2872
- hooks: false,
2873
- skills: "agents-skills"
2874
- },
2875
- install: installZcode
2876
- }
2877
- };
2878
- function getPlatformInstaller(platform) {
2879
- if (!isPlatformName(platform)) return null;
2880
- return PLATFORM_INSTALLERS[platform];
2881
- }
2882
- function getPlatformInstallers() {
2883
- return Object.values(PLATFORM_INSTALLERS);
2884
- }
2885
- function formatPlatformName(platform) {
2886
- return getPlatformInstaller(platform)?.displayName ?? platform;
2773
+ // src/installers/platform-status.ts
2774
+ async function checkPlatformStatus(rootDir, platform, installed) {
2775
+ const readiness = await checkPlatformReadiness(rootDir, platform);
2776
+ return {
2777
+ installed,
2778
+ ready: installed && readiness.ready,
2779
+ target: readiness.target,
2780
+ detail: describeStatus(installed, readiness)
2781
+ };
2887
2782
  }
2888
- function isPlatformName(platform) {
2889
- return Object.prototype.hasOwnProperty.call(PLATFORM_INSTALLERS, platform);
2783
+ async function isPlatformPresent(rootDir, platform) {
2784
+ return (await checkPlatformReadiness(rootDir, platform)).present;
2890
2785
  }
2891
-
2892
- // src/system/detect-team.ts
2893
- import { execFile } from "child_process";
2894
- import { access as access2 } from "fs/promises";
2895
- import path10 from "path";
2896
- import process2 from "process";
2897
- import { promisify } from "util";
2898
- var execFileAsync = promisify(execFile);
2899
- var NO_TEAM = {
2900
- isTeam: false,
2901
- contributors: 1,
2902
- recentActive: 1,
2903
- hasRemote: false
2904
- };
2905
- var REMOTE_PATTERN = /github\.com|gitlab\.com|bitbucket\.org/;
2906
- var GIT_ENV = {
2907
- ...process2.env,
2908
- GIT_PAGER: "cat",
2909
- PAGER: "cat",
2910
- GIT_TERMINAL_PROMPT: "0"
2786
+ async function checkPlatformReadiness(rootDir, platform) {
2787
+ if (platform === "claude-code") {
2788
+ const [hasSoloSkill, registered, hasHookFiles] = await Promise.all([
2789
+ fileMatches(
2790
+ path8.join(rootDir, ".claude", "skills", "solo", "SKILL.md"),
2791
+ (content) => isGeneratedClaudeSkill(content, "solo")
2792
+ ),
2793
+ claudeHooksRegistered(rootDir),
2794
+ pathsExist([
2795
+ path8.join(rootDir, ".mancode", "hooks", "session-start.mjs"),
2796
+ path8.join(rootDir, ".mancode", "hooks", "user-prompt-submit.mjs")
2797
+ ])
2798
+ ]);
2799
+ const present = hasSoloSkill && registered && hasHookFiles;
2800
+ const minimal = await isPlatformMinimal(rootDir, "claude-code");
2801
+ const fullContentReady = minimal ? true : await claudeFullContentReady(rootDir);
2802
+ return {
2803
+ present,
2804
+ ready: present && fullContentReady,
2805
+ target: ".claude/",
2806
+ readyDetail: present && fullContentReady ? minimal ? "solo skill and hooks ready" : "skills, agents, and hooks ready" : "skills, agents, hook files, or hook registration are incomplete"
2807
+ };
2808
+ }
2809
+ if (platform === "cursor") {
2810
+ const hasCoreRules = await allManagedSkills(
2811
+ MANCODE_CURSOR_CORE_RULE_FILES.map(
2812
+ (file) => path8.join(rootDir, ".cursor", "rules", file)
2813
+ ),
2814
+ [CURSOR_RULE_MANAGED_MARKER]
2815
+ );
2816
+ if (await isPlatformMinimal(rootDir, "cursor")) {
2817
+ return {
2818
+ present: hasCoreRules,
2819
+ ready: hasCoreRules,
2820
+ target: ".cursor/rules/",
2821
+ readyDetail: "mancode core rules present"
2822
+ };
2823
+ }
2824
+ const [hasRules, hasCommands] = await Promise.all([
2825
+ allManagedSkills(
2826
+ MANCODE_CURSOR_RULE_FILES.map(
2827
+ (file) => path8.join(rootDir, ".cursor", "rules", file)
2828
+ ),
2829
+ [CURSOR_RULE_MANAGED_MARKER]
2830
+ ),
2831
+ allManagedSkills(
2832
+ MODE_NAMES.map(
2833
+ (mode) => path8.join(rootDir, ".cursor", "commands", `${mode}.md`)
2834
+ ),
2835
+ [MODE_FILE_MANAGED_MARKER]
2836
+ )
2837
+ ]);
2838
+ return {
2839
+ present: hasCoreRules,
2840
+ ready: hasRules && hasCommands,
2841
+ target: ".cursor/rules/ + .cursor/commands/",
2842
+ readyDetail: hasRules && hasCommands ? "mancode rules and commands present" : "mode rules or commands are missing, incomplete, or user-authored"
2843
+ };
2844
+ }
2845
+ if (platform === "codex") {
2846
+ const hasBlock2 = await fileHasManagedBlock(path8.join(rootDir, "AGENTS.md"));
2847
+ if (!hasBlock2) {
2848
+ return {
2849
+ present: false,
2850
+ ready: false,
2851
+ target: "AGENTS.md",
2852
+ readyDetail: "managed block missing"
2853
+ };
2854
+ }
2855
+ if (await isPlatformMinimal(rootDir, "codex")) {
2856
+ return {
2857
+ present: true,
2858
+ ready: true,
2859
+ target: "AGENTS.md",
2860
+ readyDetail: "managed block present"
2861
+ };
2862
+ }
2863
+ const skillsDir = path8.join(rootDir, ".agents", "skills");
2864
+ const hasSkills = await allManagedSkills(
2865
+ MODE_NAMES.map((mode) => path8.join(skillsDir, mode, "SKILL.md")),
2866
+ MANCODE_AGENT_SKILL_MARKERS
2867
+ );
2868
+ return {
2869
+ present: true,
2870
+ ready: hasSkills,
2871
+ target: "AGENTS.md + .agents/skills/",
2872
+ readyDetail: hasSkills ? "managed block and skills present" : "mode skills are missing, incomplete, or user-authored"
2873
+ };
2874
+ }
2875
+ if (platform === "zcode") {
2876
+ const hasBlock2 = await fileHasManagedBlock(
2877
+ path8.join(rootDir, "AGENTS.md"),
2878
+ ZCODE_MANCODE_START_MARKER,
2879
+ ZCODE_MANCODE_END_MARKER
2880
+ );
2881
+ if (!hasBlock2) {
2882
+ return {
2883
+ present: false,
2884
+ ready: false,
2885
+ target: "AGENTS.md",
2886
+ readyDetail: "managed block missing"
2887
+ };
2888
+ }
2889
+ if (await isPlatformMinimal(rootDir, "zcode")) {
2890
+ return {
2891
+ present: true,
2892
+ ready: true,
2893
+ target: "AGENTS.md",
2894
+ readyDetail: "managed block present"
2895
+ };
2896
+ }
2897
+ const skillsDir = path8.join(rootDir, ".agents", "skills");
2898
+ const hasSkills = await allManagedSkills(
2899
+ MODE_NAMES.map((mode) => path8.join(skillsDir, mode, "SKILL.md")),
2900
+ MANCODE_AGENT_SKILL_MARKERS
2901
+ );
2902
+ return {
2903
+ present: true,
2904
+ ready: hasSkills,
2905
+ target: "AGENTS.md + .agents/skills/",
2906
+ readyDetail: hasSkills ? "managed block and skills present" : "mode skills are missing, incomplete, or user-authored"
2907
+ };
2908
+ }
2909
+ const hasBlock = await fileHasManagedBlock(
2910
+ path8.join(rootDir, ".github", "copilot-instructions.md")
2911
+ );
2912
+ if (!hasBlock) {
2913
+ return {
2914
+ present: false,
2915
+ ready: false,
2916
+ target: ".github/copilot-instructions.md",
2917
+ readyDetail: "managed block missing"
2918
+ };
2919
+ }
2920
+ if (!await isPlatformMinimal(rootDir, "copilot")) {
2921
+ const promptsDir = path8.join(rootDir, ".github", "prompts");
2922
+ const hasPrompts = await allManagedSkills(
2923
+ MODE_NAMES.map((mode) => path8.join(promptsDir, `${mode}.prompt.md`)),
2924
+ [MODE_FILE_MANAGED_MARKER]
2925
+ );
2926
+ return {
2927
+ present: true,
2928
+ ready: hasPrompts,
2929
+ target: ".github/copilot-instructions.md + .github/prompts/",
2930
+ readyDetail: hasPrompts ? "managed block and prompts present" : "mode prompts are missing, incomplete, or user-authored"
2931
+ };
2932
+ }
2933
+ return {
2934
+ present: true,
2935
+ ready: true,
2936
+ target: ".github/copilot-instructions.md",
2937
+ readyDetail: "managed block present"
2938
+ };
2939
+ }
2940
+ function describeStatus(installed, readiness) {
2941
+ if (installed && readiness.present) return readiness.readyDetail;
2942
+ if (!installed && readiness.present) {
2943
+ return "target files present but platform is not recorded in config";
2944
+ }
2945
+ return "missing generated files or registration";
2946
+ }
2947
+ async function allManagedSkills(paths, markers) {
2948
+ const results = await Promise.all(
2949
+ paths.map((filePath) => fileHasAnyMarker(filePath, markers))
2950
+ );
2951
+ return results.every(Boolean);
2952
+ }
2953
+ async function claudeFullContentReady(rootDir) {
2954
+ const skillChecks = MVP2_SKILLS.map(
2955
+ (skill) => fileMatches(
2956
+ path8.join(rootDir, ".claude", "skills", skill.name, "SKILL.md"),
2957
+ (content) => isGeneratedClaudeSkill(content, skill.name)
2958
+ )
2959
+ );
2960
+ const agentChecks = ALL_AGENTS.map(
2961
+ (agent) => fileMatches(
2962
+ path8.join(rootDir, ".claude", "agents", `${agent.name}.md`),
2963
+ (content) => isGeneratedClaudeAgent(content, agent.name)
2964
+ )
2965
+ );
2966
+ const results = await Promise.all([...skillChecks, ...agentChecks]);
2967
+ return results.every(Boolean);
2968
+ }
2969
+ async function fileMatches(filePath, predicate) {
2970
+ try {
2971
+ return predicate(await fs.readFile(filePath, "utf-8"));
2972
+ } catch {
2973
+ return false;
2974
+ }
2975
+ }
2976
+ async function pathsExist(paths) {
2977
+ return (await Promise.all(paths.map(pathExists2))).every(Boolean);
2978
+ }
2979
+ async function fileHasAnyMarker(filePath, needles) {
2980
+ try {
2981
+ const content = await fs.readFile(filePath, "utf-8");
2982
+ return needles.some((needle) => content.includes(needle));
2983
+ } catch {
2984
+ return false;
2985
+ }
2986
+ }
2987
+ async function isPlatformMinimal(rootDir, platform) {
2988
+ try {
2989
+ const raw = await fs.readFile(
2990
+ path8.join(rootDir, ".mancode", "config.json"),
2991
+ "utf-8"
2992
+ );
2993
+ const config = JSON.parse(raw);
2994
+ if (!isRecord3(config.platformOptions)) return false;
2995
+ const options = config.platformOptions[platform];
2996
+ return isRecord3(options) && options.minimal === true;
2997
+ } catch {
2998
+ return false;
2999
+ }
3000
+ }
3001
+ async function fileHasManagedBlock(filePath, startMarker = DEFAULT_MANCODE_START_MARKER, endMarker = DEFAULT_MANCODE_END_MARKER) {
3002
+ try {
3003
+ const content = await fs.readFile(filePath, "utf-8");
3004
+ return hasManagedBlock(content, startMarker, endMarker);
3005
+ } catch {
3006
+ return false;
3007
+ }
3008
+ }
3009
+ async function claudeHooksRegistered(rootDir) {
3010
+ try {
3011
+ const raw = await fs.readFile(
3012
+ path8.join(rootDir, ".claude", "settings.json"),
3013
+ "utf-8"
3014
+ );
3015
+ const settings = JSON.parse(raw);
3016
+ return hooksRegistered(settings);
3017
+ } catch {
3018
+ return false;
3019
+ }
3020
+ }
3021
+ function hooksRegistered(settings) {
3022
+ if (!isRecord3(settings)) return false;
3023
+ const hooks = settings.hooks;
3024
+ if (!isRecord3(hooks)) return false;
3025
+ return hasHookCommand(hooks.SessionStart, ".mancode/hooks/session-start.mjs") && hasHookCommand(
3026
+ hooks.UserPromptSubmit,
3027
+ ".mancode/hooks/user-prompt-submit.mjs"
3028
+ );
3029
+ }
3030
+ function hasHookCommand(value, needle) {
3031
+ if (!Array.isArray(value)) return false;
3032
+ return value.some((group) => {
3033
+ if (!isRecord3(group) || !Array.isArray(group.hooks)) return false;
3034
+ return group.hooks.some((hook) => {
3035
+ if (!isRecord3(hook) || typeof hook.command !== "string") return false;
3036
+ return hook.command.includes(needle);
3037
+ });
3038
+ });
3039
+ }
3040
+ async function pathExists2(p) {
3041
+ try {
3042
+ await fs.access(p);
3043
+ return true;
3044
+ } catch {
3045
+ return false;
3046
+ }
3047
+ }
3048
+ function isRecord3(value) {
3049
+ return typeof value === "object" && value !== null;
3050
+ }
3051
+
3052
+ // src/installers/codex.ts
3053
+ import { writeFile as writeFile7 } from "fs/promises";
3054
+ import path9 from "path";
3055
+ async function installCodex(projectRoot, options) {
3056
+ await installMancodeCore(projectRoot);
3057
+ const agentsPath = path9.join(projectRoot, "AGENTS.md");
3058
+ const existing = await readTextIfExists(agentsPath);
3059
+ const sharedContent = await generateSharedContent(projectRoot, {
3060
+ platform: "codex",
3061
+ displayName: "Codex (ChatGPT desktop/CLI)",
3062
+ capabilities: {
3063
+ slashCommands: "partial",
3064
+ subagents: false,
3065
+ hooks: false,
3066
+ skills: "agents-skills"
3067
+ },
3068
+ minimal: options.minimal,
3069
+ techStack: options.techStack,
3070
+ uiLibrary: options.uiLibrary,
3071
+ projectProfile: options.projectProfile
3072
+ });
3073
+ const block = [
3074
+ DEFAULT_MANCODE_START_MARKER,
3075
+ "<!-- Managed by mancode. Do not edit this block manually. -->",
3076
+ "",
3077
+ "# mancode Configuration",
3078
+ "",
3079
+ sharedContent.trim(),
3080
+ DEFAULT_MANCODE_END_MARKER
3081
+ ].join("\n");
3082
+ await writeFile7(agentsPath, replaceManagedBlock(existing, block), "utf-8");
3083
+ await installCodexSkills(projectRoot, options.minimal ?? false);
3084
+ }
3085
+
3086
+ // src/installers/copilot.ts
3087
+ import { mkdir as mkdir6, writeFile as writeFile8 } from "fs/promises";
3088
+ import path10 from "path";
3089
+ async function installCopilot(projectRoot, options) {
3090
+ await installMancodeCore(projectRoot);
3091
+ const githubDir = path10.join(projectRoot, ".github");
3092
+ await mkdir6(githubDir, { recursive: true });
3093
+ const instructionsPath = path10.join(githubDir, "copilot-instructions.md");
3094
+ const existing = await readTextIfExists(instructionsPath);
3095
+ const sharedContent = await generateSharedContent(projectRoot, {
3096
+ platform: "copilot",
3097
+ displayName: "GitHub Copilot",
3098
+ capabilities: {
3099
+ slashCommands: "none",
3100
+ subagents: false,
3101
+ hooks: false,
3102
+ skills: "instructions"
3103
+ },
3104
+ minimal: true,
3105
+ techStack: options.techStack,
3106
+ uiLibrary: options.uiLibrary,
3107
+ projectProfile: options.projectProfile
3108
+ });
3109
+ const sections = [
3110
+ DEFAULT_MANCODE_START_MARKER,
3111
+ "<!-- Managed by mancode. Do not edit this block manually. -->",
3112
+ "",
3113
+ "# mancode for GitHub Copilot",
3114
+ "",
3115
+ sharedContent.trim()
3116
+ ];
3117
+ if (!options.minimal) {
3118
+ sections.push("", renderCopilotPromptConventions());
3119
+ }
3120
+ sections.push(DEFAULT_MANCODE_END_MARKER);
3121
+ await writeFile8(
3122
+ instructionsPath,
3123
+ replaceManagedBlock(existing, sections.join("\n")),
3124
+ "utf-8"
3125
+ );
3126
+ await installCopilotPrompts(projectRoot, options.minimal ?? false);
3127
+ }
3128
+ function renderCopilotPromptConventions() {
3129
+ return [
3130
+ "## mancode Prompt Conventions",
3131
+ "",
3132
+ "GitHub Copilot does not provide native mancode slash commands, hooks, or isolated subagents. Treat these names as user prompt conventions:",
3133
+ "",
3134
+ "- man: use progressive research, planning, implementation, verification, and bounded risk-based review.",
3135
+ "- manba: diagnose bugs and validate real user flows or regressions.",
3136
+ "- manteam: read team memory and write handoff-friendly summaries.",
3137
+ "- manps: prefer `mancode manps [area]` before cleanup.",
3138
+ "- mansolo: exit any active mode and return to default solo behavior.",
3139
+ "",
3140
+ "These correspond to prompt files in `.github/prompts/`. Select the matching prompt to activate a mode."
3141
+ ].join("\n");
3142
+ }
3143
+
3144
+ // src/installers/registry.ts
3145
+ var PLATFORM_INSTALLERS = {
3146
+ "claude-code": {
3147
+ name: "claude-code",
3148
+ displayName: "Claude Code",
3149
+ capabilities: {
3150
+ slashCommands: "native",
3151
+ subagents: true,
3152
+ hooks: true,
3153
+ skills: "native"
3154
+ },
3155
+ install: installClaudeCode
3156
+ },
3157
+ cursor: {
3158
+ name: "cursor",
3159
+ displayName: "Cursor",
3160
+ capabilities: {
3161
+ slashCommands: "native",
3162
+ subagents: false,
3163
+ hooks: false,
3164
+ skills: "rules"
3165
+ },
3166
+ install: installCursor
3167
+ },
3168
+ codex: {
3169
+ name: "codex",
3170
+ displayName: "Codex (ChatGPT desktop/CLI)",
3171
+ capabilities: {
3172
+ slashCommands: "partial",
3173
+ subagents: false,
3174
+ hooks: false,
3175
+ skills: "agents-skills"
3176
+ },
3177
+ install: installCodex
3178
+ },
3179
+ copilot: {
3180
+ name: "copilot",
3181
+ displayName: "GitHub Copilot",
3182
+ capabilities: {
3183
+ slashCommands: "none",
3184
+ subagents: false,
3185
+ hooks: false,
3186
+ skills: "instructions"
3187
+ },
3188
+ install: installCopilot
3189
+ },
3190
+ zcode: {
3191
+ name: "zcode",
3192
+ displayName: "ZCode",
3193
+ capabilities: {
3194
+ slashCommands: "partial",
3195
+ subagents: false,
3196
+ hooks: false,
3197
+ skills: "agents-skills"
3198
+ },
3199
+ install: installZcode
3200
+ }
3201
+ };
3202
+ function getPlatformInstaller(platform) {
3203
+ if (!isPlatformName(platform)) return null;
3204
+ return PLATFORM_INSTALLERS[platform];
3205
+ }
3206
+ function getPlatformInstallers() {
3207
+ return Object.values(PLATFORM_INSTALLERS);
3208
+ }
3209
+ function formatPlatformName(platform) {
3210
+ return getPlatformInstaller(platform)?.displayName ?? platform;
3211
+ }
3212
+ function isPlatformName(platform) {
3213
+ return Object.prototype.hasOwnProperty.call(PLATFORM_INSTALLERS, platform);
3214
+ }
3215
+
3216
+ // src/system/detect-team.ts
3217
+ import { execFile } from "child_process";
3218
+ import { access as access2 } from "fs/promises";
3219
+ import path11 from "path";
3220
+ import process2 from "process";
3221
+ import { promisify } from "util";
3222
+ var execFileAsync = promisify(execFile);
3223
+ var NO_TEAM = {
3224
+ isTeam: false,
3225
+ contributors: 1,
3226
+ recentActive: 1,
3227
+ hasRemote: false
3228
+ };
3229
+ var REMOTE_PATTERN = /github\.com|gitlab\.com|bitbucket\.org/;
3230
+ var GIT_ENV = {
3231
+ ...process2.env,
3232
+ GIT_PAGER: "cat",
3233
+ PAGER: "cat",
3234
+ GIT_TERMINAL_PROMPT: "0"
2911
3235
  };
2912
3236
  async function detectTeamStatus(projectRoot) {
2913
3237
  try {
2914
- await access2(path10.join(projectRoot, ".git"));
3238
+ await access2(path11.join(projectRoot, ".git"));
2915
3239
  const inside = await runGit(projectRoot, [
2916
3240
  "rev-parse",
2917
3241
  "--is-inside-work-tree"
@@ -2969,8 +3293,8 @@ async function detectSystemDeps(env = process3.env) {
2969
3293
 
2970
3294
  // src/system/init-onboarding.ts
2971
3295
  import { execFileSync } from "child_process";
2972
- import { promises as fs } from "fs";
2973
- import path11 from "path";
3296
+ import { promises as fs2 } from "fs";
3297
+ import path12 from "path";
2974
3298
  import process4 from "process";
2975
3299
  import { stdin, stdout } from "process";
2976
3300
  import { createInterface } from "readline/promises";
@@ -3075,7 +3399,7 @@ async function detectPlatformHints(rootDir, environment = process4.env) {
3075
3399
  hints.add("copilot");
3076
3400
  const exists = async (relative) => {
3077
3401
  try {
3078
- await fs.access(path11.join(rootDir, relative));
3402
+ await fs2.access(path12.join(rootDir, relative));
3079
3403
  return true;
3080
3404
  } catch {
3081
3405
  return false;
@@ -3151,7 +3475,7 @@ function createTerminalPrompter() {
3151
3475
 
3152
3476
  // src/system/project-profile.ts
3153
3477
  import { readFile as readFile7, readdir as readdir3, stat as stat2 } from "fs/promises";
3154
- import path12 from "path";
3478
+ import path13 from "path";
3155
3479
  var PROJECT_MANIFESTS = [
3156
3480
  "package.json",
3157
3481
  "pyproject.toml",
@@ -3184,12 +3508,12 @@ async function detectProjectProfile(projectRoot) {
3184
3508
  "data",
3185
3509
  "notebooks"
3186
3510
  ]);
3187
- const packageJson = await readJson2(path12.join(projectRoot, "package.json"));
3511
+ const packageJson = await readJson2(path13.join(projectRoot, "package.json"));
3188
3512
  const [pubspec, pythonManifests] = await Promise.all([
3189
- readText(path12.join(projectRoot, "pubspec.yaml")),
3513
+ readText(path13.join(projectRoot, "pubspec.yaml")),
3190
3514
  Promise.all([
3191
- readText(path12.join(projectRoot, "pyproject.toml")),
3192
- readText(path12.join(projectRoot, "requirements.txt"))
3515
+ readText(path13.join(projectRoot, "pyproject.toml")),
3516
+ readText(path13.join(projectRoot, "requirements.txt"))
3193
3517
  ]).then((parts) => parts.filter(Boolean).join("\n"))
3194
3518
  ]);
3195
3519
  const deps = Object.keys({
@@ -3198,7 +3522,7 @@ async function detectProjectProfile(projectRoot) {
3198
3522
  ...packageJson?.peerDependencies
3199
3523
  });
3200
3524
  const flutter = isFlutterProject(pubspec);
3201
- const shadcn = entries.includes("components.json") || deps.some((dep) => dep.startsWith("@radix-ui/")) && await isDirectory(path12.join(projectRoot, "src", "components", "ui"));
3525
+ const shadcn = entries.includes("components.json") || deps.some((dep) => dep.startsWith("@radix-ui/")) && await isDirectory(path13.join(projectRoot, "src", "components", "ui"));
3202
3526
  const languages = inferLanguages(manifests, entries);
3203
3527
  const frameworks = inferFrameworks(
3204
3528
  deps,
@@ -3241,7 +3565,7 @@ async function existingDirs(root, candidates) {
3241
3565
  const found = [];
3242
3566
  for (const candidate of candidates) {
3243
3567
  try {
3244
- if ((await stat2(path12.join(root, candidate))).isDirectory())
3568
+ if ((await stat2(path13.join(root, candidate))).isDirectory())
3245
3569
  found.push(candidate);
3246
3570
  } catch {
3247
3571
  }
@@ -3415,8 +3739,8 @@ function isFlutterProject(pubspec) {
3415
3739
  }
3416
3740
 
3417
3741
  // src/system/scan-aesthetics.ts
3418
- import { promises as fs2 } from "fs";
3419
- import path13 from "path";
3742
+ import { promises as fs3 } from "fs";
3743
+ import path14 from "path";
3420
3744
  var MAX_COMPONENT_SCAN_DEPTH = 12;
3421
3745
  var MAX_COMPONENT_FILES = 2e3;
3422
3746
  async function scanAesthetics(projectRoot, uiLibrary = null) {
@@ -3429,7 +3753,7 @@ async function scanAesthetics(projectRoot, uiLibrary = null) {
3429
3753
  const cssScan = await scanCssVariables(projectRoot);
3430
3754
  if (configResult) {
3431
3755
  sourceFiles.push(configResult.relPath);
3432
- const content = await fs2.readFile(configResult.absPath, "utf-8");
3756
+ const content = await fs3.readFile(configResult.absPath, "utf-8");
3433
3757
  const inspectableContent = stripJsComments(content);
3434
3758
  const themeBlock = findKeyBlock(inspectableContent, "theme");
3435
3759
  if (themeBlock) {
@@ -3452,7 +3776,7 @@ async function scanAesthetics(projectRoot, uiLibrary = null) {
3452
3776
  } else if (await hasTailwindDep(projectRoot) || uiLibrary) {
3453
3777
  matchLevel = "low";
3454
3778
  }
3455
- if (uiLibrary && await pathExists2(path13.join(projectRoot, "package.json"))) {
3779
+ if (uiLibrary && await pathExists3(path14.join(projectRoot, "package.json"))) {
3456
3780
  sourceFiles.push("package.json");
3457
3781
  }
3458
3782
  sourceFiles.push(...cssScan.sourceFiles);
@@ -3477,8 +3801,8 @@ async function findTailwindConfig(projectRoot) {
3477
3801
  "tailwind.config.mjs"
3478
3802
  ];
3479
3803
  for (const name of candidates) {
3480
- const absPath = path13.join(projectRoot, name);
3481
- if (await pathExists2(absPath)) {
3804
+ const absPath = path14.join(projectRoot, name);
3805
+ if (await pathExists3(absPath)) {
3482
3806
  return { absPath, relPath: name };
3483
3807
  }
3484
3808
  }
@@ -3704,8 +4028,8 @@ async function scanComponents(projectRoot) {
3704
4028
  const names = /* @__PURE__ */ new Set();
3705
4029
  let visitedFiles = 0;
3706
4030
  for (const relRoot of roots) {
3707
- const absRoot = path13.join(projectRoot, relRoot);
3708
- if (!await pathExists2(absRoot)) continue;
4031
+ const absRoot = path14.join(projectRoot, relRoot);
4032
+ if (!await pathExists3(absRoot)) continue;
3709
4033
  visitedFiles = await collectComponentNames(absRoot, names, 0, visitedFiles);
3710
4034
  if (visitedFiles >= MAX_COMPONENT_FILES) break;
3711
4035
  }
@@ -3718,16 +4042,16 @@ async function collectComponentNames(dir, names, depth, visitedFiles) {
3718
4042
  let fileCount = visitedFiles;
3719
4043
  let entries;
3720
4044
  try {
3721
- entries = await fs2.readdir(dir);
4045
+ entries = await fs3.readdir(dir);
3722
4046
  } catch {
3723
4047
  return fileCount;
3724
4048
  }
3725
4049
  for (const entry of entries) {
3726
4050
  if (fileCount >= MAX_COMPONENT_FILES) return fileCount;
3727
- const abs = path13.join(dir, entry);
4051
+ const abs = path14.join(dir, entry);
3728
4052
  let info;
3729
4053
  try {
3730
- info = await fs2.lstat(abs);
4054
+ info = await fs3.lstat(abs);
3731
4055
  } catch {
3732
4056
  continue;
3733
4057
  }
@@ -3745,7 +4069,7 @@ async function collectComponentNames(dir, names, depth, visitedFiles) {
3745
4069
  ""
3746
4070
  );
3747
4071
  if (base === "index") {
3748
- base = path13.basename(dir);
4072
+ base = path14.basename(dir);
3749
4073
  }
3750
4074
  if (base.startsWith(".")) continue;
3751
4075
  const componentName = toPascalCase(base);
@@ -3767,9 +4091,9 @@ async function scanCssVariables(projectRoot) {
3767
4091
  const variables = {};
3768
4092
  const sourceFiles = [];
3769
4093
  for (const relPath of candidates) {
3770
- const absPath = path13.join(projectRoot, relPath);
3771
- if (!await pathExists2(absPath)) continue;
3772
- const content = await fs2.readFile(absPath, "utf-8");
4094
+ const absPath = path14.join(projectRoot, relPath);
4095
+ if (!await pathExists3(absPath)) continue;
4096
+ const content = await fs3.readFile(absPath, "utf-8");
3773
4097
  const found = extractCssVariables(content);
3774
4098
  if (Object.keys(found).length === 0) continue;
3775
4099
  Object.assign(variables, found);
@@ -3812,8 +4136,8 @@ function toPascalCase(value) {
3812
4136
  }
3813
4137
  async function hasTailwindDep(projectRoot) {
3814
4138
  try {
3815
- const raw = await fs2.readFile(
3816
- path13.join(projectRoot, "package.json"),
4139
+ const raw = await fs3.readFile(
4140
+ path14.join(projectRoot, "package.json"),
3817
4141
  "utf-8"
3818
4142
  );
3819
4143
  const pkg = JSON.parse(raw);
@@ -3827,9 +4151,9 @@ async function hasTailwindDep(projectRoot) {
3827
4151
  function escapeRegex(s) {
3828
4152
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3829
4153
  }
3830
- async function pathExists2(p) {
4154
+ async function pathExists3(p) {
3831
4155
  try {
3832
- await fs2.access(p);
4156
+ await fs3.access(p);
3833
4157
  return true;
3834
4158
  } catch {
3835
4159
  return false;
@@ -3844,9 +4168,9 @@ var EXIT_USER_CANCEL = 3;
3844
4168
  var EXIT_INIT_FAILED = 5;
3845
4169
  var DEFAULT_INIT_PLATFORM = "claude-code";
3846
4170
  async function init(rootDir = process5.cwd(), options = {}) {
3847
- const mancodeDir = path14.join(rootDir, ".mancode");
3848
- const stateFile = path14.join(mancodeDir, "state.json");
3849
- const wasInitialized = await pathExists3(stateFile);
4171
+ const mancodeDir = path15.join(rootDir, ".mancode");
4172
+ const stateFile = path15.join(mancodeDir, "state.json");
4173
+ const wasInitialized = await pathExists4(stateFile);
3850
4174
  let mutationSnapshots = [];
3851
4175
  let directorySnapshots = [];
3852
4176
  const locale = detectInitLocale(options.lang);
@@ -3882,7 +4206,7 @@ async function init(rootDir = process5.cwd(), options = {}) {
3882
4206
  )
3883
4207
  );
3884
4208
  }
3885
- if (!await pathExists3(rootDir)) {
4209
+ if (!await pathExists4(rootDir)) {
3886
4210
  console.error(
3887
4211
  localize(
3888
4212
  locale,
@@ -3892,26 +4216,28 @@ async function init(rootDir = process5.cwd(), options = {}) {
3892
4216
  );
3893
4217
  return EXIT_NOT_A_PROJECT_DIR;
3894
4218
  }
3895
- const isGitRepo = await pathExists3(path14.join(rootDir, ".git"));
4219
+ const isGitRepo = await pathExists4(path15.join(rootDir, ".git"));
3896
4220
  const hasManifest = await hasProjectManifest(rootDir);
3897
4221
  let isGenericProject = false;
3898
4222
  if (!isGitRepo && !hasManifest) {
3899
4223
  const genericSafety = await canInitializeGenericProject(rootDir);
3900
- if (!genericSafety.ok) {
4224
+ if (!genericSafety.ok && !(wasInitialized && genericSafety.reason === "nonempty")) {
3901
4225
  printNotProjectDirectory(rootDir, locale, genericSafety.reason);
3902
4226
  return EXIT_NOT_A_PROJECT_DIR;
3903
4227
  }
3904
- const prompter = options.prompter ?? (options.interactive ? createTerminalPrompter() : null);
3905
- const confirmed = options.empty || options.yes ? true : prompter ? await prompter.confirmGenericProject({ rootDir, locale }) : false;
3906
- if (!confirmed) {
3907
- if (options.interactive) {
3908
- console.log(
3909
- locale === "zh-CN" ? "\u5DF2\u53D6\u6D88\u521D\u59CB\u5316\u3002" : "Initialization cancelled."
3910
- );
3911
- return EXIT_USER_CANCEL;
4228
+ if (!wasInitialized) {
4229
+ const prompter = options.prompter ?? (options.interactive ? createTerminalPrompter() : null);
4230
+ const confirmed = options.empty || options.yes ? true : prompter ? await prompter.confirmGenericProject({ rootDir, locale }) : false;
4231
+ if (!confirmed) {
4232
+ if (options.interactive) {
4233
+ console.log(
4234
+ locale === "zh-CN" ? "\u5DF2\u53D6\u6D88\u521D\u59CB\u5316\u3002" : "Initialization cancelled."
4235
+ );
4236
+ return EXIT_USER_CANCEL;
4237
+ }
4238
+ printNotProjectDirectory(rootDir, locale, "empty");
4239
+ return EXIT_NOT_A_PROJECT_DIR;
3912
4240
  }
3913
- printNotProjectDirectory(rootDir, locale, "empty");
3914
- return EXIT_NOT_A_PROJECT_DIR;
3915
4241
  }
3916
4242
  isGenericProject = true;
3917
4243
  }
@@ -3966,9 +4292,12 @@ async function init(rootDir = process5.cwd(), options = {}) {
3966
4292
  );
3967
4293
  }
3968
4294
  const existingPlatform = wasInitialized ? await readExistingInitPlatform(stateFile) : null;
4295
+ const existingConfig = wasInitialized ? await readExistingInitPreferences(mancodeDir) : { platforms: [], minimalByPlatform: {} };
4296
+ const recoverablePlatforms = wasInitialized && existingConfig.platforms.length === 0 ? await detectManagedInitPlatforms(rootDir) : [];
4297
+ const forceReinstallPlatforms = options.force && options.platform === void 0 ? existingConfig.platforms.length > 0 ? existingConfig.platforms : recoverablePlatforms : [];
3969
4298
  const platformHints = await detectPlatformHints(rootDir);
3970
4299
  const selectedPlatforms = await selectInitPlatforms({
3971
- option: options.platform,
4300
+ option: options.platform ?? (forceReinstallPlatforms.length > 0 ? forceReinstallPlatforms.join(",") : void 0),
3972
4301
  existingPlatform,
3973
4302
  hints: platformHints,
3974
4303
  interactive: options.interactive,
@@ -4005,13 +4334,17 @@ async function init(rootDir = process5.cwd(), options = {}) {
4005
4334
  const managedFiles = getInitManagedFilePaths(rootDir, selectedPlatforms);
4006
4335
  mutationSnapshots = await snapshotFiles(managedFiles);
4007
4336
  directorySnapshots = await snapshotDirectories(managedFiles, [
4008
- path14.join(mancodeDir, "workflows"),
4009
- path14.join(mancodeDir, "preseason-reports")
4337
+ path15.join(mancodeDir, "workflows"),
4338
+ path15.join(mancodeDir, "preseason-reports")
4010
4339
  ]);
4011
4340
  const team = await detectTeamStatus(rootDir);
4012
- const existingPreferences = wasInitialized ? await readExistingInitPreferences(mancodeDir, primaryPlatform) : {};
4013
- const initialMinimal = existingPreferences.minimal ?? false;
4014
- const existingTeamMode = existingPreferences.forceTeamMode === true ? "on" : existingPreferences.teamMode ?? "auto";
4341
+ const platformMinimal = Object.fromEntries(
4342
+ selectedPlatforms.map((platform) => [
4343
+ platform,
4344
+ existingConfig.minimalByPlatform[platform] ?? false
4345
+ ])
4346
+ );
4347
+ const existingTeamMode = existingConfig.forceTeamMode === true ? "on" : existingConfig.teamMode ?? "auto";
4015
4348
  const teamModeEnabled = options.team ?? (existingTeamMode === "on" ? true : existingTeamMode === "off" ? false : team.isTeam);
4016
4349
  if (options.team === true) {
4017
4350
  console.log(
@@ -4057,12 +4390,12 @@ async function init(rootDir = process5.cwd(), options = {}) {
4057
4390
  await validateClaudeCodeSettings(rootDir);
4058
4391
  }
4059
4392
  await installMancodeCore(rootDir);
4060
- await fs3.mkdir(mancodeDir, { recursive: true });
4393
+ await fs4.mkdir(mancodeDir, { recursive: true });
4061
4394
  const stateContent = `${JSON.stringify(state, null, 2)}
4062
4395
  `;
4063
- await fs3.writeFile(stateFile, stateContent, "utf-8");
4064
- await fs3.writeFile(
4065
- path14.join(mancodeDir, "project-profile.json"),
4396
+ await fs4.writeFile(stateFile, stateContent, "utf-8");
4397
+ await fs4.writeFile(
4398
+ path15.join(mancodeDir, "project-profile.json"),
4066
4399
  `${JSON.stringify(profile, null, 2)}
4067
4400
  `,
4068
4401
  "utf-8"
@@ -4078,7 +4411,7 @@ async function init(rootDir = process5.cwd(), options = {}) {
4078
4411
  ...Object.fromEntries(
4079
4412
  selectedPlatforms.map((platform) => [
4080
4413
  platform,
4081
- { minimal: initialMinimal }
4414
+ { minimal: platformMinimal[platform] ?? false }
4082
4415
  ])
4083
4416
  )
4084
4417
  }
@@ -4099,12 +4432,12 @@ async function init(rootDir = process5.cwd(), options = {}) {
4099
4432
  )
4100
4433
  );
4101
4434
  const tokens = await scanAesthetics(rootDir, uiLibrary);
4102
- const tokensPath = path14.join(
4435
+ const tokensPath = path15.join(
4103
4436
  mancodeDir,
4104
4437
  "aesthetics",
4105
4438
  "style-tokens.json"
4106
4439
  );
4107
- await fs3.writeFile(
4440
+ await fs4.writeFile(
4108
4441
  tokensPath,
4109
4442
  `${JSON.stringify(tokens, null, 2)}
4110
4443
  `,
@@ -4165,7 +4498,7 @@ async function init(rootDir = process5.cwd(), options = {}) {
4165
4498
  techStack: profileStack,
4166
4499
  uiLibrary,
4167
4500
  projectProfile: profile,
4168
- minimal: initialMinimal,
4501
+ minimal: platformMinimal[installer.name] ?? false,
4169
4502
  force: options.force
4170
4503
  });
4171
4504
  }
@@ -4250,16 +4583,16 @@ async function init(rootDir = process5.cwd(), options = {}) {
4250
4583
  }
4251
4584
  }
4252
4585
  async function updateConfigOptions(mancodeDir, patch, preserveInstalledPlatforms) {
4253
- const configPath = path14.join(mancodeDir, "config.json");
4586
+ const configPath = path15.join(mancodeDir, "config.json");
4254
4587
  let config = {};
4255
4588
  try {
4256
- config = JSON.parse(await fs3.readFile(configPath, "utf-8"));
4589
+ config = JSON.parse(await fs4.readFile(configPath, "utf-8"));
4257
4590
  } catch {
4258
4591
  }
4259
4592
  const existingPlatforms = Array.isArray(config.platforms) ? config.platforms.filter(
4260
4593
  (platform) => typeof platform === "string"
4261
4594
  ) : [];
4262
- const existingPlatformOptions = isRecord3(config.platformOptions) ? config.platformOptions : {};
4595
+ const existingPlatformOptions = isRecord4(config.platformOptions) ? config.platformOptions : {};
4263
4596
  const definedPatch = Object.fromEntries(
4264
4597
  Object.entries(patch).filter(([, value]) => value !== void 0)
4265
4598
  );
@@ -4273,44 +4606,60 @@ async function updateConfigOptions(mancodeDir, patch, preserveInstalledPlatforms
4273
4606
  ...patch.platformOptions
4274
4607
  }
4275
4608
  } : definedPatch;
4276
- await fs3.writeFile(
4609
+ await fs4.writeFile(
4277
4610
  configPath,
4278
4611
  `${JSON.stringify({ ...config, ...mergedPatch }, null, 2)}
4279
4612
  `,
4280
4613
  "utf-8"
4281
4614
  );
4282
4615
  }
4283
- async function readExistingInitPreferences(mancodeDir, platform) {
4616
+ async function readExistingInitPreferences(mancodeDir) {
4284
4617
  try {
4285
4618
  const config = JSON.parse(
4286
- await fs3.readFile(path14.join(mancodeDir, "config.json"), "utf-8")
4619
+ await fs4.readFile(path15.join(mancodeDir, "config.json"), "utf-8")
4287
4620
  );
4288
- const preferences = {};
4621
+ const preferences = {
4622
+ platforms: Array.isArray(config.platforms) ? config.platforms.filter(
4623
+ (platform) => typeof platform === "string" && getPlatformInstaller(platform) !== null
4624
+ ) : [],
4625
+ minimalByPlatform: {}
4626
+ };
4289
4627
  if (typeof config.forceTeamMode === "boolean") {
4290
4628
  preferences.forceTeamMode = config.forceTeamMode;
4291
4629
  }
4292
4630
  if (config.teamMode === "auto" || config.teamMode === "on" || config.teamMode === "off") {
4293
4631
  preferences.teamMode = config.teamMode;
4294
4632
  }
4295
- if (Array.isArray(config.platforms) && config.platforms.includes(platform) && isRecord3(config.platformOptions)) {
4296
- const platformOptions = config.platformOptions[platform];
4297
- if (isRecord3(platformOptions) && platformOptions.minimal === true) {
4298
- preferences.minimal = true;
4633
+ if (isRecord4(config.platformOptions)) {
4634
+ for (const platform of preferences.platforms) {
4635
+ const platformOptions = config.platformOptions[platform];
4636
+ if (isRecord4(platformOptions) && platformOptions.minimal === true) {
4637
+ preferences.minimalByPlatform[platform] = true;
4638
+ }
4299
4639
  }
4300
4640
  }
4301
4641
  return preferences;
4302
4642
  } catch {
4303
- return {};
4643
+ return { platforms: [], minimalByPlatform: {} };
4304
4644
  }
4305
4645
  }
4306
4646
  async function readExistingInitPlatform(stateFile) {
4307
4647
  try {
4308
- const state = JSON.parse(await fs3.readFile(stateFile, "utf-8"));
4648
+ const state = JSON.parse(await fs4.readFile(stateFile, "utf-8"));
4309
4649
  return typeof state.platform === "string" && getPlatformInstaller(state.platform) ? state.platform : null;
4310
4650
  } catch {
4311
4651
  return null;
4312
4652
  }
4313
4653
  }
4654
+ async function detectManagedInitPlatforms(rootDir) {
4655
+ const detected = await Promise.all(
4656
+ getPlatformInstallers().map(async (platform) => ({
4657
+ name: platform.name,
4658
+ present: await isPlatformPresent(rootDir, platform.name)
4659
+ }))
4660
+ );
4661
+ return detected.filter((platform) => platform.present).map(({ name }) => name);
4662
+ }
4314
4663
  async function selectInitPlatforms(input) {
4315
4664
  if (input.option !== void 0) {
4316
4665
  return parsePlatformSelection(input.option);
@@ -4333,17 +4682,17 @@ async function selectInitPlatforms(input) {
4333
4682
  }
4334
4683
  async function hasProjectManifest(rootDir) {
4335
4684
  for (const name of PROJECT_MANIFESTS) {
4336
- if (await pathExists3(path14.join(rootDir, name))) return true;
4685
+ if (await pathExists4(path15.join(rootDir, name))) return true;
4337
4686
  }
4338
4687
  return false;
4339
4688
  }
4340
4689
  async function canInitializeGenericProject(rootDir) {
4341
- const resolved = path14.resolve(rootDir);
4342
- if (resolved === path14.parse(resolved).root || resolved === path14.resolve(os.homedir())) {
4690
+ const resolved = path15.resolve(rootDir);
4691
+ if (resolved === path15.parse(resolved).root || resolved === path15.resolve(os.homedir())) {
4343
4692
  return { ok: false, reason: "unsafe" };
4344
4693
  }
4345
4694
  try {
4346
- const entries = await fs3.readdir(resolved);
4695
+ const entries = await fs4.readdir(resolved);
4347
4696
  const meaningfulEntries = entries.filter(
4348
4697
  (entry) => ![".DS_Store", "Thumbs.db", ".gitkeep"].includes(entry)
4349
4698
  );
@@ -4399,432 +4748,164 @@ function getInitManagedFilePaths(rootDir, platforms) {
4399
4748
  if (platforms.includes("claude-code")) {
4400
4749
  files.push(
4401
4750
  ".mancode/hooks/session-start.sh",
4402
- ".mancode/hooks/user-prompt-submit.sh",
4403
- ".claude/settings.json",
4404
- ".claude/skills/man8/SKILL.md",
4405
- ".claude/skills/solo/SKILL.md",
4406
- ".claude/skills/mancode-solo.md",
4407
- ".claude/skills/mancode-man8.md"
4408
- );
4409
- for (const mode of MODE_NAMES) {
4410
- files.push(
4411
- `.claude/skills/${mode}/SKILL.md`,
4412
- `.claude/skills/mancode-${mode}.md`
4413
- );
4414
- }
4415
- for (const agent of ALL_AGENTS) {
4416
- files.push(`.claude/agents/${agent.name}.md`);
4417
- }
4418
- }
4419
- if (platforms.includes("cursor")) {
4420
- files.push(".cursor/rules/mancode-man8.mdc", ".cursor/commands/man8.md");
4421
- for (const fileName of MANCODE_CURSOR_RULE_FILES) {
4422
- files.push(`.cursor/rules/${fileName}`);
4423
- }
4424
- for (const mode of MODE_NAMES) {
4425
- files.push(`.cursor/commands/${mode}.md`);
4426
- }
4427
- }
4428
- if (platforms.includes("codex") || platforms.includes("zcode")) {
4429
- files.push("AGENTS.md", ".agents/skills/man8/SKILL.md");
4430
- for (const mode of MODE_NAMES) {
4431
- files.push(`.agents/skills/${mode}/SKILL.md`);
4432
- }
4433
- }
4434
- if (platforms.includes("codex")) {
4435
- files.push(".codex/skills/man8/SKILL.md");
4436
- for (const mode of MODE_NAMES) {
4437
- files.push(`.codex/skills/${mode}/SKILL.md`);
4438
- }
4439
- }
4440
- if (platforms.includes("zcode")) {
4441
- files.push(".zcode/skills/man8/SKILL.md");
4442
- for (const mode of MODE_NAMES) {
4443
- files.push(`.zcode/skills/${mode}/SKILL.md`);
4444
- }
4445
- }
4446
- if (platforms.includes("copilot")) {
4447
- files.push(
4448
- ".github/copilot-instructions.md",
4449
- ".github/prompts/man8.prompt.md"
4450
- );
4451
- for (const mode of MODE_NAMES) {
4452
- files.push(`.github/prompts/${mode}.prompt.md`);
4453
- }
4454
- }
4455
- return [...new Set(files.map((file) => path14.join(rootDir, file)))];
4456
- }
4457
- async function snapshotFiles(filePaths) {
4458
- return Promise.all(
4459
- filePaths.map(async (filePath) => {
4460
- try {
4461
- return { filePath, content: await fs3.readFile(filePath, "utf-8") };
4462
- } catch (error) {
4463
- if (isNodeError3(error) && error.code === "ENOENT") {
4464
- return { filePath, content: null };
4465
- }
4466
- throw error;
4467
- }
4468
- })
4469
- );
4470
- }
4471
- async function snapshotDirectories(filePaths, additionalDirectories = []) {
4472
- const directories = new Set(additionalDirectories);
4473
- for (const filePath of filePaths) {
4474
- let current = path14.dirname(filePath);
4475
- while (current !== path14.dirname(current)) {
4476
- directories.add(current);
4477
- current = path14.dirname(current);
4478
- }
4479
- }
4480
- return Promise.all(
4481
- [...directories].map(async (dirPath) => ({
4482
- dirPath,
4483
- existed: await pathExists3(dirPath)
4484
- }))
4485
- );
4486
- }
4487
- async function restoreFiles(snapshots) {
4488
- for (const snapshot of snapshots) {
4489
- if (snapshot.content === null) {
4490
- await fs3.rm(snapshot.filePath, { force: true });
4491
- continue;
4492
- }
4493
- await fs3.mkdir(path14.dirname(snapshot.filePath), { recursive: true });
4494
- await fs3.writeFile(snapshot.filePath, snapshot.content, "utf-8");
4495
- }
4496
- }
4497
- async function removeNewEmptyDirectories(snapshots) {
4498
- const candidates = snapshots.filter((snapshot) => !snapshot.existed).sort((a, b) => b.dirPath.length - a.dirPath.length);
4499
- for (const { dirPath } of candidates) {
4500
- try {
4501
- await fs3.rmdir(dirPath);
4502
- } catch {
4503
- }
4504
- }
4505
- }
4506
- function isRecord3(value) {
4507
- return typeof value === "object" && value !== null && !Array.isArray(value);
4508
- }
4509
- function isNodeError3(error) {
4510
- return error instanceof Error && "code" in error;
4511
- }
4512
- function printPlatformCreatedFiles(platform, locale) {
4513
- if (platform === "claude-code") {
4514
- console.log(
4515
- localize(
4516
- locale,
4517
- " .claude/settings.json # hook \u6CE8\u518C",
4518
- " .claude/settings.json # hook registration"
4519
- )
4520
- );
4521
- console.log(
4522
- localize(
4523
- locale,
4524
- " .claude/skills/ # solo + MVP-2 slash skills",
4525
- " .claude/skills/ # solo + MVP-2 slash skills"
4526
- )
4527
- );
4528
- return;
4529
- }
4530
- if (platform === "cursor") {
4531
- console.log(" .cursor/rules/ # Cursor project rules");
4532
- return;
4533
- }
4534
- if (platform === "codex") {
4535
- console.log(" AGENTS.md # Codex managed block");
4536
- console.log(" .agents/skills/ # Codex mode skills");
4537
- return;
4538
- }
4539
- if (platform === "zcode") {
4540
- console.log(" AGENTS.md # ZCode managed block");
4541
- console.log(" .agents/skills/ # ZCode mode skills");
4542
- return;
4543
- }
4544
- console.log(" .github/copilot-instructions.md # Copilot instructions");
4545
- }
4546
- function localize(locale, chinese, english) {
4547
- return locale === "zh-CN" ? chinese : english;
4548
- }
4549
- async function pathExists3(p) {
4550
- try {
4551
- await fs3.access(p);
4552
- return true;
4553
- } catch {
4554
- return false;
4555
- }
4556
- }
4557
-
4558
- // src/commands/install.ts
4559
- import { promises as fs5 } from "fs";
4560
- import path16 from "path";
4561
- import process6 from "process";
4562
-
4563
- // src/installers/platform-status.ts
4564
- import { promises as fs4 } from "fs";
4565
- import path15 from "path";
4566
- async function checkPlatformStatus(rootDir, platform, installed) {
4567
- const readiness = await checkPlatformReadiness(rootDir, platform);
4568
- return {
4569
- installed,
4570
- ready: installed && readiness.ready,
4571
- target: readiness.target,
4572
- detail: describeStatus(installed, readiness)
4573
- };
4574
- }
4575
- async function checkPlatformReadiness(rootDir, platform) {
4576
- if (platform === "claude-code") {
4577
- const [hasSoloSkill, registered, hasHookFiles] = await Promise.all([
4578
- fileMatches(
4579
- path15.join(rootDir, ".claude", "skills", "solo", "SKILL.md"),
4580
- (content) => isGeneratedClaudeSkill(content, "solo")
4581
- ),
4582
- claudeHooksRegistered(rootDir),
4583
- pathsExist([
4584
- path15.join(rootDir, ".mancode", "hooks", "session-start.mjs"),
4585
- path15.join(rootDir, ".mancode", "hooks", "user-prompt-submit.mjs")
4586
- ])
4587
- ]);
4588
- const present = hasSoloSkill && registered && hasHookFiles;
4589
- const minimal = await isPlatformMinimal(rootDir, "claude-code");
4590
- const fullContentReady = minimal ? true : await claudeFullContentReady(rootDir);
4591
- return {
4592
- present,
4593
- ready: present && fullContentReady,
4594
- target: ".claude/",
4595
- readyDetail: present && fullContentReady ? minimal ? "solo skill and hooks ready" : "skills, agents, and hooks ready" : "skills, agents, hook files, or hook registration are incomplete"
4596
- };
4597
- }
4598
- if (platform === "cursor") {
4599
- const hasCoreRules = await allManagedSkills(
4600
- MANCODE_CURSOR_CORE_RULE_FILES.map(
4601
- (file) => path15.join(rootDir, ".cursor", "rules", file)
4602
- ),
4603
- [CURSOR_RULE_MANAGED_MARKER]
4604
- );
4605
- if (await isPlatformMinimal(rootDir, "cursor")) {
4606
- return {
4607
- present: hasCoreRules,
4608
- ready: hasCoreRules,
4609
- target: ".cursor/rules/",
4610
- readyDetail: "mancode core rules present"
4611
- };
4612
- }
4613
- const [hasRules, hasCommands] = await Promise.all([
4614
- allManagedSkills(
4615
- MANCODE_CURSOR_RULE_FILES.map(
4616
- (file) => path15.join(rootDir, ".cursor", "rules", file)
4617
- ),
4618
- [CURSOR_RULE_MANAGED_MARKER]
4619
- ),
4620
- allManagedSkills(
4621
- MODE_NAMES.map(
4622
- (mode) => path15.join(rootDir, ".cursor", "commands", `${mode}.md`)
4623
- ),
4624
- [MODE_FILE_MANAGED_MARKER]
4625
- )
4626
- ]);
4627
- return {
4628
- present: hasCoreRules,
4629
- ready: hasRules && hasCommands,
4630
- target: ".cursor/rules/ + .cursor/commands/",
4631
- readyDetail: hasRules && hasCommands ? "mancode rules and commands present" : "mode rules or commands are missing, incomplete, or user-authored"
4632
- };
4633
- }
4634
- if (platform === "codex") {
4635
- const hasBlock2 = await fileHasManagedBlock(path15.join(rootDir, "AGENTS.md"));
4636
- if (!hasBlock2) {
4637
- return {
4638
- present: false,
4639
- ready: false,
4640
- target: "AGENTS.md",
4641
- readyDetail: "managed block missing"
4642
- };
4751
+ ".mancode/hooks/user-prompt-submit.sh",
4752
+ ".claude/settings.json",
4753
+ ".claude/skills/man8/SKILL.md",
4754
+ ".claude/skills/mamba/SKILL.md",
4755
+ ".claude/skills/solo/SKILL.md",
4756
+ ".claude/skills/mancode-mamba.md",
4757
+ ".claude/skills/mancode-solo.md",
4758
+ ".claude/skills/mancode-man8.md"
4759
+ );
4760
+ for (const mode of MODE_NAMES) {
4761
+ files.push(
4762
+ `.claude/skills/${mode}/SKILL.md`,
4763
+ `.claude/skills/mancode-${mode}.md`
4764
+ );
4643
4765
  }
4644
- if (await isPlatformMinimal(rootDir, "codex")) {
4645
- return {
4646
- present: true,
4647
- ready: true,
4648
- target: "AGENTS.md",
4649
- readyDetail: "managed block present"
4650
- };
4766
+ for (const agent of ALL_AGENTS) {
4767
+ files.push(`.claude/agents/${agent.name}.md`);
4651
4768
  }
4652
- const skillsDir = path15.join(rootDir, ".agents", "skills");
4653
- const hasSkills = await allManagedSkills(
4654
- MODE_NAMES.map((mode) => path15.join(skillsDir, mode, "SKILL.md")),
4655
- MANCODE_AGENT_SKILL_MARKERS
4656
- );
4657
- return {
4658
- present: true,
4659
- ready: hasSkills,
4660
- target: "AGENTS.md + .agents/skills/",
4661
- readyDetail: hasSkills ? "managed block and skills present" : "mode skills are missing, incomplete, or user-authored"
4662
- };
4663
4769
  }
4664
- if (platform === "zcode") {
4665
- const hasBlock2 = await fileHasManagedBlock(
4666
- path15.join(rootDir, "AGENTS.md"),
4667
- ZCODE_MANCODE_START_MARKER,
4668
- ZCODE_MANCODE_END_MARKER
4770
+ if (platforms.includes("cursor")) {
4771
+ files.push(
4772
+ ".cursor/rules/mancode-mamba.mdc",
4773
+ ".cursor/rules/mancode-man8.mdc",
4774
+ ".cursor/commands/mamba.md",
4775
+ ".cursor/commands/man8.md"
4669
4776
  );
4670
- if (!hasBlock2) {
4671
- return {
4672
- present: false,
4673
- ready: false,
4674
- target: "AGENTS.md",
4675
- readyDetail: "managed block missing"
4676
- };
4777
+ for (const fileName of MANCODE_CURSOR_RULE_FILES) {
4778
+ files.push(`.cursor/rules/${fileName}`);
4677
4779
  }
4678
- if (await isPlatformMinimal(rootDir, "zcode")) {
4679
- return {
4680
- present: true,
4681
- ready: true,
4682
- target: "AGENTS.md",
4683
- readyDetail: "managed block present"
4684
- };
4780
+ for (const mode of MODE_NAMES) {
4781
+ files.push(`.cursor/commands/${mode}.md`);
4685
4782
  }
4686
- const skillsDir = path15.join(rootDir, ".agents", "skills");
4687
- const hasSkills = await allManagedSkills(
4688
- MODE_NAMES.map((mode) => path15.join(skillsDir, mode, "SKILL.md")),
4689
- MANCODE_AGENT_SKILL_MARKERS
4783
+ }
4784
+ if (platforms.includes("codex") || platforms.includes("zcode")) {
4785
+ files.push(
4786
+ "AGENTS.md",
4787
+ ".agents/skills/mamba/SKILL.md",
4788
+ ".agents/skills/man8/SKILL.md"
4690
4789
  );
4691
- return {
4692
- present: true,
4693
- ready: hasSkills,
4694
- target: "AGENTS.md + .agents/skills/",
4695
- readyDetail: hasSkills ? "managed block and skills present" : "mode skills are missing, incomplete, or user-authored"
4696
- };
4790
+ for (const mode of MODE_NAMES) {
4791
+ files.push(`.agents/skills/${mode}/SKILL.md`);
4792
+ }
4697
4793
  }
4698
- const hasBlock = await fileHasManagedBlock(
4699
- path15.join(rootDir, ".github", "copilot-instructions.md")
4700
- );
4701
- if (!hasBlock) {
4702
- return {
4703
- present: false,
4704
- ready: false,
4705
- target: ".github/copilot-instructions.md",
4706
- readyDetail: "managed block missing"
4707
- };
4794
+ if (platforms.includes("codex")) {
4795
+ files.push(".codex/skills/mamba/SKILL.md", ".codex/skills/man8/SKILL.md");
4796
+ for (const mode of MODE_NAMES) {
4797
+ files.push(`.codex/skills/${mode}/SKILL.md`);
4798
+ }
4708
4799
  }
4709
- if (!await isPlatformMinimal(rootDir, "copilot")) {
4710
- const promptsDir = path15.join(rootDir, ".github", "prompts");
4711
- const hasPrompts = await allManagedSkills(
4712
- MODE_NAMES.map((mode) => path15.join(promptsDir, `${mode}.prompt.md`)),
4713
- [MODE_FILE_MANAGED_MARKER]
4714
- );
4715
- return {
4716
- present: true,
4717
- ready: hasPrompts,
4718
- target: ".github/copilot-instructions.md + .github/prompts/",
4719
- readyDetail: hasPrompts ? "managed block and prompts present" : "mode prompts are missing, incomplete, or user-authored"
4720
- };
4800
+ if (platforms.includes("zcode")) {
4801
+ files.push(".zcode/skills/mamba/SKILL.md", ".zcode/skills/man8/SKILL.md");
4802
+ for (const mode of MODE_NAMES) {
4803
+ files.push(`.zcode/skills/${mode}/SKILL.md`);
4804
+ }
4721
4805
  }
4722
- return {
4723
- present: true,
4724
- ready: true,
4725
- target: ".github/copilot-instructions.md",
4726
- readyDetail: "managed block present"
4727
- };
4728
- }
4729
- function describeStatus(installed, readiness) {
4730
- if (installed && readiness.present) return readiness.readyDetail;
4731
- if (!installed && readiness.present) {
4732
- return "target files present but platform is not recorded in config";
4806
+ if (platforms.includes("copilot")) {
4807
+ files.push(
4808
+ ".github/copilot-instructions.md",
4809
+ ".github/prompts/mamba.prompt.md",
4810
+ ".github/prompts/man8.prompt.md"
4811
+ );
4812
+ for (const mode of MODE_NAMES) {
4813
+ files.push(`.github/prompts/${mode}.prompt.md`);
4814
+ }
4733
4815
  }
4734
- return "missing generated files or registration";
4816
+ return [...new Set(files.map((file) => path15.join(rootDir, file)))];
4735
4817
  }
4736
- async function allManagedSkills(paths, markers) {
4737
- const results = await Promise.all(
4738
- paths.map((filePath) => fileHasAnyMarker(filePath, markers))
4818
+ async function snapshotFiles(filePaths) {
4819
+ return Promise.all(
4820
+ filePaths.map(async (filePath) => {
4821
+ try {
4822
+ return { filePath, content: await fs4.readFile(filePath, "utf-8") };
4823
+ } catch (error) {
4824
+ if (isNodeError5(error) && error.code === "ENOENT") {
4825
+ return { filePath, content: null };
4826
+ }
4827
+ throw error;
4828
+ }
4829
+ })
4739
4830
  );
4740
- return results.every(Boolean);
4741
4831
  }
4742
- async function claudeFullContentReady(rootDir) {
4743
- const skillChecks = MVP2_SKILLS.map(
4744
- (skill) => fileMatches(
4745
- path15.join(rootDir, ".claude", "skills", skill.name, "SKILL.md"),
4746
- (content) => isGeneratedClaudeSkill(content, skill.name)
4747
- )
4748
- );
4749
- const agentChecks = ALL_AGENTS.map(
4750
- (agent) => fileMatches(
4751
- path15.join(rootDir, ".claude", "agents", `${agent.name}.md`),
4752
- (content) => isGeneratedClaudeAgent(content, agent.name)
4753
- )
4832
+ async function snapshotDirectories(filePaths, additionalDirectories = []) {
4833
+ const directories = new Set(additionalDirectories);
4834
+ for (const filePath of filePaths) {
4835
+ let current = path15.dirname(filePath);
4836
+ while (current !== path15.dirname(current)) {
4837
+ directories.add(current);
4838
+ current = path15.dirname(current);
4839
+ }
4840
+ }
4841
+ return Promise.all(
4842
+ [...directories].map(async (dirPath) => ({
4843
+ dirPath,
4844
+ existed: await pathExists4(dirPath)
4845
+ }))
4754
4846
  );
4755
- const results = await Promise.all([...skillChecks, ...agentChecks]);
4756
- return results.every(Boolean);
4757
4847
  }
4758
- async function fileMatches(filePath, predicate) {
4759
- try {
4760
- return predicate(await fs4.readFile(filePath, "utf-8"));
4761
- } catch {
4762
- return false;
4848
+ async function restoreFiles(snapshots) {
4849
+ for (const snapshot of snapshots) {
4850
+ if (snapshot.content === null) {
4851
+ await fs4.rm(snapshot.filePath, { force: true });
4852
+ continue;
4853
+ }
4854
+ await fs4.mkdir(path15.dirname(snapshot.filePath), { recursive: true });
4855
+ await fs4.writeFile(snapshot.filePath, snapshot.content, "utf-8");
4763
4856
  }
4764
4857
  }
4765
- async function pathsExist(paths) {
4766
- return (await Promise.all(paths.map(pathExists4))).every(Boolean);
4767
- }
4768
- async function fileHasAnyMarker(filePath, needles) {
4769
- try {
4770
- const content = await fs4.readFile(filePath, "utf-8");
4771
- return needles.some((needle) => content.includes(needle));
4772
- } catch {
4773
- return false;
4858
+ async function removeNewEmptyDirectories(snapshots) {
4859
+ const candidates = snapshots.filter((snapshot) => !snapshot.existed).sort((a, b) => b.dirPath.length - a.dirPath.length);
4860
+ for (const { dirPath } of candidates) {
4861
+ try {
4862
+ await fs4.rmdir(dirPath);
4863
+ } catch {
4864
+ }
4774
4865
  }
4775
4866
  }
4776
- async function isPlatformMinimal(rootDir, platform) {
4777
- try {
4778
- const raw = await fs4.readFile(
4779
- path15.join(rootDir, ".mancode", "config.json"),
4780
- "utf-8"
4781
- );
4782
- const config = JSON.parse(raw);
4783
- if (!isRecord4(config.platformOptions)) return false;
4784
- const options = config.platformOptions[platform];
4785
- return isRecord4(options) && options.minimal === true;
4786
- } catch {
4787
- return false;
4788
- }
4867
+ function isRecord4(value) {
4868
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4789
4869
  }
4790
- async function fileHasManagedBlock(filePath, startMarker = DEFAULT_MANCODE_START_MARKER, endMarker = DEFAULT_MANCODE_END_MARKER) {
4791
- try {
4792
- const content = await fs4.readFile(filePath, "utf-8");
4793
- return hasManagedBlock(content, startMarker, endMarker);
4794
- } catch {
4795
- return false;
4796
- }
4870
+ function isNodeError5(error) {
4871
+ return error instanceof Error && "code" in error;
4797
4872
  }
4798
- async function claudeHooksRegistered(rootDir) {
4799
- try {
4800
- const raw = await fs4.readFile(
4801
- path15.join(rootDir, ".claude", "settings.json"),
4802
- "utf-8"
4873
+ function printPlatformCreatedFiles(platform, locale) {
4874
+ if (platform === "claude-code") {
4875
+ console.log(
4876
+ localize(
4877
+ locale,
4878
+ " .claude/settings.json # hook \u6CE8\u518C",
4879
+ " .claude/settings.json # hook registration"
4880
+ )
4803
4881
  );
4804
- const settings = JSON.parse(raw);
4805
- return hooksRegistered(settings);
4806
- } catch {
4807
- return false;
4882
+ console.log(
4883
+ localize(
4884
+ locale,
4885
+ " .claude/skills/ # solo + MVP-2 slash skills",
4886
+ " .claude/skills/ # solo + MVP-2 slash skills"
4887
+ )
4888
+ );
4889
+ return;
4808
4890
  }
4891
+ if (platform === "cursor") {
4892
+ console.log(" .cursor/rules/ # Cursor project rules");
4893
+ return;
4894
+ }
4895
+ if (platform === "codex") {
4896
+ console.log(" AGENTS.md # Codex managed block");
4897
+ console.log(" .agents/skills/ # Codex mode skills");
4898
+ return;
4899
+ }
4900
+ if (platform === "zcode") {
4901
+ console.log(" AGENTS.md # ZCode managed block");
4902
+ console.log(" .agents/skills/ # ZCode mode skills");
4903
+ return;
4904
+ }
4905
+ console.log(" .github/copilot-instructions.md # Copilot instructions");
4809
4906
  }
4810
- function hooksRegistered(settings) {
4811
- if (!isRecord4(settings)) return false;
4812
- const hooks = settings.hooks;
4813
- if (!isRecord4(hooks)) return false;
4814
- return hasHookCommand(hooks.SessionStart, ".mancode/hooks/session-start.mjs") && hasHookCommand(
4815
- hooks.UserPromptSubmit,
4816
- ".mancode/hooks/user-prompt-submit.mjs"
4817
- );
4818
- }
4819
- function hasHookCommand(value, needle) {
4820
- if (!Array.isArray(value)) return false;
4821
- return value.some((group) => {
4822
- if (!isRecord4(group) || !Array.isArray(group.hooks)) return false;
4823
- return group.hooks.some((hook) => {
4824
- if (!isRecord4(hook) || typeof hook.command !== "string") return false;
4825
- return hook.command.includes(needle);
4826
- });
4827
- });
4907
+ function localize(locale, chinese, english) {
4908
+ return locale === "zh-CN" ? chinese : english;
4828
4909
  }
4829
4910
  async function pathExists4(p) {
4830
4911
  try {
@@ -4834,11 +4915,11 @@ async function pathExists4(p) {
4834
4915
  return false;
4835
4916
  }
4836
4917
  }
4837
- function isRecord4(value) {
4838
- return typeof value === "object" && value !== null;
4839
- }
4840
4918
 
4841
4919
  // src/commands/install.ts
4920
+ import { promises as fs5 } from "fs";
4921
+ import path16 from "path";
4922
+ import process6 from "process";
4842
4923
  var EXIT_OK2 = 0;
4843
4924
  var EXIT_NOT_INITIALIZED = 1;
4844
4925
  var EXIT_UNSUPPORTED_PLATFORM = 2;
@@ -4935,13 +5016,13 @@ async function readConfig(rootDir) {
4935
5016
  const raw = await fs5.readFile(configPath, "utf-8");
4936
5017
  return { config: JSON.parse(raw), valid: true };
4937
5018
  } catch (err) {
4938
- if (isNodeError4(err) && err.code === "ENOENT") {
5019
+ if (isNodeError6(err) && err.code === "ENOENT") {
4939
5020
  return { config: {}, valid: false };
4940
5021
  }
4941
5022
  throw err;
4942
5023
  }
4943
5024
  }
4944
- function isNodeError4(err) {
5025
+ function isNodeError6(err) {
4945
5026
  return err instanceof Error && "code" in err;
4946
5027
  }
4947
5028
  async function updateConfig(rootDir, config) {
@@ -5749,7 +5830,7 @@ async function readIssueDatabase(issueDbPath) {
5749
5830
  try {
5750
5831
  raw = await readFile8(issueDbPath, "utf-8");
5751
5832
  } catch (err) {
5752
- if (isNodeError5(err) && err.code === "ENOENT") {
5833
+ if (isNodeError7(err) && err.code === "ENOENT") {
5753
5834
  return emptyIssueDatabase();
5754
5835
  }
5755
5836
  throw err;
@@ -5960,7 +6041,7 @@ async function pathExists6(file) {
5960
6041
  return false;
5961
6042
  }
5962
6043
  }
5963
- function isNodeError5(err) {
6044
+ function isNodeError7(err) {
5964
6045
  return err instanceof Error && "code" in err;
5965
6046
  }
5966
6047
  function isRecord6(value) {
@@ -6255,7 +6336,7 @@ async function ensureReplaceableFile(filePath) {
6255
6336
  throw new Error(`cannot replace non-file path: ${filePath}`);
6256
6337
  }
6257
6338
  } catch (error) {
6258
- if (isNodeError6(error) && error.code === "ENOENT") return;
6339
+ if (isNodeError8(error) && error.code === "ENOENT") return;
6259
6340
  throw error;
6260
6341
  }
6261
6342
  }
@@ -6272,7 +6353,7 @@ async function readOptionalText(filePath) {
6272
6353
  try {
6273
6354
  return await fs7.readFile(filePath, "utf-8");
6274
6355
  } catch (error) {
6275
- if (isNodeError6(error) && error.code === "ENOENT") return null;
6356
+ if (isNodeError8(error) && error.code === "ENOENT") return null;
6276
6357
  throw error;
6277
6358
  }
6278
6359
  }
@@ -6335,7 +6416,7 @@ async function readRequiredState(filePath) {
6335
6416
  function isRecord7(value) {
6336
6417
  return typeof value === "object" && value !== null && !Array.isArray(value);
6337
6418
  }
6338
- function isNodeError6(error) {
6419
+ function isNodeError8(error) {
6339
6420
  return error instanceof Error && "code" in error;
6340
6421
  }
6341
6422
  async function pathExists8(filePath) {
@@ -6755,7 +6836,7 @@ async function allocateTaskId(projectRoot, baseTaskId) {
6755
6836
  await mkdir9(workflowDir(projectRoot, taskId));
6756
6837
  return taskId;
6757
6838
  } catch (err) {
6758
- if (isNodeError7(err) && err.code === "EEXIST") {
6839
+ if (isNodeError9(err) && err.code === "EEXIST") {
6759
6840
  continue;
6760
6841
  }
6761
6842
  throw err;
@@ -6871,7 +6952,7 @@ function isWorkflowOutcome(value) {
6871
6952
  async function validateParentTask(projectRoot, mode, parentTaskId, requireStepSix = false) {
6872
6953
  if (!parentTaskId) return;
6873
6954
  if (mode !== "mamba") {
6874
- throw new Error("only mamba workflows can have a parent task");
6955
+ throw new Error("only manba workflows can have a parent task");
6875
6956
  }
6876
6957
  const parent = await readWorkflow(projectRoot, parentTaskId);
6877
6958
  if (!parent || parent.mode !== "man" && parent.mode !== "manteam") {
@@ -6911,14 +6992,14 @@ async function validateWorkflowMeta(projectRoot, updated, existing) {
6911
6992
  );
6912
6993
  }
6913
6994
  if (updated.status === "planned" && updated.mode === "mamba") {
6914
- throw new Error("mamba workflows cannot be planned");
6995
+ throw new Error("manba workflows cannot be planned");
6915
6996
  }
6916
6997
  if (updated.status === "planned" && updated.currentStep !== 4) {
6917
6998
  throw new Error("planned workflows must be at step 4");
6918
6999
  }
6919
7000
  if (updated.status === "completed" && updated.currentStep !== maxWorkflowStep(updated.mode)) {
6920
7001
  throw new Error(
6921
- `completed ${updated.mode} workflows must be at step ${maxWorkflowStep(updated.mode)}`
7002
+ `completed ${updated.mode === "mamba" ? "manba" : updated.mode} workflows must be at step ${maxWorkflowStep(updated.mode)}`
6922
7003
  );
6923
7004
  }
6924
7005
  if (updated.blockingReason !== void 0 && typeof updated.blockingReason !== "string") {
@@ -6932,25 +7013,25 @@ async function validateWorkflowMeta(projectRoot, updated, existing) {
6932
7013
  throw new Error("only blocked workflows can have a blocking reason");
6933
7014
  }
6934
7015
  if (updated.mode !== "mamba" && updated.outcome !== void 0) {
6935
- throw new Error("only mamba workflows can have an outcome");
7016
+ throw new Error("only manba workflows can have an outcome");
6936
7017
  }
6937
7018
  if (updated.outcome !== void 0 && !isWorkflowOutcome(updated.outcome)) {
6938
7019
  throw new Error(`invalid workflow outcome: ${updated.outcome}`);
6939
7020
  }
6940
7021
  if (updated.outcome !== void 0 && updated.status !== "completed") {
6941
- throw new Error("mamba outcomes can only be set on completed workflows");
7022
+ throw new Error("manba outcomes can only be set on completed workflows");
6942
7023
  }
6943
7024
  if (updated.mode === "mamba" && updated.status === "completed" && !updated.outcome) {
6944
- throw new Error("completed mamba workflows require an outcome");
7025
+ throw new Error("completed manba workflows require an outcome");
6945
7026
  }
6946
7027
  if (updated.mode === "mamba" && updated.planVersion !== void 0) {
6947
- throw new Error("mamba workflows cannot have a plan version");
7028
+ throw new Error("manba workflows cannot have a plan version");
6948
7029
  }
6949
7030
  if (updated.reviewPolicyVersion !== void 0 && updated.reviewPolicyVersion !== 1) {
6950
7031
  throw new Error("invalid workflow review policy version");
6951
7032
  }
6952
7033
  if (updated.mode === "mamba" && updated.reviewPolicyVersion !== void 0) {
6953
- throw new Error("mamba workflows cannot have a review policy version");
7034
+ throw new Error("manba workflows cannot have a review policy version");
6954
7035
  }
6955
7036
  if (updated.planVersion !== void 0 && (!Number.isInteger(updated.planVersion) || updated.planVersion < 1)) {
6956
7037
  throw new Error("workflow plan version must be a positive integer");
@@ -6963,7 +7044,7 @@ async function validateWorkflowMeta(projectRoot, updated, existing) {
6963
7044
  }
6964
7045
  await validateParentTask(projectRoot, updated.mode, updated.parentTaskId);
6965
7046
  if ((isTerminalWorkflowStatus(updated.status) || updated.status === "planned") && (await listActiveMambaChildren(projectRoot, updated.taskId)).length > 0) {
6966
- throw new Error("cannot finish workflow with an active mamba child");
7047
+ throw new Error("cannot finish workflow with an active manba child");
6967
7048
  }
6968
7049
  if (updated.status === "completed" && updated.reviewPolicyVersion === 1 && !reviewWasExplicitlySkipped(updated) && !await reviewCanComplete(projectRoot, updated.taskId)) {
6969
7050
  throw new Error("workflow review is incomplete or still has open blockers");
@@ -7034,7 +7115,7 @@ async function propagateChildStatus(projectRoot, child) {
7034
7115
  if (!parentTaskId) return;
7035
7116
  const parent = await readWorkflow(projectRoot, parentTaskId);
7036
7117
  if (!parent || parent.status !== "in_progress") return;
7037
- const reason = child.status === "blocked" ? `mamba child ${child.taskId} is blocked: ${child.blockingReason ?? "unknown reason"}` : `mamba child ${child.taskId} requires manual testing`;
7118
+ const reason = child.status === "blocked" ? `manba child ${child.taskId} is blocked: ${child.blockingReason ?? "unknown reason"}` : `manba child ${child.taskId} requires manual testing`;
7038
7119
  await writeMetadata(workflowDir(projectRoot, parent.taskId), {
7039
7120
  ...parent,
7040
7121
  status: "blocked",
@@ -7049,7 +7130,7 @@ async function propagateChildStatus(projectRoot, child) {
7049
7130
  });
7050
7131
  }
7051
7132
  }
7052
- function isNodeError7(err) {
7133
+ function isNodeError9(err) {
7053
7134
  return err instanceof Error && "code" in err;
7054
7135
  }
7055
7136
  function assertValidTaskId2(taskId) {
@@ -7309,7 +7390,8 @@ function runHookEstimate(rootDir, hookPath) {
7309
7390
  });
7310
7391
  }
7311
7392
  function printText(r) {
7312
- const modeLabel = r.mode === "solo" ? `${r.mode} (default)` : r.mode;
7393
+ const publicMode = r.mode === "mamba" ? "manba" : r.mode;
7394
+ const modeLabel = publicMode === "solo" ? `${publicMode} (default)` : publicMode;
7313
7395
  console.log("");
7314
7396
  console.log(`mancode v${r.version}`);
7315
7397
  console.log("");
@@ -7686,7 +7768,7 @@ async function workflow(rootDir, subcommand, args = [], options = {}) {
7686
7768
  } else {
7687
7769
  console.error(`\u2717 Invalid workflow subcommand: ${subcommand}`);
7688
7770
  console.error(
7689
- " Use: create <man|mamba|manteam> <task> | update <taskId> | review <taskId> <init|complete|remediate|show> | list | show <taskId> | clean"
7771
+ " Use: create <man|manba|manteam> <task> | update <taskId> | review <taskId> <init|complete|remediate|show> | list | show <taskId> | clean"
7690
7772
  );
7691
7773
  }
7692
7774
  return EXIT_INVALID_ARG2;
@@ -7790,20 +7872,21 @@ function parseCsv(value) {
7790
7872
  return (value ?? "").split(",").map((item) => item.trim()).filter(Boolean);
7791
7873
  }
7792
7874
  async function workflowCreate(rootDir, args, options) {
7793
- const mode = args[0];
7875
+ const requestedMode = args[0];
7876
+ const mode = parsePublicWorkflowMode(requestedMode);
7794
7877
  const task = args.slice(1).join(" ").trim();
7795
- if (mode !== "man" && mode !== "mamba" && mode !== "manteam") {
7878
+ if (!mode) {
7796
7879
  return invalidArg(
7797
7880
  options,
7798
- `invalid workflow mode: ${mode ?? ""}`,
7799
- "Use: mancode workflow create <man|mamba|manteam> <task> [--parent-task <taskId>]"
7881
+ `invalid workflow mode: ${requestedMode ?? ""}`,
7882
+ "Use: mancode workflow create <man|manba|manteam> <task> [--parent-task <taskId>]"
7800
7883
  );
7801
7884
  }
7802
7885
  if (!task) {
7803
7886
  return invalidArg(
7804
7887
  options,
7805
7888
  "missing workflow task",
7806
- "Use: mancode workflow create <man|mamba|manteam> <task> [--parent-task <taskId>]"
7889
+ "Use: mancode workflow create <man|manba|manteam> <task> [--parent-task <taskId>]"
7807
7890
  );
7808
7891
  }
7809
7892
  try {
@@ -7873,7 +7956,7 @@ async function workflowUpdate(rootDir, taskId, options) {
7873
7956
  if (existing.mode !== "mamba" || nextStatus !== "completed") {
7874
7957
  return invalidArg(
7875
7958
  options,
7876
- "--outcome is only valid when completing a mamba workflow"
7959
+ "--outcome is only valid when completing a manba workflow"
7877
7960
  );
7878
7961
  }
7879
7962
  patch.outcome = options.outcome;
@@ -7981,7 +8064,7 @@ async function workflowShow(rootDir, taskId, options) {
7981
8064
  }
7982
8065
  console.log(`Workflow: ${meta.taskId}`);
7983
8066
  console.log(`Task: ${meta.task}`);
7984
- console.log(`Mode: ${meta.mode}`);
8067
+ console.log(`Mode: ${formatPublicWorkflowMode(meta.mode)}`);
7985
8068
  console.log(`Status: ${meta.status}`);
7986
8069
  console.log(`Current step:${meta.currentStep}/${maxWorkflowStep(meta.mode)}`);
7987
8070
  console.log(
@@ -7996,7 +8079,7 @@ async function workflowShow(rootDir, taskId, options) {
7996
8079
  if (meta.blockingReason) console.log(`Blocked: ${meta.blockingReason}`);
7997
8080
  if (children !== void 0) {
7998
8081
  if (children.length > 0) {
7999
- console.log(`Children: ${children.length} active mamba workflow(s)`);
8082
+ console.log(`Children: ${children.length} active manba workflow(s)`);
8000
8083
  for (const child of children) {
8001
8084
  console.log(
8002
8085
  ` - ${child.taskId} (Step ${child.currentStep}/5, ${child.status})`
@@ -8084,7 +8167,15 @@ function formatWorkflowRow(meta) {
8084
8167
  meta.blockingReason ? `blocked=${meta.blockingReason}` : "",
8085
8168
  meta.activeChildren && meta.activeChildren.length > 0 ? `children=${meta.activeChildren.map((child) => child.taskId).join(",")}` : ""
8086
8169
  ].filter(Boolean);
8087
- return `${meta.taskId.padEnd(42)} ${meta.mode.padEnd(7)} ${meta.status.padEnd(11)} ${step}${details.length > 0 ? ` | ${details.join(" | ")}` : ""}`;
8170
+ return `${meta.taskId.padEnd(42)} ${formatPublicWorkflowMode(meta.mode).padEnd(7)} ${meta.status.padEnd(11)} ${step}${details.length > 0 ? ` | ${details.join(" | ")}` : ""}`;
8171
+ }
8172
+ function parsePublicWorkflowMode(value) {
8173
+ if (value === "manba" || value === "mamba") return "mamba";
8174
+ if (value === "man" || value === "manteam") return value;
8175
+ return null;
8176
+ }
8177
+ function formatPublicWorkflowMode(mode) {
8178
+ return mode === "mamba" ? "manba" : mode;
8088
8179
  }
8089
8180
  function attachActiveChildren(workflows) {
8090
8181
  return workflows.map((meta) => {
@@ -8142,7 +8233,7 @@ async function pathExists12(p) {
8142
8233
 
8143
8234
  // src/cli.ts
8144
8235
  program.name("mancode").description(
8145
- "AI coding agent harness. Modes: solo, man, mamba, manteam, manps."
8236
+ "AI coding agent harness. Modes: solo, man, manba, manteam, manps."
8146
8237
  ).version(VERSION);
8147
8238
  program.command("init").description("Initialize mancode in the current project").option("--force", "Reinstall even if already initialized").option("--yes", "Skip all confirmations (CI mode)").option("--team", "Force enable team mode (MVP-2)").option("--no-team", "Force disable team mode (MVP-2)").option("--style <name>", "Specify aesthetic style (MVP-2)").option("--platform <platforms>", "Adapters: comma-separated names or all").option("--empty", "Initialize a safe empty directory as a generic project").option("--lang <locale>", "Initialization language: zh-CN or en").action(async (options) => {
8148
8239
  const code = await init(process.cwd(), {
@@ -8175,8 +8266,8 @@ program.command("uninstall [platform]").description("Remove platform adapter or
8175
8266
  });
8176
8267
  program.command("workflow <subcommand> [args...]").description("Manage mancode workflows").option("--dry-run", "Preview clean without deleting").option("--older-than <duration>", "Clean workflows older than (e.g. 30d)").option("--step <n>", "Update workflow current step").option("--status <status>", "Update workflow status").option(
8177
8268
  "--parent-task <taskId>",
8178
- "Parent /man or /manteam workflow for mamba"
8179
- ).option("--blocking-reason <reason>", "Explain why a workflow is blocked").option("--outcome <outcome>", "Set mamba outcome").option("--plan-version <n>", "Set the next man/manteam plan revision").option("--skipped <steps>", "Update skipped steps as comma-separated values").option("--review-depth <depth>", "Review depth: targeted or full").option("--review-domain <domain>", "Review domain: quality or security").option(
8269
+ "Parent /man or /manteam workflow for manba"
8270
+ ).option("--blocking-reason <reason>", "Explain why a workflow is blocked").option("--outcome <outcome>", "Set manba outcome").option("--plan-version <n>", "Set the next man/manteam plan revision").option("--skipped <steps>", "Update skipped steps as comma-separated values").option("--review-depth <depth>", "Review depth: targeted or full").option("--review-domain <domain>", "Review domain: quality or security").option(
8180
8271
  "--report <path>",
8181
8272
  "Relative Markdown report path for a review domain"
8182
8273
  ).option("--blockers <ids>", "Comma-separated blocker ids found by a review").option(