@lumy-pack/syncpoint 0.0.6 → 0.0.8

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/README.md CHANGED
@@ -31,8 +31,8 @@ Or install globally if you prefer:
31
31
  # Using npm
32
32
  npm install -g @lumy-pack/syncpoint
33
33
 
34
- # Using pnpm
35
- pnpm add -g @lumy-pack/syncpoint
34
+ # Using yarn
35
+ yarn global add @lumy-pack/syncpoint
36
36
  ```
37
37
 
38
38
  ## 🚀 Quick Start
@@ -872,23 +872,23 @@ If restore shows many "overwrite" actions:
872
872
 
873
873
  ```bash
874
874
  # Install dependencies
875
- pnpm install
875
+ yarn install
876
876
 
877
877
  # Development mode
878
- pnpm dev
878
+ yarn dev
879
879
 
880
880
  # Build
881
- pnpm build
881
+ yarn build
882
882
 
883
883
  # Run tests
884
- pnpm test
884
+ yarn test
885
885
 
886
886
  # Run all tests (unit + integration + e2e + docker)
887
- pnpm test:all
887
+ yarn test:all
888
888
 
889
889
  # Lint and format
890
- pnpm lint
891
- pnpm format
890
+ yarn lint
891
+ yarn format
892
892
  ```
893
893
 
894
894
  ### Technology Stack
package/dist/cli.mjs CHANGED
@@ -4,9 +4,9 @@
4
4
  import { Command } from "commander";
5
5
 
6
6
  // src/commands/Backup.tsx
7
- import { Box, Text as Text2, useApp } from "ink";
7
+ import { Box, Static, Text as Text2, useApp } from "ink";
8
8
  import { render } from "ink";
9
- import { useEffect, useState } from "react";
9
+ import { useEffect, useMemo, useState } from "react";
10
10
 
11
11
  // src/components/ProgressBar.tsx
12
12
  import { Text } from "ink";
@@ -486,7 +486,7 @@ function validateMetadata(data) {
486
486
  }
487
487
 
488
488
  // src/version.ts
489
- var VERSION = "0.0.6";
489
+ var VERSION = "0.0.8";
490
490
 
491
491
  // src/core/metadata.ts
492
492
  var METADATA_VERSION = "1.0.0";
@@ -1201,6 +1201,24 @@ var BackupView = ({ options }) => {
1201
1201
  const [progress, setProgress] = useState(0);
1202
1202
  const [result, setResult] = useState(null);
1203
1203
  const [error, setError] = useState(null);
1204
+ const staticItems = useMemo(() => {
1205
+ if (foundFiles.length === 0 && missingFiles.length === 0) return [];
1206
+ const seen = /* @__PURE__ */ new Set();
1207
+ const deduped = [
1208
+ { id: "scan-header", type: "header" }
1209
+ ];
1210
+ for (const f of foundFiles) {
1211
+ if (seen.has(f.absolutePath)) continue;
1212
+ seen.add(f.absolutePath);
1213
+ deduped.push({ id: `found-${f.absolutePath}`, type: "found", file: f });
1214
+ }
1215
+ for (const p of missingFiles) {
1216
+ if (seen.has(p)) continue;
1217
+ seen.add(p);
1218
+ deduped.push({ id: `missing-${p}`, type: "missing", path: p });
1219
+ }
1220
+ return deduped;
1221
+ }, [foundFiles, missingFiles]);
1204
1222
  useEffect(() => {
1205
1223
  (async () => {
1206
1224
  let progressInterval;
@@ -1243,27 +1261,33 @@ var BackupView = ({ options }) => {
1243
1261
  ] }) });
1244
1262
  }
1245
1263
  return /* @__PURE__ */ jsxs2(Box, { flexDirection: "column", children: [
1246
- /* @__PURE__ */ jsx2(Text2, { bold: true, children: "\u25B8 Scanning backup targets..." }),
1247
- foundFiles.map((file, idx) => /* @__PURE__ */ jsxs2(Text2, { children: [
1248
- " ",
1249
- /* @__PURE__ */ jsx2(Text2, { color: "green", children: "\u2713" }),
1250
- " ",
1251
- contractTilde(file.absolutePath),
1252
- /* @__PURE__ */ jsxs2(Text2, { color: "gray", children: [
1253
- " ",
1254
- formatBytes(file.size).padStart(10)
1255
- ] })
1256
- ] }, idx)),
1257
- missingFiles.map((file, idx) => /* @__PURE__ */ jsxs2(Text2, { children: [
1258
- " ",
1259
- /* @__PURE__ */ jsx2(Text2, { color: "yellow", children: "\u26A0" }),
1260
- " ",
1261
- file,
1262
- /* @__PURE__ */ jsxs2(Text2, { color: "gray", children: [
1263
- " ",
1264
- "File not found, skipped"
1265
- ] })
1266
- ] }, idx)),
1264
+ /* @__PURE__ */ jsx2(Static, { items: staticItems, children: (item) => {
1265
+ if (item.type === "header") {
1266
+ return /* @__PURE__ */ jsx2(Text2, { bold: true, children: "\u25B8 Scanning backup targets..." }, item.id);
1267
+ }
1268
+ if (item.type === "found") {
1269
+ return /* @__PURE__ */ jsxs2(Text2, { children: [
1270
+ " ",
1271
+ /* @__PURE__ */ jsx2(Text2, { color: "green", children: "\u2713" }),
1272
+ " ",
1273
+ contractTilde(item.file.absolutePath),
1274
+ /* @__PURE__ */ jsxs2(Text2, { color: "gray", children: [
1275
+ " ",
1276
+ formatBytes(item.file.size).padStart(10)
1277
+ ] })
1278
+ ] }, item.id);
1279
+ }
1280
+ return /* @__PURE__ */ jsxs2(Text2, { children: [
1281
+ " ",
1282
+ /* @__PURE__ */ jsx2(Text2, { color: "yellow", children: "\u26A0" }),
1283
+ " ",
1284
+ item.path,
1285
+ /* @__PURE__ */ jsxs2(Text2, { color: "gray", children: [
1286
+ " ",
1287
+ "File not found, skipped"
1288
+ ] })
1289
+ ] }, item.id);
1290
+ } }),
1267
1291
  options.dryRun && phase === "done" && /* @__PURE__ */ jsxs2(Box, { flexDirection: "column", marginTop: 1, children: [
1268
1292
  /* @__PURE__ */ jsx2(Text2, { color: "yellow", children: "(dry-run) No actual backup was created" }),
1269
1293
  /* @__PURE__ */ jsxs2(Text2, { children: [
@@ -2442,6 +2466,7 @@ var ListView = ({ type, deleteIndex }) => {
2442
2466
  const [deleteTarget, setDeleteTarget] = useState5(null);
2443
2467
  const [error, setError] = useState5(null);
2444
2468
  const [backupDir, setBackupDir] = useState5(getSubDir("backups"));
2469
+ const [successMessage, setSuccessMessage] = useState5(null);
2445
2470
  useInput2((_input, key) => {
2446
2471
  if (!key.escape) return;
2447
2472
  switch (phase) {
@@ -2452,6 +2477,7 @@ var ListView = ({ type, deleteIndex }) => {
2452
2477
  case "template-list":
2453
2478
  setSelectedBackup(null);
2454
2479
  setSelectedTemplate(null);
2480
+ setSuccessMessage(null);
2455
2481
  setPhase("main-menu");
2456
2482
  break;
2457
2483
  case "backup-detail":
@@ -2517,6 +2543,14 @@ var ListView = ({ type, deleteIndex }) => {
2517
2543
  setSelectedTemplate(null);
2518
2544
  setPhase("template-list");
2519
2545
  };
2546
+ const reloadBackups = async () => {
2547
+ try {
2548
+ const config = await loadConfig();
2549
+ const list2 = await getBackupList(config);
2550
+ setBackups(list2);
2551
+ } catch {
2552
+ }
2553
+ };
2520
2554
  const handleDeleteConfirm = (yes) => {
2521
2555
  if (yes && deleteTarget) {
2522
2556
  try {
@@ -2524,8 +2558,13 @@ var ListView = ({ type, deleteIndex }) => {
2524
2558
  throw new Error(`Refusing to delete file outside backups directory: ${deleteTarget.path}`);
2525
2559
  }
2526
2560
  unlinkSync(deleteTarget.path);
2527
- setPhase("done");
2528
- setTimeout(() => exit(), 100);
2561
+ const deletedName = deleteTarget.name;
2562
+ setBackups((prev) => prev.filter((b) => b.path !== deleteTarget.path));
2563
+ setDeleteTarget(null);
2564
+ setSelectedBackup(null);
2565
+ setSuccessMessage(`\u2713 ${deletedName} deleted`);
2566
+ setPhase("backup-list");
2567
+ void reloadBackups();
2529
2568
  } catch (err) {
2530
2569
  setError(err instanceof Error ? err.message : String(err));
2531
2570
  setPhase("error");
@@ -2621,6 +2660,7 @@ var ListView = ({ type, deleteIndex }) => {
2621
2660
  }
2622
2661
  };
2623
2662
  return /* @__PURE__ */ jsxs8(Box6, { flexDirection: "column", children: [
2663
+ successMessage && /* @__PURE__ */ jsx8(Box6, { marginBottom: 1, children: /* @__PURE__ */ jsx8(Text8, { color: "green", children: successMessage }) }),
2624
2664
  /* @__PURE__ */ jsx8(Text8, { bold: true, children: "\u25B8 Backups" }),
2625
2665
  /* @__PURE__ */ jsx8(Box6, { marginTop: 1, children: backups.length === 0 ? /* @__PURE__ */ jsx8(Text8, { color: "gray", children: " No backups found." }) : /* @__PURE__ */ jsx8(
2626
2666
  SelectInput,
@@ -3060,7 +3100,7 @@ ${pc2.red("\u2717")} Sudo authentication failed or was cancelled. Aborting.`
3060
3100
  }
