mover-os 4.0.8 → 4.0.10

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.

Potentially problematic release.


This version of mover-os might be problematic. Click here for more details.

package/install.js CHANGED
@@ -251,7 +251,7 @@ function interactiveSelect(items, { multi = false, preSelected = [], defaultInde
251
251
  let tierLabel = "";
252
252
  if (item.tier === "Full") tierLabel = `${S.green}Full${S.reset}`;
253
253
  else if (item.tier === "Enhanced") tierLabel = `${S.cyan}Enhanced${S.reset}`;
254
- else if (item.tier === "Basic+" || item.tier === "Basic") tierLabel = `${S.gray}${item.tier}${S.reset}`;
254
+ else if (item.tier === "Basic") tierLabel = `${S.gray}Basic${S.reset}`;
255
255
  else if (item.tier === "recommended") tierLabel = `${S.green}recommended${S.reset}`;
256
256
  else if (item.tier) tierLabel = dim(item.tier);
257
257
 
@@ -397,6 +397,9 @@ async function runUninstall(vaultPath) {
397
397
  { label: "Antigravity rules", path: path.join(home, ".gemini", "GEMINI.md") },
398
398
  { label: "Antigravity workflows", path: path.join(home, ".gemini", "antigravity", "global_workflows"), dir: true },
399
399
  { label: "Codex instructions", path: path.join(home, ".codex", "instructions.md") },
400
+ { label: "Codex skills", path: path.join(home, ".codex", "skills"), dir: true },
401
+ { label: "Windsurf skills", path: path.join(home, ".windsurf", "skills"), dir: true },
402
+ { label: "Antigravity skills", path: path.join(home, ".gemini", "antigravity", "skills"), dir: true },
400
403
  { label: "Claude Code hooks", path: path.join(home, ".claude", "hooks"), dir: true },
401
404
  ];
402
405
 
@@ -466,6 +469,7 @@ async function runUninstall(vaultPath) {
466
469
 
467
470
  // ─── Agent definitions ──────────────────────────────────────────────────────
468
471
  const AGENTS = [
472
+ // ── Full (rules + skills + commands/workflows + hooks) ──
469
473
  {
470
474
  id: "claude-code",
471
475
  name: "Claude Code",
@@ -484,54 +488,62 @@ const AGENTS = [
484
488
  tier: "Full",
485
489
  detect: () => globDirExists(path.join(os.homedir(), ".vscode", "extensions"), "saoudrizwan.claude-dev-*"),
486
490
  },
487
- {
488
- id: "codex",
489
- name: "Codex CLI",
490
- tier: "Enhanced",
491
- detect: () => cmdExists("codex") || fs.existsSync(path.join(os.homedir(), ".codex")),
492
- },
493
491
  {
494
492
  id: "windsurf",
495
493
  name: "Windsurf",
496
- tier: "Enhanced",
494
+ tier: "Full",
497
495
  detect: () => fs.existsSync(path.join(os.homedir(), ".windsurf")) || cmdExists("windsurf"),
498
496
  },
499
497
  {
500
- id: "openclaw",
501
- name: "OpenClaw",
498
+ id: "gemini-cli",
499
+ name: "Gemini CLI",
500
+ tier: "Full",
501
+ detect: () => cmdExists("gemini") || fs.existsSync(path.join(os.homedir(), ".gemini", "settings.json")),
502
+ },
503
+ {
504
+ id: "copilot",
505
+ name: "GitHub Copilot",
506
+ tier: "Full",
507
+ detect: () => cmdExists("gh"),
508
+ },
509
+ // ── Enhanced (rules + skills) ──
510
+ {
511
+ id: "codex-cli",
512
+ name: "Codex CLI",
502
513
  tier: "Enhanced",
503
- detect: () => fs.existsSync(path.join(os.homedir(), ".openclaw")) || cmdExists("openclaw"),
514
+ detect: () => cmdExists("codex") || fs.existsSync(path.join(os.homedir(), ".codex")),
504
515
  },
505
516
  {
506
- id: "gemini-cli",
507
- name: "Gemini CLI",
517
+ id: "codex-cloud",
518
+ name: "Codex (Cloud)",
508
519
  tier: "Enhanced",
509
- detect: () => cmdExists("gemini") || fs.existsSync(path.join(os.homedir(), ".gemini", "settings.json")),
520
+ detect: () => false, // Browser-based no local detection possible
510
521
  },
511
522
  {
512
523
  id: "antigravity",
513
524
  name: "Antigravity",
514
- tier: "Basic+",
525
+ tier: "Enhanced",
515
526
  detect: () => fs.existsSync(path.join(os.homedir(), ".gemini", "antigravity")),
516
527
  },
528
+ {
529
+ id: "openclaw",
530
+ name: "OpenClaw",
531
+ tier: "Enhanced",
532
+ detect: () => fs.existsSync(path.join(os.homedir(), ".openclaw")) || cmdExists("openclaw"),
533
+ },
517
534
  {
518
535
  id: "roo-code",
519
536
  name: "Roo Code",
520
- tier: "Basic",
537
+ tier: "Enhanced",
521
538
  detect: () => globDirExists(path.join(os.homedir(), ".vscode", "extensions"), "rooveterinaryinc.roo-cline-*"),
522
539
  },
523
- {
524
- id: "copilot",
525
- name: "GitHub Copilot",
526
- tier: "Basic",
527
- detect: () => cmdExists("gh"),
528
- },
529
540
  {
530
541
  id: "amp",
531
542
  name: "Amp",
532
- tier: "Basic",
543
+ tier: "Enhanced",
533
544
  detect: () => cmdExists("amp") || fs.existsSync(path.join(os.homedir(), ".amp")),
534
545
  },
546
+ // ── Basic (rules only) ──
535
547
  {
536
548
  id: "aider",
537
549
  name: "Aider",
@@ -589,6 +601,72 @@ function copyDirRecursive(src, dest) {
589
601
  }
590
602
  }
591
603
 
604
+ // ─── Skill categories (maps skill folder name → category) ───────────────────
605
+ const SKILL_CATEGORIES = {
606
+ // Development
607
+ "agent-code-reviewer": "development",
608
+ "agent-security-auditor": "development",
609
+ "systematic-debugging": "development",
610
+ "find-bugs": "development",
611
+ "refactoring": "development",
612
+ "react-best-practices": "development",
613
+ "webhook-handler-patterns": "development",
614
+ // Marketing
615
+ "copywriting": "marketing",
616
+ "copy-editing": "marketing",
617
+ "seo-audit": "marketing",
618
+ "seo-content-writer": "marketing",
619
+ "social-content": "marketing",
620
+ "email-sequence": "marketing",
621
+ "paid-ads": "marketing",
622
+ "analytics-tracking": "marketing",
623
+ "human-writer": "marketing",
624
+ "marketing-ideas": "marketing",
625
+ "marketing-psychology": "marketing",
626
+ "ab-test-setup": "marketing",
627
+ // CRO
628
+ "page-cro": "cro",
629
+ "form-cro": "cro",
630
+ "signup-flow-cro": "cro",
631
+ "onboarding-cro": "cro",
632
+ "popup-cro": "cro",
633
+ "paywall-upgrade-cro": "cro",
634
+ // Strategy
635
+ "pricing-strategy": "strategy",
636
+ "launch-strategy": "strategy",
637
+ "competitor-alternatives": "strategy",
638
+ "free-tool-strategy": "strategy",
639
+ "referral-program": "strategy",
640
+ "agent-strategy-analyst": "strategy",
641
+ "agent-research-analyst": "strategy",
642
+ "agent-content-researcher": "strategy",
643
+ // SEO
644
+ "programmatic-seo": "seo",
645
+ "schema-markup": "seo",
646
+ // Design
647
+ "frontend-design": "design",
648
+ "ui-ux-pro-max": "design",
649
+ // Obsidian
650
+ "obsidian-markdown": "obsidian",
651
+ "obsidian-bases": "obsidian",
652
+ "obsidian-cli": "obsidian",
653
+ "json-canvas": "obsidian",
654
+ // Tools (always installed — core utilities)
655
+ "defuddle": "tools",
656
+ "skill-creator": "tools",
657
+ "find-skills": "tools",
658
+ };
659
+
660
+ const CATEGORY_META = [
661
+ { id: "development", name: "Development", desc: "code review, debugging, security" },
662
+ { id: "marketing", name: "Marketing", desc: "copy, SEO, social, email, ads" },
663
+ { id: "cro", name: "CRO", desc: "page optimization, forms, popups" },
664
+ { id: "strategy", name: "Strategy", desc: "pricing, launch, competitors" },
665
+ { id: "seo", name: "SEO", desc: "programmatic SEO, schema markup" },
666
+ { id: "design", name: "Design", desc: "frontend, UI/UX" },
667
+ { id: "obsidian", name: "Obsidian", desc: "markdown, bases, canvas, CLI" },
668
+ ];
669
+
592
670
  function findSkills(bundleDir) {
593
671
  const skillsDir = path.join(bundleDir, "src", "skills");
594
672
  if (!fs.existsSync(skillsDir)) return [];
@@ -598,7 +676,7 @@ function findSkills(bundleDir) {
598
676
  const full = path.join(dir, entry.name);
599
677
  if (entry.isDirectory()) {
600
678
  if (fs.existsSync(path.join(full, "SKILL.md"))) {
601
- skills.push({ name: entry.name, path: full });
679
+ skills.push({ name: entry.name, path: full, category: SKILL_CATEGORIES[entry.name] || "tools" });
602
680
  } else {
603
681
  walk(full);
604
682
  }
@@ -832,11 +910,13 @@ function installRules(bundleDir, destPath) {
832
910
  return linkOrCopy(src, destPath) !== null;
833
911
  }
834
912
 
835
- function installSkillPacks(bundleDir, destDir) {
913
+ function installSkillPacks(bundleDir, destDir, selectedCategories) {
836
914
  const skills = findSkills(bundleDir);
837
915
  fs.mkdirSync(destDir, { recursive: true });
838
916
  let count = 0;
839
917
  for (const skill of skills) {
918
+ // Filter by category if categories were selected (tools always installed)
919
+ if (selectedCategories && skill.category !== "tools" && !selectedCategories.has(skill.category)) continue;
840
920
  const dest = path.join(destDir, skill.name);
841
921
  if (fs.existsSync(dest)) fs.rmSync(dest, { recursive: true, force: true });
842
922
  copyDirRecursive(skill.path, dest);
@@ -870,7 +950,7 @@ function installHooksForClaude(bundleDir, vaultPath) {
870
950
  }
871
951
 
872
952
  // ─── Per-agent install orchestrators ────────────────────────────────────────
873
- function installClaudeCode(bundleDir, vaultPath) {
953
+ function installClaudeCode(bundleDir, vaultPath, skillOpts) {
874
954
  const home = os.homedir();
875
955
  const steps = [];
876
956
 
@@ -882,9 +962,11 @@ function installClaudeCode(bundleDir, vaultPath) {
882
962
  const wfCount = installWorkflows(bundleDir, cmdsDir);
883
963
  if (wfCount > 0) steps.push(`${wfCount} commands`);
884
964
 
885
- const skillsDir = path.join(claudeDir, "skills");
886
- const skCount = installSkillPacks(bundleDir, skillsDir);
887
- if (skCount > 0) steps.push(`${skCount} skills`);
965
+ if (skillOpts && skillOpts.install) {
966
+ const skillsDir = path.join(claudeDir, "skills");
967
+ const skCount = installSkillPacks(bundleDir, skillsDir, skillOpts.categories);
968
+ if (skCount > 0) steps.push(`${skCount} skills`);
969
+ }
888
970
 
889
971
  if (vaultPath) {
890
972
  const hkCount = installHooksForClaude(bundleDir, vaultPath);
@@ -894,7 +976,7 @@ function installClaudeCode(bundleDir, vaultPath) {
894
976
  return steps;
895
977
  }
896
978
 
897
- function installCursor(bundleDir, vaultPath) {
979
+ function installCursor(bundleDir, vaultPath, skillOpts) {
898
980
  const home = os.homedir();
899
981
  const steps = [];
900
982
 
@@ -913,14 +995,16 @@ function installCursor(bundleDir, vaultPath) {
913
995
  const wfCount = installWorkflows(bundleDir, cmdsDir);
914
996
  if (wfCount > 0) steps.push(`${wfCount} commands`);
915
997
 
916
- const skillsDir = path.join(home, ".cursor", "skills");
917
- const skCount = installSkillPacks(bundleDir, skillsDir);
918
- if (skCount > 0) steps.push(`${skCount} skills`);
998
+ if (skillOpts && skillOpts.install) {
999
+ const skillsDir = path.join(home, ".cursor", "skills");
1000
+ const skCount = installSkillPacks(bundleDir, skillsDir, skillOpts.categories);
1001
+ if (skCount > 0) steps.push(`${skCount} skills`);
1002
+ }
919
1003
 
920
1004
  return steps;
921
1005
  }
922
1006
 
923
- function installCline(bundleDir, vaultPath) {
1007
+ function installCline(bundleDir, vaultPath, skillOpts) {
924
1008
  const steps = [];
925
1009
 
926
1010
  if (vaultPath) {
@@ -932,39 +1016,62 @@ function installCline(bundleDir, vaultPath) {
932
1016
  steps.push("rules");
933
1017
  }
934
1018
 
935
- const skillsDir = path.join(vaultPath, ".cline", "skills");
936
- const skCount = installSkillPacks(bundleDir, skillsDir);
937
- if (skCount > 0) steps.push(`${skCount} skills`);
1019
+ if (skillOpts && skillOpts.install) {
1020
+ const skillsDir = path.join(vaultPath, ".cline", "skills");
1021
+ const skCount = installSkillPacks(bundleDir, skillsDir, skillOpts.categories);
1022
+ if (skCount > 0) steps.push(`${skCount} skills`);
1023
+ }
938
1024
  }
939
1025
 
940
1026
  return steps;
941
1027
  }
942
1028
 
943
- function installCodex(bundleDir, vaultPath) {
1029
+ function installCodexCli(bundleDir, vaultPath, skillOpts) {
944
1030
  const home = os.homedir();
945
1031
  const steps = [];
946
1032
 
947
- if (vaultPath) {
948
- fs.writeFileSync(path.join(vaultPath, "AGENTS.md"), generateAgentsMd(), "utf8");
949
- steps.push("AGENTS.md");
950
- }
951
-
952
1033
  const codexDir = path.join(home, ".codex");
953
1034
  fs.mkdirSync(codexDir, { recursive: true });
954
1035
  if (installRules(bundleDir, path.join(codexDir, "instructions.md"))) steps.push("global instructions");
955
1036
 
1037
+ if (skillOpts && skillOpts.install) {
1038
+ const skillsDir = path.join(codexDir, "skills");
1039
+ const skCount = installSkillPacks(bundleDir, skillsDir, skillOpts.categories);
1040
+ if (skCount > 0) steps.push(`${skCount} skills`);
1041
+ }
1042
+
1043
+ return steps;
1044
+ }
1045
+
1046
+ function installCodexCloud(bundleDir, vaultPath, skillOpts) {
1047
+ const steps = [];
1048
+
1049
+ if (vaultPath && installSkills) {
1050
+ const skillsDir = path.join(vaultPath, ".agents", "skills");
1051
+ const skCount = installSkillPacks(bundleDir, skillsDir, skillOpts.categories);
1052
+ if (skCount > 0) steps.push(`${skCount} skills`);
1053
+ }
1054
+
956
1055
  return steps;
957
1056
  }
958
1057
 
959
- function installWindsurf(bundleDir, vaultPath) {
1058
+ function installWindsurf(bundleDir, vaultPath, skillOpts) {
1059
+ const home = os.homedir();
960
1060
  const steps = [];
961
1061
  if (vaultPath) {
962
1062
  if (installRules(bundleDir, path.join(vaultPath, ".windsurfrules"))) steps.push("rules");
963
1063
  }
1064
+
1065
+ if (skillOpts && skillOpts.install) {
1066
+ const skillsDir = path.join(home, ".windsurf", "skills");
1067
+ const skCount = installSkillPacks(bundleDir, skillsDir, skillOpts.categories);
1068
+ if (skCount > 0) steps.push(`${skCount} skills`);
1069
+ }
1070
+
964
1071
  return steps;
965
1072
  }
966
1073
 
967
- function installOpenClaw(bundleDir, vaultPath) {
1074
+ function installOpenClaw(bundleDir, vaultPath, skillOpts) {
968
1075
  const home = os.homedir();
969
1076
  const workspace = path.join(home, ".openclaw", "workspace");
970
1077
  const steps = [];
@@ -988,42 +1095,64 @@ function installOpenClaw(bundleDir, vaultPath) {
988
1095
  steps.push("USER.md");
989
1096
  }
990
1097
 
991
- const skCount = installSkillPacks(bundleDir, path.join(workspace, "skills"));
992
- if (skCount > 0) steps.push(`${skCount} skills`);
1098
+ if (skillOpts && skillOpts.install) {
1099
+ const skCount = installSkillPacks(bundleDir, path.join(workspace, "skills"), skillOpts.categories);
1100
+ if (skCount > 0) steps.push(`${skCount} skills`);
1101
+ }
993
1102
 
994
1103
  return steps;
995
1104
  }
996
1105
 
997
- function installGeminiCli(bundleDir) {
1106
+ function installGeminiCli(bundleDir, vaultPath, skillOpts, writtenFiles) {
998
1107
  const home = os.homedir();
999
1108
  const steps = [];
1000
1109
 
1001
1110
  const geminiDir = path.join(home, ".gemini");
1002
1111
  fs.mkdirSync(geminiDir, { recursive: true });
1003
- if (installRules(bundleDir, path.join(geminiDir, "GEMINI.md"))) steps.push("rules");
1112
+ const geminiMdPath = path.join(geminiDir, "GEMINI.md");
1113
+ if (!writtenFiles.has(geminiMdPath)) {
1114
+ if (installRules(bundleDir, geminiMdPath)) steps.push("rules");
1115
+ writtenFiles.add(geminiMdPath);
1116
+ } else {
1117
+ steps.push("rules (shared)");
1118
+ }
1004
1119
 
1005
- const skCount = installSkillPacks(bundleDir, path.join(geminiDir, "skills"));
1006
- if (skCount > 0) steps.push(`${skCount} skills`);
1120
+ if (skillOpts && skillOpts.install) {
1121
+ const skCount = installSkillPacks(bundleDir, path.join(geminiDir, "skills"), skillOpts.categories);
1122
+ if (skCount > 0) steps.push(`${skCount} skills`);
1123
+ }
1007
1124
 
1008
1125
  return steps;
1009
1126
  }
1010
1127
 
1011
- function installAntigravity(bundleDir) {
1128
+ function installAntigravity(bundleDir, vaultPath, skillOpts, writtenFiles) {
1012
1129
  const home = os.homedir();
1013
1130
  const steps = [];
1014
1131
 
1015
1132
  const geminiDir = path.join(home, ".gemini");
1016
1133
  fs.mkdirSync(geminiDir, { recursive: true });
1017
- if (installRules(bundleDir, path.join(geminiDir, "GEMINI.md"))) steps.push("rules");
1134
+ const geminiMdPath = path.join(geminiDir, "GEMINI.md");
1135
+ if (!writtenFiles.has(geminiMdPath)) {
1136
+ if (installRules(bundleDir, geminiMdPath)) steps.push("rules");
1137
+ writtenFiles.add(geminiMdPath);
1138
+ } else {
1139
+ steps.push("rules (shared)");
1140
+ }
1018
1141
 
1019
1142
  const wfDir = path.join(geminiDir, "antigravity", "global_workflows");
1020
1143
  const wfCount = installWorkflows(bundleDir, wfDir);
1021
1144
  if (wfCount > 0) steps.push(`${wfCount} workflows`);
1022
1145
 
1146
+ if (skillOpts && skillOpts.install) {
1147
+ const skillsDir = path.join(geminiDir, "antigravity", "skills");
1148
+ const skCount = installSkillPacks(bundleDir, skillsDir, skillOpts.categories);
1149
+ if (skCount > 0) steps.push(`${skCount} skills`);
1150
+ }
1151
+
1023
1152
  return steps;
1024
1153
  }
1025
1154
 
1026
- function installRooCode(bundleDir, vaultPath) {
1155
+ function installRooCode(bundleDir, vaultPath, skillOpts) {
1027
1156
  const steps = [];
1028
1157
  if (vaultPath) {
1029
1158
  const rulesDir = path.join(vaultPath, ".roo", "rules");
@@ -1033,11 +1162,17 @@ function installRooCode(bundleDir, vaultPath) {
1033
1162
  fs.copyFileSync(src, path.join(rulesDir, "mover-os.md"));
1034
1163
  steps.push("rules");
1035
1164
  }
1165
+
1166
+ if (skillOpts && skillOpts.install) {
1167
+ const skillsDir = path.join(vaultPath, ".roo", "skills");
1168
+ const skCount = installSkillPacks(bundleDir, skillsDir, skillOpts.categories);
1169
+ if (skCount > 0) steps.push(`${skCount} skills`);
1170
+ }
1036
1171
  }
1037
1172
  return steps;
1038
1173
  }
1039
1174
 
1040
- function installCopilot(bundleDir, vaultPath) {
1175
+ function installCopilot(bundleDir, vaultPath, skillOpts) {
1041
1176
  const steps = [];
1042
1177
  if (vaultPath) {
1043
1178
  const ghDir = path.join(vaultPath, ".github");
@@ -1047,21 +1182,31 @@ function installCopilot(bundleDir, vaultPath) {
1047
1182
  fs.copyFileSync(src, path.join(ghDir, "copilot-instructions.md"));
1048
1183
  steps.push("rules");
1049
1184
  }
1185
+
1186
+ if (skillOpts && skillOpts.install) {
1187
+ const skillsDir = path.join(ghDir, "skills");
1188
+ const skCount = installSkillPacks(bundleDir, skillsDir, skillOpts.categories);
1189
+ if (skCount > 0) steps.push(`${skCount} skills`);
1190
+ }
1050
1191
  }
1051
1192
  return steps;
1052
1193
  }
1053
1194
 
1054
- function installAmp(bundleDir, vaultPath) {
1195
+ function installAmp(bundleDir, vaultPath, skillOpts) {
1055
1196
  const steps = [];
1056
1197
  if (vaultPath) {
1057
- fs.writeFileSync(path.join(vaultPath, "AGENTS.md"), generateAgentsMd(), "utf8");
1058
- steps.push("AGENTS.md");
1059
1198
  if (installRules(bundleDir, path.join(vaultPath, "AMP.md"))) steps.push("AMP.md");
1199
+
1200
+ if (skillOpts && skillOpts.install) {
1201
+ const skillsDir = path.join(vaultPath, ".agents", "skills");
1202
+ const skCount = installSkillPacks(bundleDir, skillsDir, skillOpts.categories);
1203
+ if (skCount > 0) steps.push(`${skCount} skills`);
1204
+ }
1060
1205
  }
1061
1206
  return steps;
1062
1207
  }
1063
1208
 
1064
- function installAider(bundleDir, vaultPath) {
1209
+ function installAider(bundleDir, vaultPath, skillOpts) {
1065
1210
  const steps = [];
1066
1211
  if (vaultPath) {
1067
1212
  const agentsMdPath = path.join(vaultPath, "AGENTS.md");
@@ -1083,7 +1228,8 @@ const AGENT_INSTALLERS = {
1083
1228
  "claude-code": installClaudeCode,
1084
1229
  cursor: installCursor,
1085
1230
  cline: installCline,
1086
- codex: installCodex,
1231
+ "codex-cli": installCodexCli,
1232
+ "codex-cloud": installCodexCloud,
1087
1233
  windsurf: installWindsurf,
1088
1234
  openclaw: installOpenClaw,
1089
1235
  "gemini-cli": installGeminiCli,
@@ -1298,19 +1444,39 @@ async function main() {
1298
1444
  // ── Skills ──
1299
1445
  const allSkills = findSkills(bundleDir);
1300
1446
  let installSkills = false;
1447
+ let selectedCategories = null; // null = all, Set = filtered
1301
1448
 
1302
1449
  if (allSkills.length > 0 && selectedAgents.some((a) => ["Full", "Enhanced"].includes(a.tier))) {
1303
- question(`Install ${bold(String(allSkills.length))} skill packs? ${dim("code review, marketing, security...")}`);
1450
+ // Count skills per category
1451
+ const catCounts = {};
1452
+ for (const sk of allSkills) {
1453
+ catCounts[sk.category] = (catCounts[sk.category] || 0) + 1;
1454
+ }
1455
+
1456
+ question(`${bold(String(allSkills.length))} skill packs available. Select categories:`);
1304
1457
  barLn();
1305
1458
 
1306
- const skillChoice = await interactiveSelect(
1307
- [
1308
- { id: "yes", name: "Yes" },
1309
- { id: "no", name: "No" },
1310
- ],
1311
- { multi: false, defaultIndex: 0 }
1312
- );
1313
- installSkills = skillChoice === "yes";
1459
+ const categoryItems = CATEGORY_META.map((c) => ({
1460
+ id: c.id,
1461
+ name: `${c.name} ${dim(`(${catCounts[c.id] || 0})`)}`,
1462
+ tier: dim(c.desc),
1463
+ }));
1464
+
1465
+ // Pre-select Development + Obsidian (core categories everyone needs)
1466
+ const preSelected = ["development", "obsidian"];
1467
+
1468
+ const selectedCatIds = await interactiveSelect(categoryItems, {
1469
+ multi: true,
1470
+ preSelected,
1471
+ });
1472
+
1473
+ installSkills = selectedCatIds.length > 0;
1474
+ if (skillOpts && skillOpts.install) {
1475
+ selectedCategories = new Set(selectedCatIds);
1476
+ // Count how many skills will be installed (selected categories + tools)
1477
+ const skillCount = allSkills.filter((s) => s.category === "tools" || selectedCategories.has(s.category)).length;
1478
+ barLn(dim(`${skillCount} skills selected`));
1479
+ }
1314
1480
  }
1315
1481
 
1316
1482
  // ── Install with animated spinners ──
@@ -1369,11 +1535,16 @@ async function main() {
1369
1535
  }
1370
1536
 
1371
1537
  // 4. Per-agent installation
1538
+ const writtenFiles = new Set(); // Track shared files to avoid double-writes (e.g. GEMINI.md)
1539
+ const skillOpts = { install: installSkills, categories: selectedCategories };
1372
1540
  for (const agent of selectedAgents) {
1373
1541
  const fn = AGENT_INSTALLERS[agent.id];
1374
1542
  if (!fn) continue;
1375
1543
  sp = spinner(agent.name);
1376
- const steps = (agent.id === "antigravity" || agent.id === "gemini-cli") ? fn(bundleDir) : fn(bundleDir, vaultPath);
1544
+ const usesWrittenFiles = agent.id === "antigravity" || agent.id === "gemini-cli";
1545
+ const steps = usesWrittenFiles
1546
+ ? fn(bundleDir, vaultPath, skillOpts, writtenFiles)
1547
+ : fn(bundleDir, vaultPath, skillOpts);
1377
1548
  await sleep(250);
1378
1549
  if (steps.length > 0) {
1379
1550
  sp.stop(`${agent.name} ${dim(steps.join(", "))}`);
@@ -1384,8 +1555,8 @@ async function main() {
1384
1555
  }
1385
1556
  }
1386
1557
 
1387
- // 5. AGENTS.md — only for agents that need it
1388
- const needsAgentsMd = selectedAgents.some((a) => ["codex", "amp", "aider", "openclaw"].includes(a.id));
1558
+ // 5. AGENTS.md — only for agents that need it (consolidated write)
1559
+ const needsAgentsMd = selectedAgents.some((a) => ["codex-cli", "codex-cloud", "amp", "aider"].includes(a.id));
1389
1560
  if (needsAgentsMd) {
1390
1561
  fs.writeFileSync(path.join(vaultPath, "AGENTS.md"), generateAgentsMd(), "utf8");
1391
1562
  sp = spinner("AGENTS.md");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mover-os",
3
- "version": "4.0.8",
3
+ "version": "4.0.10",
4
4
  "description": "The self-improving OS for AI agents. Turns Obsidian into an execution engine.",
5
5
  "bin": {
6
6
  "mover-os": "install.js"
@@ -65,6 +65,10 @@ Break down the task blocks here
65
65
 
66
66
  - 09:00 -
67
67
 
68
+ **Food:**
69
+
70
+ **Sleep:** Total: | Deep:
71
+
68
72
 
69
73
  ---
70
74
 
@@ -27,6 +27,8 @@ LOAD (Memory Hierarchy):
27
27
  4. Identity_Prime.md (P3)
28
28
  5. Mover_Dossier.md (P3)
29
29
  6. Last 3 Daily Notes (P5) — yesterday + 2 days before, needed for multi-day pattern detection. Delegate reading to subagents (model: haiku) to keep main context clean. Extract: task completion rates, energy patterns, carry-over tasks, session log signals.
30
+ 7. Active project's `project_state.md` (P4) — get project path from Active_Context `## 4. TECHNICAL CONTEXT`. Read current phase, blockers, last milestone. Proactive load, not reactive.
31
+ 8. Active_Context `## 5. RECENT MEMORIES` / `## 5. ACTIVE SESSIONS` — rolling session buffer for operational context on recent work.
30
32
 
31
33
  CONSTRAINTS:
32
34
  - All verdicts grounded in log data, not assumptions
@@ -65,7 +67,7 @@ Read these files and extract the map:
65
67
 
66
68
  **From Strategy.md:** Primary Metric, Hypothesis, Daily Volume Targets, Variables, Constants.
67
69
  **From Identity_Prime.md:** Core Identity, Anti-Identity triggers, Non-negotiables.
68
- **From Active_Context.md:** Current project, phase, blockers, energy.
70
+ **From Active_Context.md:** Current project, phase, blockers, energy. Also read `## 5. RECENT MEMORIES` / `## 5. ACTIVE SESSIONS` for operational context on what was worked on across recent sessions.
69
71
  **From Auto_Learnings.md:** Last 5 entries. Cross-reference with today's log.
70
72
  **From Daily Note:** Full content, especially Session Log and task list.
71
73
 
@@ -92,6 +94,20 @@ If yes: flag as RECURRING. If new pattern: flag as NEW.
92
94
 
93
95
  Perform these checks. Do not output this monologue directly.
94
96
 
97
+ ### 4A.pre Critical Path Check
98
+
99
+ Before scoring strategy alignment, determine whether today's work is on the critical path. Uses project_state.md (loaded in Pre-Flight item 7) + sessions buffer (item 8).
100
+
101
+ 1. **What is the stated Single Test?** Read from today's Daily Note `## Focus` section.
102
+ 2. **What are its prerequisites?** Using project_state.md current phase, plan.md task dependencies, and Active_Context Technical Context, identify what must be done before the Single Test goal can be achieved.
103
+ 3. **Is today's work a direct prerequisite?** Classify today's actual work:
104
+ - `[DIRECT]` — working on the Single Test itself
105
+ - `[PREREQUISITE]` — working on something that unblocks the Single Test (strategic, not drift)
106
+ - `[DRIFT]` — unrelated work that doesn't advance the critical path
107
+ 4. **Low confidence guard:** If Confidence < 3 on prerequisite status, label as `[INFERRED]` and don't assert drift. "This appears to be prerequisite work, but I'm not certain of the dependency chain."
108
+
109
+ Output: `Critical Path: [DIRECT|PREREQUISITE|DRIFT]` — this verdict feeds into 4A and 4E below.
110
+
95
111
  ### 4A. Strategy Audit
96
112
  Compare Daily Log inputs VS Strategy.md Targets.
97
113
  - Volume low? -> "Execution Failure" (Discipline issue).
@@ -135,6 +151,7 @@ Compare how the user spent their time vs what Strategy.md says the bottleneck is
135
151
  - If user spent time building/planning when the bottleneck is execution: call it out directly.
136
152
  - Be careful not to hallucinate — only flag if you have clear evidence from the Session Log and task list.
137
153
  - Confidence labeling required: this is inference, not fact.
154
+ - **Use Critical Path verdict from 4A.pre:** If today's work is `[DIRECT]` or `[PREREQUISITE]`, it IS strategic even if it doesn't directly touch the Primary Metric. Only `[DRIFT]` work gets the normal leverage comparison. Prerequisite work that unblocks the Single Test is high-leverage by definition.
138
155
 
139
156
  **Leverage Check (Naval Framework):**
140
157
  Classify today's work on this axis — be honest, not generous:
@@ -27,6 +27,12 @@ git rev-parse --show-toplevel
27
27
  ```
28
28
  Save result as VAULT_ROOT. ALL Engine file paths below are relative to this root, NOT to the current working directory.
29
29
 
30
+ WORKING DIRECTORY (capture project context):
31
+ ```bash
32
+ pwd
33
+ ```
34
+ Save as WORKING_DIR. Extract project name: if inside `01_Projects/[Name]/`, capture `[Name]`. Otherwise use the directory basename.
35
+
30
36
  DAILY NOTE PATH (derive from SESSION_END_TIME):
31
37
  ```
32
38
  {VAULT_ROOT}/02_Areas/Engine/Dailies/YYYY-MM/Daily - YYYY-MM-DD.md
@@ -81,7 +87,10 @@ Before reviewing history, determine the session type:
81
87
  - AUTONOMOUS sessions: mark ALL timestamps as `[AUTO]` and add note: "Agent-driven session. User may not have been present."
82
88
  - SEMI-AUTONOMOUS: mark agent-only work timestamps with `[AUTO]`, user-present segments with normal timestamps
83
89
 
84
- Tag the session log section: `### Session Log [ATTENDED]` or `### Session Log [AUTONOMOUS]` or `### Session Log [SEMI-AUTO]`
90
+ Tag the session log section: `### Session Log [ATTENDED] — HH:MM-HH:MM [Platform] [Project]` or `### Session Log [AUTONOMOUS]` or `### Session Log [SEMI-AUTO]`
91
+
92
+ Include WORKING_DIR project name in the session header. If the session spans multiple projects, note the primary one.
93
+ Example: `### Session Log [ATTENDED] — 14:00-15:30 [Claude Code] [Mover OS Bundle]`
85
94
 
86
95
  ---
87
96
 
@@ -61,6 +61,21 @@ If Active_Context is stale (>3 days): "Your context is [X] days old. Consider ru
61
61
 
62
62
  ---
63
63
 
64
+ ## 2.3 MONTHLY REVIEW CHECK
65
+
66
+ Read `monthly_review_last_run` from Active_Context.md Workflow State.
67
+
68
+ Quick date check (no subagent — pure math):
69
+ - Is today within the **last 3 days of the month**?
70
+ - Has `monthly_review_last_run` already fired this month?
71
+
72
+ If last 3 days of month AND monthly review hasn't run this month:
73
+ - "Monthly review hasn't run yet this month and the month ends in [X] days. Run `/review-week` before the month closes — it triggers monthly mode automatically on the last review-day."
74
+
75
+ Otherwise: skip silently. No output.
76
+
77
+ ---
78
+
64
79
  ## 2.5 PROJECT PORTFOLIO (Quick Health Scan)
65
80
 
66
81
  Scan `{VAULT_ROOT}/01_Projects/` for all project folders. For each, check:
@@ -26,6 +26,8 @@ LOAD (Memory Hierarchy):
26
26
  5. Mover_Dossier.md (P3)
27
27
  6. Goals.md (if exists)
28
28
  7. Last 3-5 Daily Notes (P5)
29
+ 8. Active project's `project_state.md` (P4) — get project path from Active_Context `## 4. TECHNICAL CONTEXT`. Read current phase, blockers, last milestone from Solutions Ledger and Changelog. Skip if no active project.
30
+ 9. Active_Context `## 5. RECENT MEMORIES` / `## 5. ACTIVE SESSIONS` — rolling session buffer for operational awareness of recent work across sessions.
29
31
 
30
32
  CONSTRAINTS:
31
33
  - All task selections grounded in Strategy.md or Identity_Prime.md
@@ -55,6 +57,15 @@ Is it after **6pm** AND `/analyse-day` has NOT been run today?
55
57
 
56
58
  If template missing: BLOCK. "Daily_Template.md not found. Create it or run `/setup`."
57
59
 
60
+ ### 1D. Monthly Review Check
61
+ Read `monthly_review_last_run` from Active_Context.md Workflow State.
62
+ - Is tomorrow within the **last 3 days of the month**?
63
+ - Has `monthly_review_last_run` already fired this month?
64
+
65
+ If last 3 days AND monthly hasn't run: SUGGEST (don't block). "Monthly review hasn't run yet and the month ends soon. Consider running `/review-week` before month-end — it auto-triggers monthly mode on the last review-day."
66
+
67
+ Otherwise: skip silently.
68
+
58
69
  ---
59
70
 
60
71
  ## 2. RESILIENCE CHECK
@@ -123,11 +134,16 @@ If a project is mentioned:
123
134
  ## 4. STRATEGIC LOGIC
124
135
 
125
136
  ### 4A. Zombie Task Audit
137
+
138
+ **Cardinal rule: The AI NEVER removes, kills, or drops a zombie task without explicit user confirmation. The task stays in the plan until the user decides. Surface the problem, don't solve it unilaterally.**
139
+
126
140
  Is there a task carried over > 2 times?
127
- - If yes: Flag it. "ZOMBIE TASK (x[N]): [Task]. This has been on your list for [N] days. That means you either don't want to do it, don't know how to do it, or it's not important enough. Which one?"
128
- - If x3+: ESCALATE. "This has been carried [X] times. Copying it forward again is not a plan. Three options: break it into a 15-minute first step, delegate it, or kill it. Carrying it forward is NOT an option."
129
- - If x5+: HARD BLOCK. "This task has been on your list for [X] days. It's dead weight. I'm removing it from tomorrow's plan unless you can tell me exactly when and how you'll do it."
130
- - Do NOT let the user say "I'll get to it tomorrow" without a specific time block and first step.
141
+
142
+ - **x2:** Flag it. "ZOMBIE TASK (x2): [Task]. This has been on your list for 2 days. Three possible reasons: you don't want to do it, you don't know how to start, or it's not actually important. Which one?" **WAIT for the user's answer before proceeding.**
143
+ - **x3-x4:** ESCALATE. "ZOMBIE (x[N]): [Task]. Carried [N] times. Three options: (1) Break it into a 15-minute first step, (2) Delegate it, (3) Kill it. Which one?" **WAIT for the user's choice. Do NOT auto-select. Task stays in plan until user decides.**
144
+ - **x5+:** CRITICAL ZOMBIE. "CRITICAL ZOMBIE (x[N]): [Task] has been on your list for [N] days. Something is blocking this. What is it?" **WAIT for the user's response. Task remains in the plan until the user explicitly says to remove it. Never pre-emptively remove.**
145
+
146
+ Do NOT let the user say "I'll get to it tomorrow" without a specific time block and first step.
131
147
 
132
148
  ### 4B. Dependency Awareness
133
149
  For each task, classify:
@@ -144,11 +160,17 @@ Cite: [Identity_Prime.md] for identity alignment checks.
144
160
 
145
161
  If a task has no carry marker, treat it as `(x1)` and write `(x2)`. If a task already has `(xN)`, increment to `(x(N+1))`. Never remove the carry marker.
146
162
 
147
- ### 4D. The Single Test
148
- From Strategy.md Primary Metric: What ONE task directly impacts it?
149
- - Default: The Single Test MUST impact the primary metric.
150
- - Overwhelm Exception: If overwhelm detected, Single Test = a "Simplification Task."
151
- - If Strategy has multiple metrics: track all, but prioritize primary.
163
+ ### 4D. The Single Test (Dependency-Aware)
164
+
165
+ 1. **Identify the goal:** Read Strategy.md Primary Metric. What outcome are we driving toward?
166
+ 2. **Prerequisite scan:** Using project_state.md (loaded in Pre-Flight item 8) + Active_Context Technical Context + recent session buffer, identify the prerequisites for that goal. Which are done? Which aren't?
167
+ 3. **Dependency reasoning:**
168
+ - If ALL prerequisites are complete: Single Test = the goal itself (direct metric impact).
169
+ - If prerequisites are INCOMPLETE: Single Test = the next incomplete prerequisite, NOT the goal. The goal can't be attacked until its dependencies are cleared.
170
+ - Example: Goal = "purchase path live". Prerequisites = [landing page (incomplete), payment provider (not started)]. Single Test = "finish landing page", not "add payment link".
171
+ 4. **Overwhelm Exception:** If overwhelm detected (from Section 2), Single Test = a "Simplification Task" regardless of dependency state.
172
+ 5. **Multiple metrics:** If Strategy has multiple metrics, track all but prioritize primary. Apply prerequisite scan to each.
173
+ 6. **Low confidence:** If prerequisite status is unclear (Confidence < 3), state what you see and ask: "Is [X] a prerequisite for [goal]? I want to get the Single Test right."
152
174
 
153
175
  ### 4E. Review Day Special
154
176
  Is the plan for the user's configured review day (from `review_week_day` in Active_Context.md, default: Sunday)?
@@ -369,6 +369,7 @@ Always runs — Active_Context is always stale after a week.
369
369
  5. Section 4 (Technical Context): if active project changed, update project name, path, and tech stack
370
370
  6. Section 5 (Active Sessions): verify buffer is current — trim to last 5 entries
371
371
  7. Write workflow state: `weekly_review_last_run: [YYYY-MM-DD]`
372
+ 8. If MONTHLY_MODE was true: also write `monthly_review_last_run: [YYYY-MM-DD]` to Workflow State
372
373
 
373
374
  "Proposed Active_Context.md changes:
374
375
  [DIFF FORMAT — only the lines that change, not the full file]
@@ -75,10 +75,11 @@ This is not the interview. This is context-loading. Don't ask questions yet. Mov
75
75
  Copy `Someday_Maybe.md` template to `02_Areas/Engine/Someday_Maybe.md` if it doesn't exist.
76
76
  2. **Re-Setup Protection:** Check if core Engine files already exist (Identity_Prime.md, Strategy.md, Mover_Dossier.md).
77
77
  - If ANY exist: "Existing Engine files detected: [list]. Options:"
78
- - **(A) Fresh Start:** Archive existing to `04_Archives/Engine_Backup_YYYY-MM-DD/` and start clean.
79
- - **(B) Update Mode:** Interview to fill gaps in existing files. Skip banks already covered.
80
- - **(C) Cancel:** Exit setup.
78
+ - **(A) Update Mode:** Keep existing files. Interview to fill any gaps in existing files. Skip banks already covered. (RECOMMENDED — safe default)
79
+ - **(B) Cancel:** Exit setup.
80
+ - **(C) Fresh Start:** Archive existing to `04_Archives/Engine_Backup_YYYY-MM-DD/` and start clean. (DESTRUCTIVE)
81
81
  - WAIT FOR USER CHOICE. Do not overwrite without explicit consent.
82
+ - **If user selects (C) Fresh Start:** "This will ARCHIVE your existing Engine files (Identity, Strategy, Dossier, Goals) to `04_Archives/Engine_Backup_YYYY-MM-DD/` and start from scratch. Type 'ARCHIVE' to confirm." WAIT for user to type 'ARCHIVE'. If they type anything else, return to option selection.
82
83
  3. **Welcome:**
83
84
  "Welcome to Mover OS. I'm The System — I learn how you work and hold you accountable to your own goals.
84
85
  To set this up properly, I need to understand you — not just what you do, but how you think. The more honest you are, the better this works."