pushwork 1.0.5 → 1.0.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.
Files changed (204) hide show
  1. package/README.md +87 -335
  2. package/dist/.pushwork/automerge/3P/Dm3ekE2pmjGnWvDaG3vSR7ww98/snapshot/aa2349c94955ea561f698720142f9d884a6872d9f82dc332d578c216beb0df0e +0 -0
  3. package/dist/.pushwork/automerge/st/orage-adapter-id +1 -0
  4. package/dist/.pushwork/config.json +15 -0
  5. package/dist/.pushwork/snapshot.json +7 -0
  6. package/dist/cli.js +208 -213
  7. package/dist/cli.js.map +1 -1
  8. package/dist/commands.d.ts +51 -0
  9. package/dist/commands.d.ts.map +1 -0
  10. package/dist/commands.js +799 -0
  11. package/dist/commands.js.map +1 -0
  12. package/dist/core/change-detection.d.ts +2 -23
  13. package/dist/core/change-detection.d.ts.map +1 -1
  14. package/dist/core/change-detection.js +73 -115
  15. package/dist/core/change-detection.js.map +1 -1
  16. package/dist/{config/index.d.ts → core/config.d.ts} +13 -3
  17. package/dist/core/config.d.ts.map +1 -0
  18. package/dist/{config/index.js → core/config.js} +55 -73
  19. package/dist/core/config.js.map +1 -0
  20. package/dist/core/index.d.ts +1 -0
  21. package/dist/core/index.d.ts.map +1 -1
  22. package/dist/core/index.js +1 -1
  23. package/dist/core/index.js.map +1 -1
  24. package/dist/core/move-detection.d.ts +4 -3
  25. package/dist/core/move-detection.d.ts.map +1 -1
  26. package/dist/core/move-detection.js +8 -7
  27. package/dist/core/move-detection.js.map +1 -1
  28. package/dist/core/snapshot.d.ts +0 -4
  29. package/dist/core/snapshot.d.ts.map +1 -1
  30. package/dist/core/snapshot.js +2 -11
  31. package/dist/core/snapshot.js.map +1 -1
  32. package/dist/core/sync-engine.d.ts +5 -11
  33. package/dist/core/sync-engine.d.ts.map +1 -1
  34. package/dist/core/sync-engine.js +211 -308
  35. package/dist/core/sync-engine.js.map +1 -1
  36. package/dist/index.d.ts +0 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +0 -6
  39. package/dist/index.js.map +1 -1
  40. package/dist/types/config.d.ts +24 -88
  41. package/dist/types/config.d.ts.map +1 -1
  42. package/dist/types/config.js +6 -0
  43. package/dist/types/config.js.map +1 -1
  44. package/dist/types/documents.d.ts +15 -2
  45. package/dist/types/documents.d.ts.map +1 -1
  46. package/dist/types/documents.js.map +1 -1
  47. package/dist/types/index.d.ts.map +1 -1
  48. package/dist/types/index.js +0 -3
  49. package/dist/types/index.js.map +1 -1
  50. package/dist/types/snapshot.d.ts +0 -21
  51. package/dist/types/snapshot.d.ts.map +1 -1
  52. package/dist/types/snapshot.js +0 -14
  53. package/dist/types/snapshot.js.map +1 -1
  54. package/dist/utils/content.d.ts.map +1 -1
  55. package/dist/utils/content.js +2 -6
  56. package/dist/utils/content.js.map +1 -1
  57. package/dist/utils/directory.d.ts +10 -0
  58. package/dist/utils/directory.d.ts.map +1 -0
  59. package/dist/utils/directory.js +37 -0
  60. package/dist/utils/directory.js.map +1 -0
  61. package/dist/utils/fs.d.ts +15 -2
  62. package/dist/utils/fs.d.ts.map +1 -1
  63. package/dist/utils/fs.js +54 -20
  64. package/dist/utils/fs.js.map +1 -1
  65. package/dist/utils/index.d.ts +1 -0
  66. package/dist/utils/index.d.ts.map +1 -1
  67. package/dist/utils/index.js +1 -3
  68. package/dist/utils/index.js.map +1 -1
  69. package/dist/utils/mime-types.d.ts.map +1 -1
  70. package/dist/utils/mime-types.js +11 -4
  71. package/dist/utils/mime-types.js.map +1 -1
  72. package/dist/utils/network-sync.d.ts +0 -6
  73. package/dist/utils/network-sync.d.ts.map +1 -1
  74. package/dist/utils/network-sync.js +55 -99
  75. package/dist/utils/network-sync.js.map +1 -1
  76. package/dist/utils/output.d.ts +129 -0
  77. package/dist/utils/output.d.ts.map +1 -0
  78. package/dist/utils/output.js +375 -0
  79. package/dist/utils/output.js.map +1 -0
  80. package/dist/utils/repo-factory.d.ts +2 -6
  81. package/dist/utils/repo-factory.d.ts.map +1 -1
  82. package/dist/utils/repo-factory.js +8 -31
  83. package/dist/utils/repo-factory.js.map +1 -1
  84. package/dist/utils/string-similarity.js +2 -2
  85. package/dist/utils/string-similarity.js.map +1 -1
  86. package/dist/utils/trace.d.ts +19 -0
  87. package/dist/utils/trace.d.ts.map +1 -0
  88. package/dist/utils/trace.js +68 -0
  89. package/dist/utils/trace.js.map +1 -0
  90. package/package.json +11 -11
  91. package/src/cli.ts +276 -308
  92. package/src/commands.ts +988 -0
  93. package/src/core/change-detection.ts +182 -240
  94. package/src/{config/index.ts → core/config.ts} +65 -82
  95. package/src/core/index.ts +1 -1
  96. package/src/core/move-detection.ts +10 -8
  97. package/src/core/snapshot.ts +2 -12
  98. package/src/core/sync-engine.ts +237 -427
  99. package/src/index.ts +0 -10
  100. package/src/types/config.ts +28 -93
  101. package/src/types/documents.ts +16 -2
  102. package/src/types/index.ts +0 -5
  103. package/src/types/snapshot.ts +0 -23
  104. package/src/utils/content.ts +2 -6
  105. package/src/utils/directory.ts +50 -0
  106. package/src/utils/fs.ts +58 -23
  107. package/src/utils/index.ts +1 -5
  108. package/src/utils/mime-types.ts +12 -4
  109. package/src/utils/network-sync.ts +79 -137
  110. package/src/utils/output.ts +450 -0
  111. package/src/utils/repo-factory.ts +13 -44
  112. package/src/utils/string-similarity.ts +2 -2
  113. package/src/utils/trace.ts +70 -0
  114. package/test/integration/exclude-patterns.test.ts +6 -15
  115. package/test/integration/fuzzer.test.ts +308 -391
  116. package/test/integration/init-sync.test.ts +89 -0
  117. package/test/integration/sync-deletion.test.ts +2 -61
  118. package/test/integration/sync-flow.test.ts +4 -24
  119. package/test/jest.setup.ts +34 -0
  120. package/test/unit/deletion-behavior.test.ts +3 -14
  121. package/test/unit/enhanced-mime-detection.test.ts +0 -22
  122. package/test/unit/snapshot.test.ts +2 -29
  123. package/test/unit/sync-convergence.test.ts +3 -198
  124. package/test/unit/sync-timing.test.ts +0 -44
  125. package/test/unit/utils.test.ts +0 -2
  126. package/tsconfig.json +3 -3
  127. package/bench/filesystem.bench.ts +0 -78
  128. package/bench/hashing.bench.ts +0 -60
  129. package/bench/move-detection.bench.ts +0 -130
  130. package/bench/runner.ts +0 -49
  131. package/dist/browser/browser-sync-engine.d.ts +0 -64
  132. package/dist/browser/browser-sync-engine.d.ts.map +0 -1
  133. package/dist/browser/browser-sync-engine.js +0 -303
  134. package/dist/browser/browser-sync-engine.js.map +0 -1
  135. package/dist/browser/filesystem-adapter.d.ts +0 -84
  136. package/dist/browser/filesystem-adapter.d.ts.map +0 -1
  137. package/dist/browser/filesystem-adapter.js +0 -413
  138. package/dist/browser/filesystem-adapter.js.map +0 -1
  139. package/dist/browser/index.d.ts +0 -36
  140. package/dist/browser/index.d.ts.map +0 -1
  141. package/dist/browser/index.js +0 -90
  142. package/dist/browser/index.js.map +0 -1
  143. package/dist/browser/types.d.ts +0 -70
  144. package/dist/browser/types.d.ts.map +0 -1
  145. package/dist/browser/types.js +0 -6
  146. package/dist/browser/types.js.map +0 -1
  147. package/dist/cli/commands.d.ts +0 -67
  148. package/dist/cli/commands.d.ts.map +0 -1
  149. package/dist/cli/commands.js +0 -794
  150. package/dist/cli/commands.js.map +0 -1
  151. package/dist/cli/index.d.ts +0 -2
  152. package/dist/cli/index.d.ts.map +0 -1
  153. package/dist/cli/index.js +0 -19
  154. package/dist/cli/index.js.map +0 -1
  155. package/dist/cli/output.d.ts +0 -75
  156. package/dist/cli/output.d.ts.map +0 -1
  157. package/dist/cli/output.js +0 -182
  158. package/dist/cli/output.js.map +0 -1
  159. package/dist/config/index.d.ts.map +0 -1
  160. package/dist/config/index.js.map +0 -1
  161. package/dist/config/remote-manager.d.ts +0 -65
  162. package/dist/config/remote-manager.d.ts.map +0 -1
  163. package/dist/config/remote-manager.js +0 -243
  164. package/dist/config/remote-manager.js.map +0 -1
  165. package/dist/core/isomorphic-snapshot.d.ts +0 -58
  166. package/dist/core/isomorphic-snapshot.d.ts.map +0 -1
  167. package/dist/core/isomorphic-snapshot.js +0 -204
  168. package/dist/core/isomorphic-snapshot.js.map +0 -1
  169. package/dist/platform/browser-filesystem.d.ts +0 -26
  170. package/dist/platform/browser-filesystem.d.ts.map +0 -1
  171. package/dist/platform/browser-filesystem.js +0 -91
  172. package/dist/platform/browser-filesystem.js.map +0 -1
  173. package/dist/platform/filesystem.d.ts +0 -29
  174. package/dist/platform/filesystem.d.ts.map +0 -1
  175. package/dist/platform/filesystem.js +0 -65
  176. package/dist/platform/filesystem.js.map +0 -1
  177. package/dist/platform/node-filesystem.d.ts +0 -21
  178. package/dist/platform/node-filesystem.d.ts.map +0 -1
  179. package/dist/platform/node-filesystem.js +0 -93
  180. package/dist/platform/node-filesystem.js.map +0 -1
  181. package/dist/utils/content-similarity.d.ts +0 -53
  182. package/dist/utils/content-similarity.d.ts.map +0 -1
  183. package/dist/utils/content-similarity.js +0 -155
  184. package/dist/utils/content-similarity.js.map +0 -1
  185. package/dist/utils/fs-browser.d.ts +0 -57
  186. package/dist/utils/fs-browser.d.ts.map +0 -1
  187. package/dist/utils/fs-browser.js +0 -311
  188. package/dist/utils/fs-browser.js.map +0 -1
  189. package/dist/utils/fs-node.d.ts +0 -53
  190. package/dist/utils/fs-node.d.ts.map +0 -1
  191. package/dist/utils/fs-node.js +0 -220
  192. package/dist/utils/fs-node.js.map +0 -1
  193. package/dist/utils/isomorphic.d.ts +0 -29
  194. package/dist/utils/isomorphic.d.ts.map +0 -1
  195. package/dist/utils/isomorphic.js +0 -139
  196. package/dist/utils/isomorphic.js.map +0 -1
  197. package/dist/utils/pure.d.ts +0 -25
  198. package/dist/utils/pure.d.ts.map +0 -1
  199. package/dist/utils/pure.js +0 -112
  200. package/dist/utils/pure.js.map +0 -1
  201. package/src/cli/commands.ts +0 -1030
  202. package/src/cli/index.ts +0 -2
  203. package/src/cli/output.ts +0 -244
  204. package/test/README-TESTING-GAPS.md +0 -174