3061
3101
 
3062
3102
  // src/components/StepRunner.tsx
3063
- import { Text as Text10, Box as Box8 } from "ink";
3103
+ import { Text as Text10, Box as Box8, Static as Static2 } from "ink";
3064
3104
  import Spinner2 from "ink-spinner";
3065
3105
  import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
3066
3106
  var StepIcon = ({ status }) => {
@@ -3099,35 +3139,73 @@ var StepStatusText = ({ step }) => {
3099
3139
  return null;
3100
3140
  }
3101
3141
  };
3142
+ var StepItemView = ({
3143
+ step,
3144
+ index,
3145
+ total,
3146
+ isLast
3147
+ }) => /* @__PURE__ */ jsxs10(Box8, { flexDirection: "column", marginBottom: isLast ? 0 : 1, children: [
3148
+ /* @__PURE__ */ jsxs10(Text10, { children: [
3149
+ " ",
3150
+ /* @__PURE__ */ jsx10(StepIcon, { status: step.status }),
3151
+ /* @__PURE__ */ jsxs10(Text10, { children: [
3152
+ " ",
3153
+ /* @__PURE__ */ jsxs10(Text10, { bold: true, children: [
3154
+ "Step ",
3155
+ index + 1,
3156
+ "/",
3157
+ total
3158
+ ] }),
3159
+ " ",
3160
+ step.name
3161
+ ] })
3162
+ ] }),
3163
+ step.output && step.status !== "pending" && /* @__PURE__ */ jsxs10(Text10, { color: "gray", children: [
3164
+ " ",
3165
+ step.output
3166
+ ] }),
3167
+ /* @__PURE__ */ jsxs10(Text10, { children: [
3168
+ " ",
3169
+ /* @__PURE__ */ jsx10(StepStatusText, { step })
3170
+ ] })
3171
+ ] });
3102
3172
  var StepRunner = ({
3103
3173
  steps,
3104
3174
  total
3105
3175
  }) => {
3106
- return /* @__PURE__ */ jsx10(Box8, { flexDirection: "column", children: steps.map((step, idx) => /* @__PURE__ */ jsxs10(Box8, { flexDirection: "column", marginBottom: idx < steps.length - 1 ? 1 : 0, children: [
3107
- /* @__PURE__ */ jsxs10(Text10, { children: [
3108
- " ",
3109
- /* @__PURE__ */ jsx10(StepIcon, { status: step.status }),
3110
- /* @__PURE__ */ jsxs10(Text10, { children: [
3111
- " ",
3112
- /* @__PURE__ */ jsxs10(Text10, { bold: true, children: [
3113
- "Step ",
3114
- idx + 1,
3115
- "/",
3116
- total
3117
- ] }),
3118
- " ",
3119
- step.name
3120
- ] })
3121
- ] }),
3122
- step.output && step.status !== "pending" && /* @__PURE__ */ jsxs10(Text10, { color: "gray", children: [
3123
- " ",
3124
- step.output
3125
- ] }),
3126
- /* @__PURE__ */ jsxs10(Text10, { children: [
3127
- " ",
3128
- /* @__PURE__ */ jsx10(StepStatusText, { step })
3129
- ] })
3130
- ] }, idx)) });
3176
+ const completedSteps = [];
3177
+ const activeSteps = [];
3178
+ steps.forEach((step, idx) => {
3179
+ const indexed = { ...step, idx };
3180
+ if (step.status === "success" || step.status === "failed" || step.status === "skipped") {
3181
+ completedSteps.push(indexed);
3182
+ } else {
3183
+ activeSteps.push(indexed);
3184
+ }
3185
+ });
3186
+ const lastIdx = steps.length - 1;
3187
+ return /* @__PURE__ */ jsxs10(Box8, { flexDirection: "column", children: [
3188
+ /* @__PURE__ */ jsx10(Static2, { items: completedSteps, children: (item) => /* @__PURE__ */ jsx10(
3189
+ StepItemView,
3190
+ {
3191
+ step: item,
3192
+ index: item.idx,
3193
+ total,
3194
+ isLast: item.idx === lastIdx && activeSteps.length === 0
3195
+ },
3196
+ item.idx
3197
+ ) }),
3198
+ activeSteps.map((item) => /* @__PURE__ */ jsx10(
3199
+ StepItemView,
3200
+ {
3201
+ step: item,
3202
+ index: item.idx,
3203
+ total,
3204
+ isLast: item.idx === lastIdx
3205
+ },
3206
+ item.idx
3207
+ ))
3208
+ ] });
3131
3209
  };
