@minecraft-docker/mcctl 2.15.3 → 2.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +8 -9
  3. package/dist/commands/config-snapshot/create.d.ts +11 -0
  4. package/dist/commands/config-snapshot/create.d.ts.map +1 -0
  5. package/dist/commands/config-snapshot/create.js +39 -0
  6. package/dist/commands/config-snapshot/create.js.map +1 -0
  7. package/dist/commands/config-snapshot/delete.d.ts +10 -0
  8. package/dist/commands/config-snapshot/delete.d.ts.map +1 -0
  9. package/dist/commands/config-snapshot/delete.js +43 -0
  10. package/dist/commands/config-snapshot/delete.js.map +1 -0
  11. package/dist/commands/config-snapshot/diff.d.ts +14 -0
  12. package/dist/commands/config-snapshot/diff.d.ts.map +1 -0
  13. package/dist/commands/config-snapshot/diff.js +157 -0
  14. package/dist/commands/config-snapshot/diff.js.map +1 -0
  15. package/dist/commands/config-snapshot/index.d.ts +8 -0
  16. package/dist/commands/config-snapshot/index.d.ts.map +1 -0
  17. package/dist/commands/config-snapshot/index.js +9 -0
  18. package/dist/commands/config-snapshot/index.js.map +1 -0
  19. package/dist/commands/config-snapshot/list.d.ts +12 -0
  20. package/dist/commands/config-snapshot/list.d.ts.map +1 -0
  21. package/dist/commands/config-snapshot/list.js +55 -0
  22. package/dist/commands/config-snapshot/list.js.map +1 -0
  23. package/dist/commands/config-snapshot/restore.d.ts +11 -0
  24. package/dist/commands/config-snapshot/restore.d.ts.map +1 -0
  25. package/dist/commands/config-snapshot/restore.js +55 -0
  26. package/dist/commands/config-snapshot/restore.js.map +1 -0
  27. package/dist/commands/config-snapshot/schedule/add.d.ts +13 -0
  28. package/dist/commands/config-snapshot/schedule/add.d.ts.map +1 -0
  29. package/dist/commands/config-snapshot/schedule/add.js +46 -0
  30. package/dist/commands/config-snapshot/schedule/add.js.map +1 -0
  31. package/dist/commands/config-snapshot/schedule/index.d.ts +5 -0
  32. package/dist/commands/config-snapshot/schedule/index.d.ts.map +1 -0
  33. package/dist/commands/config-snapshot/schedule/index.js +5 -0
  34. package/dist/commands/config-snapshot/schedule/index.js.map +1 -0
  35. package/dist/commands/config-snapshot/schedule/list.d.ts +10 -0
  36. package/dist/commands/config-snapshot/schedule/list.d.ts.map +1 -0
  37. package/dist/commands/config-snapshot/schedule/list.js +57 -0
  38. package/dist/commands/config-snapshot/schedule/list.js.map +1 -0
  39. package/dist/commands/config-snapshot/schedule/remove.d.ts +10 -0
  40. package/dist/commands/config-snapshot/schedule/remove.d.ts.map +1 -0
  41. package/dist/commands/config-snapshot/schedule/remove.js +38 -0
  42. package/dist/commands/config-snapshot/schedule/remove.js.map +1 -0
  43. package/dist/commands/config-snapshot/schedule/toggle.d.ts +10 -0
  44. package/dist/commands/config-snapshot/schedule/toggle.d.ts.map +1 -0
  45. package/dist/commands/config-snapshot/schedule/toggle.js +34 -0
  46. package/dist/commands/config-snapshot/schedule/toggle.js.map +1 -0
  47. package/dist/commands/config-snapshot/show.d.ts +11 -0
  48. package/dist/commands/config-snapshot/show.d.ts.map +1 -0
  49. package/dist/commands/config-snapshot/show.js +53 -0
  50. package/dist/commands/config-snapshot/show.js.map +1 -0
  51. package/dist/commands/index.d.ts +1 -0
  52. package/dist/commands/index.d.ts.map +1 -1
  53. package/dist/commands/index.js +2 -0
  54. package/dist/commands/index.js.map +1 -1
  55. package/dist/index.js +145 -2
  56. package/dist/index.js.map +1 -1
  57. package/dist/infrastructure/di/container.d.ts +7 -1
  58. package/dist/infrastructure/di/container.d.ts.map +1 -1
  59. package/dist/infrastructure/di/container.js +30 -2
  60. package/dist/infrastructure/di/container.js.map +1 -1
  61. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -5,6 +5,32 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.16.0] - 2026-02-23