@@ -1,7 +1,12 @@
1
1
  import * as fs from "fs/promises";
2
2
  import * as path from "path";
3
3
  import * as os from "os";
4
- import { GlobalConfig, DirectoryConfig } from "../types";
4
+ import {
5
+ GlobalConfig,
6
+ DirectoryConfig,
7
+ DEFAULT_SYNC_SERVER,
8
+ DEFAULT_SYNC_SERVER_STORAGE_ID,
9
+ } from "../types";
5
10
  import { pathExists, ensureDirectoryExists } from "../utils";
6
11
 
7
12
  /**
@@ -10,7 +15,8 @@ import { pathExists, ensureDirectoryExists } from "../utils";
10
15
  export class ConfigManager {
11
16
  private static readonly GLOBAL_CONFIG_DIR = ".pushwork";
12
17
  private static readonly CONFIG_FILENAME = "config.json";
13
- private static readonly LOCAL_CONFIG_DIR = ".pushwork";
18
+
19
+ static readonly CONFIG_DIR = ".pushwork";
14
20
 
15
21
  constructor(private workingDir?: string) {}
16
22
 
@@ -34,7 +40,7 @@ export class ConfigManager {
34
40
  }
35
41
  return path.join(
36
42
  this.workingDir,
37
- ConfigManager.LOCAL_CONFIG_DIR,
43
+ ConfigManager.CONFIG_DIR,
38
44
  ConfigManager.CONFIG_FILENAME
39
45
  );
40
46
  }
@@ -52,7 +58,7 @@ export class ConfigManager {
52
58
  const content = await fs.readFile(configPath, "utf8");
53
59
  return JSON.parse(content) as GlobalConfig;
54
60
  } catch (error) {
55
- console.warn(`Failed to load global config: ${error}`);
61
+ // Failed to load global config
56
62
  return null;
57
63
  }
58
64
  }
@@ -89,7 +95,7 @@ export class ConfigManager {
89
95
  const content = await fs.readFile(configPath, "utf8");
90
96
  return JSON.parse(content) as DirectoryConfig;
91
97
  } catch (error) {
92
- console.warn(`Failed to load local config: ${error}`);
98
+ // Failed to load local config
93
99
  return null;
94
100
  }
95
101
  }
@@ -113,34 +119,53 @@ export class ConfigManager {
113
119
  }
114
120
  }
115
121
 
122
+ private getDefaultGlobalConfig(): GlobalConfig {
123
+ return {
124
+ exclude_patterns: [
125
+ ".git",
126
+ "node_modules",
127
+ "*.tmp",
128
+ ".DS_Store",
129
+ ".pushwork",
130
+ ],
131
+ sync_server: DEFAULT_SYNC_SERVER,
132
+ sync_server_storage_id: DEFAULT_SYNC_SERVER_STORAGE_ID,
133
+ sync: {
134
+ move_detection_threshold: 0.7,
135
+ },
136
+ };
137
+ }
138
+
116
139
  /**
117
- * Get merged configuration (global + local)
140
+ * Get default configuration
118
141
  */
