diff --git a/src/Commands/InstallCommand.php b/src/Commands/InstallCommand.php
new file mode 100644
index 0000000..a1c114b
--- /dev/null
+++ b/src/Commands/InstallCommand.php
@@ -0,0 +1,41 @@
+call('vendor:publish', ['--tag' => 'cart-config', '--ansi' => true]);
+
+ static::scaffoldDirectories(app_path('Cart'));
+
+ $this->info('Cart installed successfully.');
+ $this->newLine();
+ $this->line(' Next steps:');
+ $this->line(' 1. Review config/cart.php and set your preferred storage driver.');
+ $this->line(' 2. Run php artisan cart:make:coupon MyCoupon to create your first coupon.');
+ $this->line(' 3. Run php artisan cart:make:tax MyTax to add a tax rule.');
+ $this->line(' 4. Run php artisan cart:make:shipping MyShipping to add a shipping rate.');
+
+ return self::SUCCESS;
+ }
+
+ public static function scaffoldDirectories(string $base): void
+ {
+ foreach (['Coupons', 'Tax', 'Shipping', 'Drivers'] as $subdir) {
+ $path = "{$base}/{$subdir}";
+ if (! is_dir($path)) {
+ mkdir($path, 0755, true);
+ }
+ }
+ }
+}
diff --git a/tests/Unit/Commands/InstallCommandTest.php b/tests/Unit/Commands/InstallCommandTest.php
new file mode 100644
index 0000000..c9887c3
--- /dev/null
+++ b/tests/Unit/Commands/InstallCommandTest.php
@@ -0,0 +1,33 @@
+toBeTrue();
+ expect(is_dir("{$base}/Tax"))->toBeTrue();
+ expect(is_dir("{$base}/Shipping"))->toBeTrue();
+ expect(is_dir("{$base}/Drivers"))->toBeTrue();
+
+ foreach (["{$base}/Coupons", "{$base}/Tax", "{$base}/Shipping", "{$base}/Drivers", $base] as $dir) {
+ @rmdir($dir);
+ }
+ });
+
+ test('scaffoldDirectories() is idempotent - does not throw if dirs already exist', function () {
+ $base = sys_get_temp_dir() . '/cart-install-idem-' . uniqid();
+
+ InstallCommand::scaffoldDirectories($base);
+ InstallCommand::scaffoldDirectories($base);
+
+ expect(is_dir("{$base}/Coupons"))->toBeTrue();
+
+ foreach (["{$base}/Coupons", "{$base}/Tax", "{$base}/Shipping", "{$base}/Drivers", $base] as $dir) {
+ @rmdir($dir);
+ }
+ });
+});