9
+
10
+ ### Added
11
+ - **Config Snapshot** - Full-stack configuration snapshot system for server config versioning (#397~#406, #414~#424)
12
+ - **Domain Layer**: `ConfigSnapshot`, `ConfigSnapshotSchedule` entities with `SnapshotId`, `SnapshotType`, `SnapshotStatus` value objects (#397, #414)
13
+ - **Infrastructure**: `SqliteConfigSnapshotRepository` adapter with SQLite persistence (#398)
14
+ - **API**: RESTful Config Snapshot endpoints - CRUD, diff, restore, schedule management (#399, #400, #416)
15
+ - `ConfigSnapshotSchedulerService` with `node-cron` integration for automated snapshots (#405)
16
+ - Audit logging for all snapshot mutations
17
+ - **CLI**: `mcctl config-snapshot` commands for snapshot management (#401)
18
+ - **Console**: Config Snapshots tab on Backup page with full UI (#402)
19
+ - Config History tab on Server Detail page (#403)
20
+ - ConfigDiff viewer and ConfigRestore dialog components (#404)
21
+ - BFF proxy routes, React Query hooks, and TypeScript types
22
+ - **E2E Tests**: Config Snapshot E2E test fixtures and test files (#406)
23
+
24
+ - **Backup Retention Policy Pruning** - Implement `applyRetentionPolicy()` for automated backup cleanup (#396, #426)
25
+ - Git history truncation logic for old backups
26
+ - Integration with backup scheduler for automatic pruning
27
+
28
+ ### Fixed
29
+ - **Backup Git Path** - Fix git repository path and prevent shell injection (#423, #425)
30
+ - Replace `exec()` with `execFile()` to prevent shell injection vulnerabilities
31
+ - Correct git repository path resolution in backup routes
32
+ - Added test coverage for backup routes
33
+
8
34
  ## [2.15.3] - 2026-02-22
9
35
 
10
36
  ### Changed
package/README.md CHANGED
@@ -77,6 +77,14 @@ mcctl logs myserver
77
77
 
78
78
  ## Changelog
79
79
 
80
+ ### v2.16.0 (2026-02-23)
81
+ - **feat**: Config Snapshot system - full-stack server configuration versioning (#397~#406)
82
+ - Domain layer, infrastructure, API, CLI, Console UI, and E2E tests
83
+ - Automated snapshot scheduling with node-cron
84
+ - Config diff viewer and restore functionality
85
+ - **feat**: Backup retention policy pruning implementation (#396, #426)
86
+ - **fix**: Backup git path and shell injection prevention (#423, #425)
87
+
80
88
  ### v2.15.3 (2026-02-22)
81
89
  - **docs**: Update README.md with Management Console features and architecture (#412, #413)
82
90
 
@@ -98,15 +106,6 @@ mcctl logs myserver
98
106
  ### v2.14.0 (2026-02-21)
99
107
  - **feat(console)**: Enhanced installed mods display with rich card UI and batch API
100
108
 
101
- ### v2.13.0 (2026-02-21)
102
- - **feat(console)**: Improve Server Activity tab to match Audit Logs page UI (#391, #392)
103
-
104
- ### v2.12.1 (2026-02-20)
105
- - **docs**: Add server management guide (EN/KO) for start/stop operations
106
-
107
- ### v2.12.0 (2026-02-20)
108
- - **refactor(console)**: Convert file editors from Dialog to inline Card-based views (#389, #390)
109
-
110
109
  [Full Changelog](https://github.com/smallmiro/minecraft-server-manager/releases)
111
110
 
112
111
  ## AI Assistant
@@ -0,0 +1,11 @@
1
+ export interface ConfigSnapshotCreateOptions {
2
+ root?: string;
3
+ serverName?: string;
4
+ description?: string;
5
+ json?: boolean;
6
+ }
7
+ /**
8
+ * Create a new config snapshot for a server
9
+ */
10
+ export declare function configSnapshotCreateCommand(options: ConfigSnapshotCreateOptions): Promise<number>;
11
+ //# sourceMappingURL=create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/config-snapshot/create.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,2BAA2B;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,MAAM,CAAC,CAgDjB"}
@@ -0,0 +1,39 @@
1
+ import { log, colors } from '@minecraft-docker/shared';
2
+ import { getContainer } from '../../infrastructure/di/container.js';
3
+ /**
4
+ * Create a new config snapshot for a server
5
+ */
6
+ export async function configSnapshotCreateCommand(options) {
7
+ const container = getContainer(options.root);
8
+ const useCase = container.configSnapshotUseCase;
9
+ // Validate server name
10
+ if (!options.serverName) {
11
+ log.error('Server name is required. Usage: mcctl config-snapshot create <server>');
12
+ return 1;
13
+ }
14
+ try {
15
+ console.log('');
16
+ console.log(colors.dim(`Creating snapshot for server "${options.serverName}"...`));
17
+ const snapshot = await useCase.create(options.serverName, options.description);
18
+ if (options.json) {
19
+ console.log(JSON.stringify(snapshot.toJSON(), null, 2));
20
+ return 0;
21
+ }
22
+ console.log(colors.green('Snapshot created successfully!'));
23
+ console.log(` ID: ${colors.cyan(snapshot.id)}`);
24
+ console.log(` Server: ${colors.bold(snapshot.serverName.value)}`);
25
+ console.log(` Files: ${colors.yellow(String(snapshot.files.length))} files captured`);
26
+ console.log(` Time: ${colors.dim(snapshot.createdAt.toLocaleString())}`);
27
+ if (snapshot.description) {
28
+ console.log(` Note: ${colors.dim(snapshot.description)}`);
29
+ }
30
+ console.log('');
31
+ return 0;
32
+ }
33
+ catch (error) {
34
+ const message = error instanceof Error ? error.message : String(error);
35
+ log.error(`Failed to create snapshot: ${message}`);
36
+ return 1;
37
+ }
38
+ }
39
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/commands/config-snapshot/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AASpE;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,OAAoC;IAEpC,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,SAAS,CAAC,qBAAqB,CAAC;IAEhD,uBAAuB;IACvB,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QACxB,GAAG,CAAC,KAAK,CAAC,uEAAuE,CAAC,CAAC;QACnF,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CACT,MAAM,CAAC,GAAG,CACR,iCAAiC,OAAO,CAAC,UAAU,MAAM,CAC1D,CACF,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,MAAM,CACnC,OAAO,CAAC,UAAU,EAClB,OAAO,CAAC,WAAW,CACpB,CAAC;QAEF,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACxD,OAAO,CAAC,CAAC;QACX,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC,CAAC;QAC5D,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACnE,OAAO,CAAC,GAAG,CACT,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,iBAAiB,CAC3E,CAAC;QACF,OAAO,CAAC,GAAG,CACT,aAAa,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,CAAC,EAAE,CAC/D,CAAC;QACF,IAAI,QAAQ,CAAC,WAAW,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEhB,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,GAAG,CAAC,KAAK,CAAC,8BAA8B,OAAO,EAAE,CAAC,CAAC;QACnD,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
@@ -0,0 +1,10 @@
1
+ export interface ConfigSnapshotDeleteOptions {
2
+ root?: string;
3
+ id: string;
4
+ force?: boolean;
5
+ }
6
+ /**
7
+ * Delete a config snapshot
8
+ */
9
+ export declare function configSnapshotDeleteCommand(options: ConfigSnapshotDeleteOptions): Promise<number>;
10
+ //# sourceMappingURL=delete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/commands/config-snapshot/delete.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,2BAA2B;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,MAAM,CAAC,CA8CjB"}
@@ -0,0 +1,43 @@
1
+ import * as p from '@clack/prompts';
2
+ import { log, colors } from '@minecraft-docker/shared';
3
+ import { getContainer } from '../../infrastructure/di/container.js';
4
+ /**
5
+ * Delete a config snapshot
6
+ */
7
+ export async function configSnapshotDeleteCommand(options) {
8
+ if (!options.id) {
9
+ log.error('Snapshot ID is required. Usage: mcctl config-snapshot delete <id>');
10
+ return 1;
11
+ }
12
+ const container = getContainer(options.root);
13
+ const useCase = container.configSnapshotUseCase;
14
+ try {
15
+ const snapshot = await useCase.findById(options.id);
16
+ if (!snapshot) {
17
+ log.error(`Snapshot not found: ${options.id}`);
18
+ return 1;
19
+ }
20
+ // Confirmation prompt (unless --force)
21
+ if (!options.force) {
22
+ const confirmed = await p.confirm({
23
+ message: `Delete snapshot ${colors.cyan(snapshot.id.substring(0, 8))} for server "${colors.bold(snapshot.serverName.value)}" (${snapshot.files.length} files, created ${snapshot.createdAt.toLocaleDateString()})?`,
24
+ initialValue: false,
25
+ });
26
+ if (p.isCancel(confirmed) || !confirmed) {
27
+ console.log(colors.dim('\nDeletion cancelled.\n'));
28
+ return 0;
29
+ }
30
+ }
31
+ await useCase.delete(options.id);
32
+ console.log('');
33
+ console.log(colors.green(`Snapshot deleted: ${colors.bold(snapshot.id.substring(0, 8))}...`));
34
+ console.log('');
35
+ return 0;
36
+ }
37
+ catch (error) {
38
+ const message = error instanceof Error ? error.message : String(error);
39
+ log.error(`Failed to delete snapshot: ${message}`);
40
+ return 1;
41
+ }
42
+ }
43
+ //# sourceMappingURL=delete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.js","sourceRoot":"","sources":["../../../src/commands/config-snapshot/delete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAQpE;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,OAAoC;IAEpC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;QAChB,GAAG,CAAC,KAAK,CAAC,mEAAmE,CAAC,CAAC;QAC/E,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,SAAS,CAAC,qBAAqB,CAAC;IAEhD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAEpD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,GAAG,CAAC,KAAK,CAAC,uBAAuB,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;YAC/C,OAAO,CAAC,CAAC;QACX,CAAC;QAED,uCAAuC;QACvC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACnB,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,OAAO,CAAC;gBAChC,OAAO,EAAE,mBAAmB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,gBAAgB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,MAAM,mBAAmB,QAAQ,CAAC,SAAS,CAAC,kBAAkB,EAAE,IAAI;gBACnN,YAAY,EAAE,KAAK;aACpB,CAAC,CAAC;YAEH,IAAI,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACxC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC,CAAC;gBACnD,OAAO,CAAC,CAAC;YACX,CAAC;QACH,CAAC;QAED,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAEjC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CACT,MAAM,CAAC,KAAK,CACV,qBAAqB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CACnE,CACF,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEhB,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,GAAG,CAAC,KAAK,CAAC,8BAA8B,OAAO,EAAE,CAAC,CAAC;QACnD,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ export interface ConfigSnapshotDiffOptions {
2
+ root?: string;
3
+ id1: string;
4
+ id2: string;
5
+ unified?: boolean;
6
+ sideBySide?: boolean;
7
+ filesOnly?: boolean;
8
+ json?: boolean;
9
+ }
10
+ /**
11
+ * Display diff between two config snapshots
12
+ */
13
+ export declare function configSnapshotDiffCommand(options: ConfigSnapshotDiffOptions): Promise<number>;
14
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../src/commands/config-snapshot/diff.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,yBAAyB;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,MAAM,CAAC,CAmEjB"}
@@ -0,0 +1,157 @@
1
+ import { log, colors } from '@minecraft-docker/shared';
2
+ import { getContainer } from '../../infrastructure/di/container.js';
3
+ /**
4
+ * Display diff between two config snapshots
5
+ */
6
+ export async function configSnapshotDiffCommand(options) {
7
+ if (!options.id1 || !options.id2) {
8
+ log.error('Two snapshot IDs are required. Usage: mcctl config-snapshot diff <id1> <id2>');
9
+ return 1;
10
+ }
11
+ const container = getContainer(options.root);
12
+ const useCase = container.configSnapshotUseCase;
13
+ try {
14
+ const diff = await useCase.diff(options.id1, options.id2);
15
+ if (options.json) {
16
+ console.log(JSON.stringify(diff.toJSON(), null, 2));
17
+ return 0;
18
+ }
19
+ // Summary header
20
+ const { added, modified, deleted } = diff.summary;
21
+ console.log('');
22
+ console.log(colors.bold('Snapshot Diff'));
23
+ console.log(` Base: ${colors.dim(options.id1.substring(0, 8))}...`);
24
+ console.log(` Compare: ${colors.dim(options.id2.substring(0, 8))}...`);
25
+ console.log('');
26
+ if (!diff.hasChanges) {
27
+ console.log(colors.dim('No differences found between snapshots.'));
28
+ console.log('');
29
+ return 0;
30
+ }
31
+ // Summary line
32
+ const summaryParts = [];
33
+ if (added > 0)
34
+ summaryParts.push(colors.green(`+${added} added`));
35
+ if (modified > 0)
36
+ summaryParts.push(colors.yellow(`~${modified} modified`));
37
+ if (deleted > 0)
38
+ summaryParts.push(colors.red(`-${deleted} deleted`));
39
+ console.log(` Changes: ${summaryParts.join(', ')}`);
40
+ console.log('');
41
+ if (options.filesOnly) {
42
+ // Show only file names with status indicators
43
+ console.log(colors.bold('Changed Files:'));
44
+ console.log('');
45
+ for (const change of diff.changes) {
46
+ const statusIcon = getStatusIcon(change.status);
47
+ const statusColor = getStatusColor(change.status);
48
+ console.log(` ${statusIcon} ${statusColor(change.path)}`);
49
+ }
50
+ console.log('');
51
+ return 0;
52
+ }
53
+ // Full diff output
54
+ for (const change of diff.changes) {
55
+ printFileDiff(change);
56
+ }
57
+ return 0;
58
+ }
59
+ catch (error) {
60
+ const message = error instanceof Error ? error.message : String(error);
61
+ log.error(`Failed to compute diff: ${message}`);
62
+ return 1;
63
+ }
64
+ }
65
+ /**
66
+ * Get the status icon for a file change
67
+ */
68
+ function getStatusIcon(status) {
69
+ switch (status) {
70
+ case 'added':
71
+ return colors.green('+');
72
+ case 'deleted':
73
+ return colors.red('-');
74
+ case 'modified':
75
+ return colors.yellow('~');
76
+ default:
77
+ return ' ';
78
+ }
79
+ }
80
+ /**
81
+ * Get the color function for a file change status
82
+ */
83
+ function getStatusColor(status) {
84
+ switch (status) {
85
+ case 'added':
86
+ return colors.green;
87
+ case 'deleted':
88
+ return colors.red;
89
+ case 'modified':
90
+ return colors.yellow;
91
+ default:
92
+ return (t) => t;
93
+ }
94
+ }
95
+ /**
96
+ * Print unified diff output for a single file
97
+ */
98
+ function printFileDiff(change) {
99
+ const statusLabel = change.status === 'added'
100
+ ? colors.green('[ADDED]')
101
+ : change.status === 'deleted'
102
+ ? colors.red('[DELETED]')
103
+ : colors.yellow('[MODIFIED]');
104
+ console.log(`${statusLabel} ${colors.bold(change.path)}`);
105
+ if (change.status === 'added' && change.newContent !== undefined) {
106
+ // Show added file content (first 10 lines)
107
+ const lines = change.newContent.split('\n').slice(0, 10);
108
+ for (const line of lines) {
109
+ console.log(colors.green(` + ${line}`));
110
+ }
111
+ if (change.newContent.split('\n').length > 10) {
112
+ console.log(colors.dim(' ... (truncated)'));
113
+ }
114
+ }
115
+ else if (change.status === 'deleted' && change.oldContent !== undefined) {
116
+ // Show deleted file content (first 10 lines)
117
+ const lines = change.oldContent.split('\n').slice(0, 10);
118
+ for (const line of lines) {
119
+ console.log(colors.red(` - ${line}`));
120
+ }
121
+ if (change.oldContent.split('\n').length > 10) {
122
+ console.log(colors.dim(' ... (truncated)'));
123
+ }
124
+ }
125
+ else if (change.status === 'modified' &&
126
+ change.oldContent !== undefined &&
127
+ change.newContent !== undefined) {
128
+ // Produce a simple line-by-line diff
129
+ const oldLines = change.oldContent.split('\n');
130
+ const newLines = change.newContent.split('\n');
131
+ const maxLines = Math.min(Math.max(oldLines.length, newLines.length), 20);
132
+ for (let i = 0; i < maxLines; i++) {
133
+ const oldLine = oldLines[i];
134
+ const newLine = newLines[i];
135
+ if (oldLine === undefined && newLine !== undefined) {
136
+ console.log(colors.green(` + ${newLine}`));
137
+ }
138
+ else if (newLine === undefined && oldLine !== undefined) {
139
+ console.log(colors.red(` - ${oldLine}`));
140
+ }
141
+ else if (oldLine !== newLine) {
142
+ if (oldLine !== undefined) {
143
+ console.log(colors.red(` - ${oldLine}`));
144
+ }
145
+ if (newLine !== undefined) {
146
+ console.log(colors.green(` + ${newLine}`));
147
+ }
148
+ }
149
+ }
150
+ const totalLines = Math.max(oldLines.length, newLines.length);
151
+ if (totalLines > 20) {
152
+ console.log(colors.dim(` ... (${totalLines - 20} more lines)`));
153
+ }
154
+ }
155
+ console.log('');
156
+ }
157
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../src/commands/config-snapshot/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export { configSnapshotListCommand, type ConfigSnapshotListOptions, } from './list.js';
2
+ export { configSnapshotCreateCommand, type ConfigSnapshotCreateOptions, } from './create.js';
3
+ export { configSnapshotShowCommand, type ConfigSnapshotShowOptions, } from './show.js';
4
+ export { configSnapshotDeleteCommand, type ConfigSnapshotDeleteOptions, } from './delete.js';
5
+ export { configSnapshotDiffCommand, type ConfigSnapshotDiffOptions, } from './diff.js';
6
+ export { configSnapshotRestoreCommand, type ConfigSnapshotRestoreOptions, } from './restore.js';
7
+ export { configSnapshotScheduleListCommand, type ConfigSnapshotScheduleListOptions, configSnapshotScheduleAddCommand, type ConfigSnapshotScheduleAddOptions, configSnapshotScheduleRemoveCommand, type ConfigSnapshotScheduleRemoveOptions, configSnapshotScheduleToggleCommand, type ConfigSnapshotScheduleToggleOptions, } from './schedule/index.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/config-snapshot/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,KAAK,yBAAyB,GAC/B,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,2BAA2B,EAC3B,KAAK,2BAA2B,GACjC,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,yBAAyB,EACzB,KAAK,yBAAyB,GAC/B,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,2BAA2B,EAC3B,KAAK,2BAA2B,GACjC,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,yBAAyB,EACzB,KAAK,yBAAyB,GAC/B,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,4BAA4B,EAC5B,KAAK,4BAA4B,GAClC,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,iCAAiC,EACjC,KAAK,iCAAiC,EACtC,gCAAgC,EAChC,KAAK,gCAAgC,EACrC,mCAAmC,EACnC,KAAK,mCAAmC,EACxC,mCAAmC,EACnC,KAAK,mCAAmC,GACzC,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,9 @@
1
+ export { configSnapshotListCommand, } from './list.js';
2
+ export { configSnapshotCreateCommand, } from './create.js';
3
+ export { configSnapshotShowCommand, } from './show.js';
4
+ export { configSnapshotDeleteCommand, } from './delete.js';
5
+ export { configSnapshotDiffCommand, } from './diff.js';
6
+ export { configSnapshotRestoreCommand, } from './restore.js';
7
+ // Schedule sub-commands
8
+ export { configSnapshotScheduleListCommand, configSnapshotScheduleAddCommand, configSnapshotScheduleRemoveCommand, configSnapshotScheduleToggleCommand, } from './schedule/index.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/config-snapshot/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,GAE1B,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,2BAA2B,GAE5B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,yBAAyB,GAE1B,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,2BAA2B,GAE5B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,yBAAyB,GAE1B,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,4BAA4B,GAE7B,MAAM,cAAc,CAAC;AAEtB,wBAAwB;AACxB,OAAO,EACL,iCAAiC,EAEjC,gCAAgC,EAEhC,mCAAmC,EAEnC,mCAAmC,GAEpC,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,12 @@
1
+ export interface ConfigSnapshotListOptions {
2
+ root?: string;
3
+ serverName?: string;
4
+ limit?: number;
5
+ offset?: number;
6
+ json?: boolean;
7
+ }
8
+ /**
9
+ * List config snapshots (all servers or specific server)
10
+ */
11
+ export declare function configSnapshotListCommand(options: ConfigSnapshotListOptions): Promise<number>;
12
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/config-snapshot/list.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,yBAAyB;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,MAAM,CAAC,CAoEjB"}
@@ -0,0 +1,55 @@
1
+ import { log, colors } from '@minecraft-docker/shared';
2
+ import { getContainer } from '../../infrastructure/di/container.js';
3
+ /**
4
+ * List config snapshots (all servers or specific server)
5
+ */
6
+ export async function configSnapshotListCommand(options) {
7
+ const container = getContainer(options.root);
8
+ const useCase = container.configSnapshotUseCase;
9
+ const limit = options.limit ?? 20;
10
+ try {
11
+ const snapshots = await useCase.list(options.serverName, limit, options.offset);
12
+ if (options.json) {
13
+ console.log(JSON.stringify(snapshots.map((s) => s.toJSON()), null, 2));
14
+ return 0;
15
+ }
16
+ if (snapshots.length === 0) {
17
+ console.log('');
18
+ if (options.serverName) {
19
+ console.log(colors.dim(`No snapshots found for server "${options.serverName}".`));
20
+ }
21
+ else {
22
+ console.log(colors.dim('No snapshots found.'));
23
+ }
24
+ console.log(colors.dim(' Use: mcctl config-snapshot create <server> to create one.'));
25
+ console.log('');
26
+ return 0;
27
+ }
28
+ console.log('');
29
+ if (options.serverName) {
30
+ console.log(colors.bold(`Config Snapshots for ${options.serverName} (${snapshots.length}):`));
31
+ }
32
+ else {
33
+ console.log(colors.bold(`Config Snapshots (${snapshots.length}):`));
34
+ }
35
+ console.log('');
36
+ for (const snapshot of snapshots) {
37
+ const date = snapshot.createdAt.toLocaleString();
38
+ const server = colors.cyan(snapshot.serverName.value.padEnd(15));
39
+ const id = colors.dim(snapshot.id.substring(0, 8) + '...');
40
+ const fileCount = colors.yellow(`${snapshot.files.length} files`);
41
+ const desc = snapshot.description
42
+ ? colors.dim(` "${snapshot.description}"`)
43
+ : '';
44
+ console.log(` ${server} ${colors.dim(date)} ${fileCount} ${id}${desc}`);
45
+ }
46
+ console.log('');
47
+ return 0;
48
+ }
49
+ catch (error) {
50
+ const message = error instanceof Error ? error.message : String(error);
51
+ log.error(`Failed to list snapshots: ${message}`);
52
+ return 1;
53
+ }
54
+ }
55
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/commands/config-snapshot/list.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export interface ConfigSnapshotRestoreOptions {
2
+ root?: string;
3
+ id: string;
4
+ force?: boolean;
5
+ noSafety?: boolean;
6
+ }
7
+ /**
8
+ * Restore server configuration from a config snapshot
9
+ */
10
+ export declare function configSnapshotRestoreCommand(options: ConfigSnapshotRestoreOptions): Promise<number>;
11
+ //# sourceMappingURL=restore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restore.d.ts","sourceRoot":"","sources":["../../../src/commands/config-snapshot/restore.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,4BAA4B;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,MAAM,CAAC,CAoEjB"}
@@ -0,0 +1,55 @@
1
+ import * as p from '@clack/prompts';
2
+ import { log, colors } from '@minecraft-docker/shared';
3
+ import { getContainer } from '../../infrastructure/di/container.js';
4
+ /**
5
+ * Restore server configuration from a config snapshot
6
+ */
7
+ export async function configSnapshotRestoreCommand(options) {
8
+ if (!options.id) {
9
+ log.error('Snapshot ID is required. Usage: mcctl config-snapshot restore <id>');
10
+ return 1;
11
+ }
12
+ const container = getContainer(options.root);
13
+ const useCase = container.configSnapshotUseCase;
14
+ try {
15
+ const snapshot = await useCase.findById(options.id);
16
+ if (!snapshot) {
17
+ log.error(`Snapshot not found: ${options.id}`);
18
+ return 1;
19
+ }
20
+ // Confirmation prompt (unless --force)
21
+ if (!options.force) {
22
+ console.log('');
23
+ console.log(colors.bold('Restore Configuration'));
24
+ console.log(` Server: ${colors.bold(snapshot.serverName.value)}`);
25
+ console.log(` Snapshot: ${colors.cyan(snapshot.id.substring(0, 8))}...`);
26
+ console.log(` Created: ${colors.dim(snapshot.createdAt.toLocaleString())}`);
27
+ console.log(` Files: ${colors.yellow(String(snapshot.files.length))} files will be overwritten`);
28
+ if (snapshot.description) {
29
+ console.log(` Note: ${colors.dim(snapshot.description)}`);
30
+ }
31
+ console.log('');
32
+ const confirmed = await p.confirm({
33
+ message: `Restore ${snapshot.files.length} files for server "${snapshot.serverName.value}"? This will overwrite current configuration.`,
34
+ initialValue: false,
35
+ });
36
+ if (p.isCancel(confirmed) || !confirmed) {
37
+ console.log(colors.dim('\nRestore cancelled.\n'));
38
+ return 0;
39
+ }
40
+ }
41
+ console.log(colors.dim('\nRestoring configuration files...'));
42
+ await useCase.restore(options.id, options.force ?? false);
43
+ console.log('');
44
+ console.log(colors.green(`Configuration restored from snapshot ${colors.bold(snapshot.id.substring(0, 8))}...`));
45
+ console.log(` ${colors.yellow(String(snapshot.files.length))} files restored for server "${colors.bold(snapshot.serverName.value)}".`);
46
+ console.log('');
47
+ return 0;
48
+ }
49
+ catch (error) {
50
+ const message = error instanceof Error ? error.message : String(error);
51
+ log.error(`Failed to restore snapshot: ${message}`);
52
+ return 1;
53
+ }
54
+ }
55
+ //# sourceMappingURL=restore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restore.js","sourceRoot":"","sources":["../../../src/commands/config-snapshot/restore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface ConfigSnapshotScheduleAddOptions {
2
+ root?: string;
3
+ serverName?: string;
4
+ cron?: string;
5
+ name?: string;
6
+ retention?: number;
7
+ json?: boolean;
8
+ }
9
+ /**
10
+ * Add a new config snapshot schedule
11
+ */
12
+ export declare function configSnapshotScheduleAddCommand(options: ConfigSnapshotScheduleAddOptions): Promise<number>;
13
+ //# sourceMappingURL=add.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../../src/commands/config-snapshot/schedule/add.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gCAAgC;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,gCAAgC,CACpD,OAAO,EAAE,gCAAgC,GACxC,OAAO,CAAC,MAAM,CAAC,CA6DjB"}
@@ -0,0 +1,46 @@
1
+ import { log, colors } from '@minecraft-docker/shared';
2
+ import { getContainer } from '../../../infrastructure/di/container.js';
3
+ /**
4
+ * Add a new config snapshot schedule
5
+ */
6
+ export async function configSnapshotScheduleAddCommand(options) {
7
+ const container = getContainer(options.root);
8
+ const useCase = container.configSnapshotScheduleUseCase;
9
+ // Validate required fields
10
+ if (!options.serverName) {
11
+ log.error('--server is required. Usage: mcctl config-snapshot schedule add --server <name> --cron "..." --name "..."');
12
+ return 1;
13
+ }
14
+ if (!options.cron) {
15
+ log.error('--cron is required. Example: --cron "0 3 * * *"');
16
+ return 1;
17
+ }
18
+ if (!options.name) {
19
+ log.error('--name is required. Example: --name "Daily Snapshot"');
20
+ return 1;
21
+ }
22
+ const retentionCount = options.retention ?? 10;
23
+ try {
24
+ const schedule = await useCase.create(options.serverName, options.name, options.cron, retentionCount);
25
+ if (options.json) {
26
+ console.log(JSON.stringify(schedule.toJSON(), null, 2));
27
+ return 0;
28
+ }
29
+ console.log('');
30
+ console.log(colors.green('Config snapshot schedule created!'));
31
+ console.log(` Name: ${colors.bold(schedule.name)}`);
32
+ console.log(` Server: ${colors.bold(schedule.serverName.value)}`);
33
+ console.log(` Cron: ${colors.cyan(schedule.cronExpression.expression)}`);
34
+ console.log(` Schedule: ${schedule.cronExpression.toHumanReadable()}`);
35
+ console.log(` Retention: max ${colors.yellow(String(schedule.retentionCount))} snapshots`);
36
+ console.log(` ID: ${colors.dim(schedule.id)}`);
37
+ console.log('');
38
+ return 0;
39
+ }
40
+ catch (error) {
41
+ const message = error instanceof Error ? error.message : String(error);
42
+ log.error(`Failed to create schedule: ${message}`);
43
+ return 1;
44
+ }
45
+ }
46
+ //# sourceMappingURL=add.js.map