119
- async getMerged(): Promise<DirectoryConfig> {
120
- const globalConfig = await this.loadGlobal();
121
- const localConfig = await this.load();
122
-
123
- // Create default configuration
124
- const defaultConfig: DirectoryConfig = {
142
+ private getDefaultConfig(): DirectoryConfig {
143
+ return {
125
144
  sync_enabled: true,
126
- sync_server_storage_id: "3760df37-a4c6-4f66-9ecd-732039a9385d",
127
- defaults: {
128
- exclude_patterns: [".git", "node_modules", "*.tmp", ".pushwork"],
129
- large_file_threshold: "100MB",
130
- },
131
- diff: {
132
- show_binary: false,
133
- },
145
+ sync_server: DEFAULT_SYNC_SERVER,
146
+ sync_server_storage_id: DEFAULT_SYNC_SERVER_STORAGE_ID,
147
+ exclude_patterns: [
148
+ ".git",
149
+ "node_modules",
150
+ "*.tmp",
151
+ ".pushwork",
152
+ ".DS_Store",
153
+ ],
134
154
  sync: {
135
- move_detection_threshold: 0.8,
136
- prompt_threshold: 0.5,
137
- auto_sync: false,
138
- parallel_operations: 4,
155
+ move_detection_threshold: 0.7,
139
156
  },
140
157
  };
158
+ }
159
+
160
+ /**
161
+ * Get merged configuration (global + local)
162
+ */
163
+ async getMerged(): Promise<DirectoryConfig> {
164
+ const globalConfig = await this.loadGlobal();
165
+ const localConfig = await this.load();
141
166
 
142
167
  // Merge configurations: default < global < local
143
- let merged = { ...defaultConfig };
168
+ let merged = this.getDefaultConfig();
144
169
 
145
170
  if (globalConfig) {
146
171
  merged = this.mergeConfigs(merged, globalConfig);
@@ -153,6 +178,18 @@ export class ConfigManager {
153
178
  return merged;
154
179
  }
155
180
 
181
+ /**
182
+ * Initialize with CLI option overrides
183
+ * Creates a new config with defaults + CLI overrides and saves it
184
+ */
185
+ async initializeWithOverrides(
186
+ overrides: Partial<DirectoryConfig> = {}
187
+ ): Promise<DirectoryConfig> {
188
+ const config = this.mergeConfigs(this.getDefaultConfig(), overrides);
189
+ await this.save(config);
190
+ return config;
191
+ }
192
+
156
193
  /**
157
194
  * Merge two configuration objects
158
195
  */
@@ -179,25 +216,7 @@ export class ConfigManager {
179
216
 
180
217
  // Handle GlobalConfig structure
181
218
  if ("exclude_patterns" in override && override.exclude_patterns) {
182
- merged.defaults.exclude_patterns = override.exclude_patterns;
183
- }
184
-
185
- if ("large_file_threshold" in override && override.large_file_threshold) {
186
- merged.defaults.large_file_threshold = override.large_file_threshold;
187
- }
188
-
189
- // Handle DirectoryConfig structure
190
- if ("defaults" in override && override.defaults) {
191
- merged.defaults = { ...merged.defaults, ...override.defaults };
192
- }
193
-
194
- if ("diff" in override && override.diff) {
195
- // Merge diff settings, ensuring show_binary has a default
196
- merged.diff = {
197
- ...merged.diff,
198
- ...override.diff,
199
- show_binary: override.diff.show_binary ?? merged.diff.show_binary,
200
- };
219
+ merged.exclude_patterns = override.exclude_patterns;
201
220
  }
202
221
 
203
222
  if ("sync" in override && override.sync) {
@@ -211,28 +230,7 @@ export class ConfigManager {
211
230
  * Create default global configuration
212
231
  */
213
232
  async createDefaultGlobal(): Promise<void> {
214
- const defaultGlobal: GlobalConfig = {
215
- exclude_patterns: [
216
- ".git",
217
- "node_modules",
218
- "*.tmp",
219
- ".DS_Store",
220
- ".pushwork",
221
- ],
222
- large_file_threshold: "100MB",
223
- sync_server: "wss://sync3.automerge.org",
224
- sync_server_storage_id: "3760df37-a4c6-4f66-9ecd-732039a9385d",
225
- diff: {
226
- show_binary: false,
227
- },
228
- sync: {
229
- move_detection_threshold: 0.8,
230
- prompt_threshold: 0.5,
231
- auto_sync: false,
232
- parallel_operations: 4,
233
- },
234
- };
235
-
233
+ const defaultGlobal = this.getDefaultGlobalConfig();
236
234
  await this.saveGlobal(defaultGlobal);
237
235
  }
238
236
 
@@ -252,7 +250,7 @@ export class ConfigManager {
252
250
  }
253
251
 
254
252
  /**
255
- * Get configuration value by path (e.g., 'sync.auto_sync')
253
+ * Get configuration value by path (e.g., 'sync.move_detection_threshold')
256
254
  */
257
255
  async getValue(keyPath: string): Promise<any> {
258
256
  const config = await this.getMerged();
@@ -311,21 +309,6 @@ export class ConfigManager {
311
309
  }
312
310
  }
313
311
 
314
- if (config.sync?.prompt_threshold !== undefined) {
315
- if (
316
- config.sync.prompt_threshold < 0 ||
317
- config.sync.prompt_threshold > 1
318
- ) {
319
- errors.push("prompt_threshold must be between 0 and 1");
320
- }
321
- }
322
-
323
- if (config.sync?.parallel_operations !== undefined) {
324
- if (config.sync.parallel_operations < 1) {
325
- errors.push("parallel_operations must be at least 1");
326
- }
327
- }
328
-
329
312
  return {
330
313
  valid: errors.length === 0,
331
314
  errors,
package/src/core/index.ts CHANGED
@@ -1,5 +1,5 @@
1
- // Core sync components
2
1
  export * from "./snapshot";
3
2
  export * from "./change-detection";
4
3
  export * from "./move-detection";
5
4
  export * from "./sync-engine";
5
+ export * from "./config";
@@ -1,22 +1,24 @@
1
- import { SyncSnapshot, MoveCandidate, SnapshotFileEntry } from "../types";
2
- import { calculateContentHash, isTextFile } from "../utils";
1
+ import { SyncSnapshot, MoveCandidate } from "../types";
2
+ import { isTextFile } from "../utils";
3
3
  import { stringSimilarity } from "../utils/string-similarity";
4
- import { DetectedChange, ChangeType } from "./change-detection";
4
+ import { ChangeType, DetectedChange } from "../types";
5
5
 
6
6
  /**
7
7
  * Simplified move detection engine
8
8
  */
9
9
  export class MoveDetector {
10
- // Single threshold: either it's a move or it's not
11
- private static readonly MOVE_THRESHOLD = 0.7;
10
+ private readonly moveThreshold: number;
11
+
12
+ constructor(moveThreshold: number = 0.7) {
13
+ this.moveThreshold = moveThreshold;
14
+ }
12
15
 
13
16
  /**
14
17
  * Detect file moves by analyzing deleted and created files
15
18
  */
16
19
  async detectMoves(
17
20
  changes: DetectedChange[],
18
- snapshot: SyncSnapshot,
19
- rootPath: string
21
+ snapshot: SyncSnapshot
20
22
  ): Promise<{ moves: MoveCandidate[]; remainingChanges: DetectedChange[] }> {
21
23
  const deletedFiles = changes.filter(
22
24
  (c) => !c.localContent && c.changeType === ChangeType.LOCAL_ONLY
@@ -53,7 +55,7 @@ export class MoveDetector {
53
55
  deletedFile.path
54
56
  );
55
57
 
56
- if (similarity >= MoveDetector.MOVE_THRESHOLD) {
58
+ if (similarity >= this.moveThreshold) {
57
59
  if (!bestMatch || similarity > bestMatch.similarity) {
58
60
  bestMatch = { file: createdFile, similarity };
59
61
  }
@@ -11,6 +11,7 @@ import {
11
11
  SnapshotDirectoryEntry,
12
12
  } from "../types";
13
13
  import { pathExists, ensureDirectoryExists } from "../utils";
14
+ import { out } from "../utils/output";
14
15
 
15
16
  /**
16
17
  * Manages sync snapshots for local state tracking
@@ -57,7 +58,7 @@ export class SnapshotManager {
57
58
 
58
59
  return this.deserializeSnapshot(serializable);
59
60
  } catch (error) {
60
- console.warn(`Failed to load snapshot: ${error}`);
61
+ out.taskLine(`Failed to load snapshot: ${error}`);
61
62
  return null;
62
63
  }
63
64
  }
@@ -189,17 +190,6 @@ export class SnapshotManager {
189
190
  };
190
191
  }
191
192
 
192
- /**
193
- * Backup current snapshot
194
- */
195
- async backup(): Promise<void> {
196
- const snapshotPath = this.getSnapshotPath();
197
- if (await pathExists(snapshotPath)) {
198
- const backupPath = `${snapshotPath}.backup.${Date.now()}`;
199
- await fs.copyFile(snapshotPath, backupPath);
200
- }
201
- }
202
-
203
193
  /**
204
194
  * Validate snapshot integrity
205
195
  */