3132
3210
 
3133
3211
  // src/commands/Provision.tsx
package/dist/index.cjs CHANGED
@@ -44,7 +44,7 @@ __export(src_exports, {
44
44
  });
45
45
  module.exports = __toCommonJS(src_exports);
46
46
 
47
- // ../../node_modules/.pnpm/tsup@8.5.1_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/cjs_shims.js
47
+ // ../../node_modules/tsup/assets/cjs_shims.js
48
48
  var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
49
49
  var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
50
50
 
@@ -652,7 +652,7 @@ function validateMetadata(data) {
652
652
  }
653
653
 
654
654
  // src/version.ts
655
- var VERSION = "0.0.6";
655
+ var VERSION = "0.0.8";
656
656
 
657
657
  // src/core/metadata.ts
658
658
  var METADATA_VERSION = "1.0.0";
package/dist/index.mjs CHANGED
@@ -602,7 +602,7 @@ function validateMetadata(data) {
602
602
  }
603
603
 
604
604
  // src/version.ts
605
- var VERSION = "0.0.6";
605
+ var VERSION = "0.0.8";
606
606
 
607
607
  // src/core/metadata.ts
608
608
  var METADATA_VERSION = "1.0.0";
package/dist/version.d.ts CHANGED
@@ -2,4 +2,4 @@
2
2
  * Current package version from package.json
3
3
  * Automatically synchronized during build process
4
4
  */
5
- export declare const VERSION = "0.0.6";
5
+ export declare const VERSION = "0.0.8";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumy-pack/syncpoint",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "CLI tool for project synchronization and scaffolding",
5
5
  "keywords": [
6
6
  "cli",
@@ -37,6 +37,23 @@
37
37
  "assets",
38
38
  "README.md"
39
39
  ],
40
+ "scripts": {
41
+ "build": "node scripts/inject-version.js && tsup && yarn build:types",
42
+ "build:publish:npm": "yarn build && yarn publish:npm",
43
+ "build:types": "tsc -p ./tsconfig.declarations.json",
44
+ "dev": "node scripts/inject-version.js && tsx src/cli.ts",
45
+ "format": "prettier --write \"src/**/*.ts\"",
46
+ "lint": "eslint \"src/**/*.ts\"",
47
+ "publish:npm": "yarn npm publish --access public",
48
+ "test": "vitest",
49
+ "test:all": "vitest run && yarn test:e2e && yarn test:docker",
50
+ "test:docker": "vitest run --config vitest.e2e.config.ts src/__tests__/docker/",
51
+ "test:e2e": "vitest run --config vitest.e2e.config.ts src/__tests__/e2e/",
52
+ "test:run": "vitest run",
53
+ "version:major": "yarn version major",
54
+ "version:minor": "yarn version minor",
55
+ "version:patch": "yarn version patch"
56
+ },
40
57
  "dependencies": {
41
58
  "ajv": "^8.0.0",
42
59
  "ajv-formats": "^3.0.0",
@@ -57,22 +74,5 @@
57
74
  "@types/react": "^18.0.0",
58
75
  "@vitest/coverage-v8": "^3.2.4",
59
76
  "ink-testing-library": "^4.0.0"
60
- },
61
- "scripts": {
62
- "build": "node scripts/inject-version.js && tsup && pnpm build:types",
63
- "build:publish:npm": "pnpm build && pnpm publish:npm",
64
- "build:types": "tsc -p ./tsconfig.declarations.json",
65
- "dev": "node scripts/inject-version.js && tsx src/cli.ts",
66
- "format": "prettier --write \"src/**/*.ts\"",
67
- "lint": "eslint \"src/**/*.ts\"",
68
- "publish:npm": "pnpm publish --access public --no-git-checks",
69
- "test": "vitest",
70
- "test:all": "vitest run && pnpm test:e2e && pnpm test:docker",
71
- "test:docker": "vitest run --config vitest.e2e.config.ts src/__tests__/docker/",
72
- "test:e2e": "vitest run --config vitest.e2e.config.ts src/__tests__/e2e/",
73
- "test:run": "vitest run",
74
- "version:major": "pnpm version major",
75
- "version:minor": "pnpm version minor",
76
- "version:patch": "pnpm version patch"
77
77
  }
78
78
  }