freestyle-sync 0.1.10 → 0.1.11
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 +49 -42
- package/dist/src/main.d.ts +46 -0
- package/dist/src/main.js +74 -6
- package/dist/src/plugin-api.d.ts +127 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,46 +1,12 @@
|
|
|
1
1
|
# Freestyle Sync
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Offload any development environment to a VM with 1 command. Authentication, agent context, and dependencies are automatically handled.
|
|
4
4
|
|
|
5
5
|
```
|
|
6
6
|
npx freestyle-sync
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
```sh
|
|
12
|
-
npx freestyle-sync --provider apple-container --apple-container-image ubuntu:24.04
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Use `--vm-id <container-name-or-id>` to reuse an existing Apple container. Snapshot caching is only available with the Freestyle provider.
|
|
16
|
-
|
|
17
|
-
Use the SDK when embedding sync inside another CLI/app (no required `freestyle-sync.config.ts` or cache file):
|
|
18
|
-
|
|
19
|
-
```ts
|
|
20
|
-
import { defineConfig, sync, type SyncCache } from "freestyle-sync";
|
|
21
|
-
import { gitAuthPlugin } from "@freestyle-sync/auth-git";
|
|
22
|
-
import { nodeNpmPlugin } from "@freestyle-sync/node-npm";
|
|
23
|
-
|
|
24
|
-
let cache: SyncCache | undefined;
|
|
25
|
-
|
|
26
|
-
const result = await sync({
|
|
27
|
-
config: defineConfig({
|
|
28
|
-
plugins: [gitAuthPlugin(), nodeNpmPlugin()],
|
|
29
|
-
}),
|
|
30
|
-
options: {
|
|
31
|
-
projectRoot: process.cwd(),
|
|
32
|
-
autoSsh: false,
|
|
33
|
-
},
|
|
34
|
-
cache,
|
|
35
|
-
onCacheUpdate(nextCache) {
|
|
36
|
-
cache = nextCache;
|
|
37
|
-
},
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
console.log("synced runtime", result.vmId);
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
freestyle-sync creates `freestyle-sync.config.mjs` on first run and installs the config dependencies into your project as dev dependencies. Remove the generated config or dependencies if you want to reset it later.
|
|
9
|
+
On it's first run, freestyle-sync creates `freestyle-sync.config.mjs` and configures a large set of default plugins. Plugins help sync parts of your development environment that require more complex logic than just copying the current directory's files.
|
|
44
10
|
|
|
45
11
|
```js
|
|
46
12
|
import { defineConfig } from "freestyle-sync";
|
|
@@ -57,8 +23,11 @@ import { githubCliAuthPlugin } from "@freestyle-sync/auth-github-cli";
|
|
|
57
23
|
import { npmAuthPlugin } from "@freestyle-sync/auth-npm";
|
|
58
24
|
import { sshAuthPlugin } from "@freestyle-sync/auth-ssh";
|
|
59
25
|
import { yarnAuthPlugin } from "@freestyle-sync/auth-yarn";
|
|
26
|
+
import { nextjsPlugin } from "@freestyle-sync/nextjs";
|
|
60
27
|
import { nodeNpmPlugin } from "@freestyle-sync/node-npm";
|
|
28
|
+
import { rustPlugin } from "@freestyle-sync/rust";
|
|
61
29
|
import { shellHistoryPlugin } from "@freestyle-sync/shell-history";
|
|
30
|
+
import { vitePlugin } from "@freestyle-sync/vite";
|
|
62
31
|
|
|
63
32
|
export default defineConfig({
|
|
64
33
|
plugins: [
|
|
@@ -73,6 +42,9 @@ export default defineConfig({
|
|
|
73
42
|
azureAuthPlugin(),
|
|
74
43
|
gcloudAuthPlugin(),
|
|
75
44
|
nodeNpmPlugin(),
|
|
45
|
+
nextjsPlugin(),
|
|
46
|
+
vitePlugin(),
|
|
47
|
+
rustPlugin(),
|
|
76
48
|
claudeAgentPlugin(),
|
|
77
49
|
codexAgentPlugin(),
|
|
78
50
|
copilotAgentPlugin(),
|
|
@@ -81,7 +53,7 @@ export default defineConfig({
|
|
|
81
53
|
});
|
|
82
54
|
```
|
|
83
55
|
|
|
84
|
-
|
|
56
|
+
You can exclude folders and include additional local paths. Include paths may point outside the project directory; they are copied into the remote project at the configured relative target.
|
|
85
57
|
|
|
86
58
|
```js
|
|
87
59
|
export default defineConfig({
|
|
@@ -90,15 +62,50 @@ export default defineConfig({
|
|
|
90
62
|
include: [
|
|
91
63
|
{ source: "../shared-config", target: "shared-config" },
|
|
92
64
|
],
|
|
93
|
-
}
|
|
94
|
-
plugins: [
|
|
95
|
-
nodeNpmPlugin(),
|
|
96
|
-
],
|
|
65
|
+
}
|
|
97
66
|
});
|
|
98
67
|
```
|
|
99
68
|
|
|
100
|
-
|
|
69
|
+
The default Node/framework/runtime plugins avoid uploading generated dependency and build output folders:
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
nodeNpmPlugin() // excludes node_modules and installs frozen dependencies remotely
|
|
73
|
+
nextjsPlugin() // excludes .next
|
|
74
|
+
vitePlugin() // excludes dist, build, and .vite
|
|
75
|
+
rustPlugin() // excludes target, installs Rust/Cargo, and runs cargo fetch
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
You can keep uploading those generated folders when needed:
|
|
101
79
|
|
|
102
80
|
```js
|
|
103
81
|
nodeNpmPlugin({ syncNodeModules: true })
|
|
82
|
+
nextjsPlugin({ syncNextDir: true })
|
|
83
|
+
vitePlugin({ syncBuildOutput: true })
|
|
84
|
+
rustPlugin({ syncTargetDir: true })
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
If you're integrating freestyle-sync into your own toolchain, you can use it as an sdk and take full control over how configuration and cache is stored.
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import { defineConfig, sync, type SyncCache } from "freestyle-sync";
|
|
91
|
+
import { gitAuthPlugin } from "@freestyle-sync/auth-git";
|
|
92
|
+
import { nodeNpmPlugin } from "@freestyle-sync/node-npm";
|
|
93
|
+
|
|
94
|
+
let cache: SyncCache | undefined;
|
|
95
|
+
|
|
96
|
+
const result = await sync({
|
|
97
|
+
config: defineConfig({
|
|
98
|
+
plugins: [gitAuthPlugin(), nodeNpmPlugin()],
|
|
99
|
+
}),
|
|
100
|
+
options: {
|
|
101
|
+
projectRoot: process.cwd(),
|
|
102
|
+
autoSsh: false,
|
|
103
|
+
},
|
|
104
|
+
cache,
|
|
105
|
+
onCacheUpdate(nextCache) {
|
|
106
|
+
cache = nextCache;
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
console.log("synced runtime", result.vmId);
|
|
104
111
|
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "dotenv/config";
|
|
3
|
+
import type { CliOptions, PushvmConfig, VmProviderName } from "./plugin-api.ts";
|
|
4
|
+
export * from "./plugin-api.ts";
|
|
5
|
+
type FileKind = "file" | "symlink";
|
|
6
|
+
type FileDigest = {
|
|
7
|
+
hash: string;
|
|
8
|
+
kind: FileKind;
|
|
9
|
+
mode: number;
|
|
10
|
+
size: number;
|
|
11
|
+
};
|
|
12
|
+
type CacheFile = {
|
|
13
|
+
version: number;
|
|
14
|
+
projectRoot: string;
|
|
15
|
+
remoteProjectDir: string;
|
|
16
|
+
provider?: VmProviderName;
|
|
17
|
+
vmId?: string;
|
|
18
|
+
snapshotId?: string;
|
|
19
|
+
projectFiles: Record<string, FileDigest>;
|
|
20
|
+
contextFiles: Record<string, FileDigest>;
|
|
21
|
+
snapshotProjectFiles?: Record<string, FileDigest>;
|
|
22
|
+
snapshotContextFiles?: Record<string, FileDigest>;
|
|
23
|
+
envHash?: string;
|
|
24
|
+
snapshotEnvHash?: string;
|
|
25
|
+
updatedAt?: string;
|
|
26
|
+
};
|
|
27
|
+
type PluginPreferences = {
|
|
28
|
+
version: number;
|
|
29
|
+
disabledPlugins: string[];
|
|
30
|
+
updatedAt?: string;
|
|
31
|
+
};
|
|
32
|
+
export type SyncCache = CacheFile;
|
|
33
|
+
export type SyncPluginPreferences = PluginPreferences;
|
|
34
|
+
export type SyncSdkOptions = {
|
|
35
|
+
config: PushvmConfig;
|
|
36
|
+
options?: Partial<CliOptions>;
|
|
37
|
+
cache?: SyncCache;
|
|
38
|
+
pluginPreferences?: SyncPluginPreferences;
|
|
39
|
+
onCacheUpdate?(cache: SyncCache): Promise<void> | void;
|
|
40
|
+
};
|
|
41
|
+
export type SyncSdkResult = {
|
|
42
|
+
vmId?: string;
|
|
43
|
+
cache: SyncCache;
|
|
44
|
+
snapshotId?: string;
|
|
45
|
+
};
|
|
46
|
+
export declare function sync(sdkOptions: SyncSdkOptions): Promise<SyncSdkResult>;
|
package/dist/src/main.js
CHANGED
|
@@ -47,8 +47,11 @@ const DEFAULT_CONFIG_DEPENDENCIES = [
|
|
|
47
47
|
{ name: "@freestyle-sync/auth-npm", spec: "@freestyle-sync/auth-npm@latest" },
|
|
48
48
|
{ name: "@freestyle-sync/auth-ssh", spec: "@freestyle-sync/auth-ssh@latest" },
|
|
49
49
|
{ name: "@freestyle-sync/auth-yarn", spec: "@freestyle-sync/auth-yarn@latest" },
|
|
50
|
+
{ name: "@freestyle-sync/nextjs", spec: "@freestyle-sync/nextjs@latest" },
|
|
50
51
|
{ name: "@freestyle-sync/node-npm", spec: "@freestyle-sync/node-npm@latest" },
|
|
52
|
+
{ name: "@freestyle-sync/rust", spec: "@freestyle-sync/rust@latest" },
|
|
51
53
|
{ name: "@freestyle-sync/shell-history", spec: "@freestyle-sync/shell-history@latest" },
|
|
54
|
+
{ name: "@freestyle-sync/vite", spec: "@freestyle-sync/vite@latest" },
|
|
52
55
|
];
|
|
53
56
|
const pluginUtils = {
|
|
54
57
|
checkedExec,
|
|
@@ -375,8 +378,11 @@ import { githubCliAuthPlugin } from "@freestyle-sync/auth-github-cli";
|
|
|
375
378
|
import { npmAuthPlugin } from "@freestyle-sync/auth-npm";
|
|
376
379
|
import { sshAuthPlugin } from "@freestyle-sync/auth-ssh";
|
|
377
380
|
import { yarnAuthPlugin } from "@freestyle-sync/auth-yarn";
|
|
381
|
+
import { nextjsPlugin } from "@freestyle-sync/nextjs";
|
|
378
382
|
import { nodeNpmPlugin } from "@freestyle-sync/node-npm";
|
|
383
|
+
import { rustPlugin } from "@freestyle-sync/rust";
|
|
379
384
|
import { shellHistoryPlugin } from "@freestyle-sync/shell-history";
|
|
385
|
+
import { vitePlugin } from "@freestyle-sync/vite";
|
|
380
386
|
import { defineConfig } from "freestyle-sync";
|
|
381
387
|
|
|
382
388
|
export default defineConfig({
|
|
@@ -392,6 +398,9 @@ export default defineConfig({
|
|
|
392
398
|
azureAuthPlugin(),
|
|
393
399
|
gcloudAuthPlugin(),
|
|
394
400
|
nodeNpmPlugin(),
|
|
401
|
+
nextjsPlugin(),
|
|
402
|
+
vitePlugin(),
|
|
403
|
+
rustPlugin(),
|
|
395
404
|
claudeAgentPlugin(),
|
|
396
405
|
codexAgentPlugin(),
|
|
397
406
|
copilotAgentPlugin(),
|
|
@@ -414,8 +423,11 @@ import { githubCliAuthPlugin } from "@freestyle-sync/auth-github-cli";
|
|
|
414
423
|
import { npmAuthPlugin } from "@freestyle-sync/auth-npm";
|
|
415
424
|
import { sshAuthPlugin } from "@freestyle-sync/auth-ssh";
|
|
416
425
|
import { yarnAuthPlugin } from "@freestyle-sync/auth-yarn";
|
|
426
|
+
import { nextjsPlugin } from "@freestyle-sync/nextjs";
|
|
417
427
|
import { nodeNpmPlugin } from "@freestyle-sync/node-npm";
|
|
428
|
+
import { rustPlugin } from "@freestyle-sync/rust";
|
|
418
429
|
import { shellHistoryPlugin } from "@freestyle-sync/shell-history";
|
|
430
|
+
import { vitePlugin } from "@freestyle-sync/vite";
|
|
419
431
|
import { defineConfig } from "freestyle-sync";
|
|
420
432
|
|
|
421
433
|
export default defineConfig({
|
|
@@ -431,6 +443,9 @@ export default defineConfig({
|
|
|
431
443
|
azureAuthPlugin(),
|
|
432
444
|
gcloudAuthPlugin(),
|
|
433
445
|
nodeNpmPlugin(),
|
|
446
|
+
nextjsPlugin(),
|
|
447
|
+
vitePlugin(),
|
|
448
|
+
rustPlugin(),
|
|
434
449
|
claudeAgentPlugin(),
|
|
435
450
|
codexAgentPlugin(),
|
|
436
451
|
copilotAgentPlugin(),
|
|
@@ -1581,6 +1596,8 @@ async function runInstall(vm, projectRoot, remoteProjectDir) {
|
|
|
1581
1596
|
await checkedExec(vm, `cd ${shellQuote(remoteProjectDir)} && ${installCommand}`, 20 * 60 * 1000);
|
|
1582
1597
|
}
|
|
1583
1598
|
async function detectInstallCommand(projectRoot) {
|
|
1599
|
+
if (await exists(path.join(projectRoot, "bun.lock")) || await exists(path.join(projectRoot, "bun.lockb")))
|
|
1600
|
+
return "bun install --frozen-lockfile";
|
|
1584
1601
|
if (await exists(path.join(projectRoot, "pnpm-lock.yaml")))
|
|
1585
1602
|
return "corepack enable && pnpm install --frozen-lockfile";
|
|
1586
1603
|
if (await exists(path.join(projectRoot, "yarn.lock")))
|
|
@@ -1648,11 +1665,13 @@ async function uploadArchiveInChunks(vm, vmId, archivePath, remoteArchivePath, l
|
|
|
1648
1665
|
const width = String(chunkCount - 1).length;
|
|
1649
1666
|
const canRenderInlineProgress = process.stdout.isTTY;
|
|
1650
1667
|
const logEvery = Math.max(1, Math.ceil(chunkCount / 4));
|
|
1668
|
+
const chunkManifest = [];
|
|
1651
1669
|
let index = 0;
|
|
1652
1670
|
for await (const chunk of createReadStream(archivePath, { highWaterMark: ARCHIVE_CHUNK_BYTES })) {
|
|
1653
|
-
const chunkName = `${String(index).padStart(width, "0")}.chunk
|
|
1671
|
+
const chunkName = `${String(index).padStart(width, "0")}.chunk`;
|
|
1654
1672
|
const content = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
1655
|
-
|
|
1673
|
+
chunkManifest.push(`${chunkName} ${content.length}`);
|
|
1674
|
+
await vm.fs.writeFile(`${chunkDir}/${chunkName}`, content);
|
|
1656
1675
|
const uploadedChunks = index + 1;
|
|
1657
1676
|
if (chunkCount > 1) {
|
|
1658
1677
|
const progressMessage = `VM ${vmId}: uploaded ${uploadedChunks}/${chunkCount} ${label} archive chunks`;
|
|
@@ -1668,14 +1687,63 @@ async function uploadArchiveInChunks(vm, vmId, archivePath, remoteArchivePath, l
|
|
|
1668
1687
|
}
|
|
1669
1688
|
index += 1;
|
|
1670
1689
|
}
|
|
1690
|
+
if (archiveSize > 0) {
|
|
1691
|
+
await vm.fs.writeTextFile(`${chunkDir}/manifest`, `${chunkManifest.join("\n")}\n`);
|
|
1692
|
+
}
|
|
1671
1693
|
await checkedExec(vm, archiveSize === 0
|
|
1672
1694
|
? `: > ${shellQuote(remoteArchivePath)} && rm -rf ${shellQuote(chunkDir)}`
|
|
1673
1695
|
: [
|
|
1674
1696
|
"set -e",
|
|
1675
|
-
`
|
|
1676
|
-
`
|
|
1677
|
-
`
|
|
1697
|
+
`chunk_dir=${shellQuote(chunkDir)}`,
|
|
1698
|
+
`remote_archive=${shellQuote(remoteArchivePath)}`,
|
|
1699
|
+
`manifest="$chunk_dir/manifest"`,
|
|
1700
|
+
"deadline=$(( $(date +%s) + 60 ))",
|
|
1701
|
+
"while :; do",
|
|
1702
|
+
" validation_error=",
|
|
1703
|
+
" validated_chunks=0",
|
|
1704
|
+
" if [ ! -f \"$manifest\" ]; then",
|
|
1705
|
+
" validation_error='missing chunk manifest'",
|
|
1706
|
+
" else",
|
|
1707
|
+
" actual_chunks=$(find \"$chunk_dir\" -maxdepth 1 -type f -name '*.chunk' | wc -l | tr -d '[:space:]')",
|
|
1708
|
+
` if [ "$actual_chunks" != ${shellQuote(String(chunkCount))} ]; then`,
|
|
1709
|
+
` validation_error="expected ${chunkCount} chunks, found $actual_chunks"`,
|
|
1710
|
+
" else",
|
|
1711
|
+
" while IFS=' ' read -r chunk_name expected_size; do",
|
|
1712
|
+
" [ -n \"$chunk_name\" ] || continue",
|
|
1713
|
+
" chunk_path=\"$chunk_dir/$chunk_name\"",
|
|
1714
|
+
" if [ ! -f \"$chunk_path\" ]; then",
|
|
1715
|
+
" validation_error=\"missing chunk $chunk_name\"",
|
|
1716
|
+
" break",
|
|
1717
|
+
" fi",
|
|
1718
|
+
" actual_chunk_size=$(wc -c < \"$chunk_path\" | tr -d '[:space:]')",
|
|
1719
|
+
" if [ \"$actual_chunk_size\" != \"$expected_size\" ]; then",
|
|
1720
|
+
" validation_error=\"chunk $chunk_name expected $expected_size bytes, got $actual_chunk_size\"",
|
|
1721
|
+
" break",
|
|
1722
|
+
" fi",
|
|
1723
|
+
" validated_chunks=$((validated_chunks + 1))",
|
|
1724
|
+
" done < \"$manifest\"",
|
|
1725
|
+
` if [ "$validated_chunks" != ${shellQuote(String(chunkCount))} ] && [ -z "$validation_error" ]; then`,
|
|
1726
|
+
` validation_error="expected ${chunkCount} manifest entries, found $validated_chunks"`,
|
|
1727
|
+
" fi",
|
|
1728
|
+
" fi",
|
|
1729
|
+
" fi",
|
|
1730
|
+
" if [ -z \"$validation_error\" ]; then",
|
|
1731
|
+
" break",
|
|
1732
|
+
" fi",
|
|
1733
|
+
" if [ \"$(date +%s)\" -ge \"$deadline\" ]; then",
|
|
1734
|
+
` rm -f ${shellQuote(remoteArchivePath)}`,
|
|
1735
|
+
` rm -rf ${shellQuote(chunkDir)}`,
|
|
1736
|
+
` echo ${shellQuote(`archive chunk validation failed for ${label}`)} >&2`,
|
|
1737
|
+
" echo \"$validation_error\" >&2",
|
|
1738
|
+
" exit 1",
|
|
1739
|
+
" fi",
|
|
1740
|
+
" sleep 1",
|
|
1678
1741
|
"done",
|
|
1742
|
+
`rm -f ${shellQuote(remoteArchivePath)}`,
|
|
1743
|
+
"while IFS=' ' read -r chunk_name expected_size; do",
|
|
1744
|
+
" [ -n \"$chunk_name\" ] || continue",
|
|
1745
|
+
" cat \"$chunk_dir/$chunk_name\" >> \"$remote_archive\"",
|
|
1746
|
+
"done < \"$manifest\"",
|
|
1679
1747
|
`actual_size=$(wc -c < ${shellQuote(remoteArchivePath)} | tr -d '[:space:]')`,
|
|
1680
1748
|
`actual_hash=$(sha256sum ${shellQuote(remoteArchivePath)} | awk '{print $1}')`,
|
|
1681
1749
|
`if [ "$actual_size" != ${shellQuote(String(archiveSize))} ] || [ "$actual_hash" != ${shellQuote(archiveHash)} ]; then`,
|
|
@@ -1686,7 +1754,7 @@ async function uploadArchiveInChunks(vm, vmId, archivePath, remoteArchivePath, l
|
|
|
1686
1754
|
" exit 1",
|
|
1687
1755
|
"fi",
|
|
1688
1756
|
`rm -rf ${shellQuote(chunkDir)}`,
|
|
1689
|
-
].join("\n"));
|
|
1757
|
+
].join("\n"), 5 * 60 * MS_PER_SECOND);
|
|
1690
1758
|
}
|
|
1691
1759
|
async function mkdirRemote(vm, directories) {
|
|
1692
1760
|
for (const chunk of chunkArray(directories, 50)) {
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
export type VmProviderName = "freestyle" | "apple-container";
|
|
2
|
+
export type CliOptions = {
|
|
3
|
+
projectRoot: string;
|
|
4
|
+
cachePath: string;
|
|
5
|
+
remoteProjectDir: string;
|
|
6
|
+
provider: VmProviderName;
|
|
7
|
+
name: string;
|
|
8
|
+
vmId?: string;
|
|
9
|
+
appleContainerImage: string;
|
|
10
|
+
idleTimeoutSeconds?: number;
|
|
11
|
+
yes: boolean;
|
|
12
|
+
dryRun: boolean;
|
|
13
|
+
disablePlugins: string[];
|
|
14
|
+
enablePlugins: string[];
|
|
15
|
+
resetPluginPrefs: boolean;
|
|
16
|
+
listPlugins: boolean;
|
|
17
|
+
includeAuth: boolean;
|
|
18
|
+
includeAgentContext: boolean;
|
|
19
|
+
includeGitDir: boolean;
|
|
20
|
+
includeAllCopilotWorkspaces: boolean;
|
|
21
|
+
snapshot: boolean;
|
|
22
|
+
skipSync: boolean;
|
|
23
|
+
install: boolean;
|
|
24
|
+
autoSsh: boolean;
|
|
25
|
+
envKeys: string[];
|
|
26
|
+
};
|
|
27
|
+
export type ContextCandidate = {
|
|
28
|
+
source: string;
|
|
29
|
+
remoteRoot: string;
|
|
30
|
+
label: string;
|
|
31
|
+
sensitive: boolean;
|
|
32
|
+
preferenceKey: string;
|
|
33
|
+
promptLabel: string;
|
|
34
|
+
};
|
|
35
|
+
export type RemoteVm = {
|
|
36
|
+
exec(args: {
|
|
37
|
+
command: string;
|
|
38
|
+
timeoutMs?: number;
|
|
39
|
+
}): Promise<{
|
|
40
|
+
stdout?: string | null;
|
|
41
|
+
stderr?: string | null;
|
|
42
|
+
statusCode?: number | null;
|
|
43
|
+
}>;
|
|
44
|
+
fs: {
|
|
45
|
+
writeFile(path: string, content: Buffer): Promise<void>;
|
|
46
|
+
writeTextFile(path: string, content: string): Promise<void>;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
export type UploadArchiveInChunks = (vm: RemoteVm, vmId: string, archivePath: string, remoteArchivePath: string, label: string) => Promise<void>;
|
|
50
|
+
export type ExecFileAsync = (file: string, args: string[]) => Promise<{
|
|
51
|
+
stdout: string;
|
|
52
|
+
stderr: string;
|
|
53
|
+
}>;
|
|
54
|
+
export type PushvmPluginUtils = {
|
|
55
|
+
checkedExec(vm: RemoteVm, command: string, timeoutMs?: number): Promise<{
|
|
56
|
+
stdout?: string | null;
|
|
57
|
+
stderr?: string | null;
|
|
58
|
+
statusCode?: number | null;
|
|
59
|
+
}>;
|
|
60
|
+
createTar(args: string[]): Promise<void>;
|
|
61
|
+
uploadArchiveInChunks: UploadArchiveInChunks;
|
|
62
|
+
execFileAsync: ExecFileAsync;
|
|
63
|
+
shellQuote(value: string): string;
|
|
64
|
+
md5(value: string): string;
|
|
65
|
+
delay(ms: number): Promise<void>;
|
|
66
|
+
};
|
|
67
|
+
export type PushvmPluginContext = {
|
|
68
|
+
options: CliOptions;
|
|
69
|
+
utils: PushvmPluginUtils;
|
|
70
|
+
};
|
|
71
|
+
export type RemoteHookContext = PushvmPluginContext & {
|
|
72
|
+
vm: RemoteVm;
|
|
73
|
+
vmId: string;
|
|
74
|
+
};
|
|
75
|
+
export type EditorScheme = string;
|
|
76
|
+
export type EditorHookContext = RemoteHookContext & {
|
|
77
|
+
scheme: EditorScheme;
|
|
78
|
+
remoteWorkspaceUri: string;
|
|
79
|
+
};
|
|
80
|
+
export type ConnectHookContext = RemoteHookContext & {
|
|
81
|
+
contextCandidates: ContextCandidate[];
|
|
82
|
+
runBeforeOpenRemoteEditor(args: {
|
|
83
|
+
scheme: EditorScheme;
|
|
84
|
+
remoteWorkspaceUri: string;
|
|
85
|
+
}): Promise<string[]>;
|
|
86
|
+
runAfterOpenRemoteEditor(args: {
|
|
87
|
+
scheme: EditorScheme;
|
|
88
|
+
remoteWorkspaceUri: string;
|
|
89
|
+
}): Promise<string[]>;
|
|
90
|
+
};
|
|
91
|
+
export type ProjectSyncInclude = string | {
|
|
92
|
+
source: string;
|
|
93
|
+
target?: string;
|
|
94
|
+
};
|
|
95
|
+
export type ProjectSyncConfig = {
|
|
96
|
+
exclude?: string[];
|
|
97
|
+
include?: ProjectSyncInclude[];
|
|
98
|
+
};
|
|
99
|
+
export type PushvmPlugin = {
|
|
100
|
+
name: string;
|
|
101
|
+
collectEnvironment?(context: PushvmPluginContext): Record<string, string>;
|
|
102
|
+
discoverContextCandidates?(context: PushvmPluginContext): Promise<ContextCandidate[]> | ContextCandidate[];
|
|
103
|
+
configureProjectSync?(context: PushvmPluginContext): Promise<ProjectSyncConfig | void> | ProjectSyncConfig | void;
|
|
104
|
+
shouldSkipContextDirectory?(relativePath: string, name: string): boolean;
|
|
105
|
+
isProtectedRemotePath?(remotePath: string): boolean;
|
|
106
|
+
afterProjectSync?(context: RemoteHookContext): Promise<void> | void;
|
|
107
|
+
afterContextSync?(context: RemoteHookContext & {
|
|
108
|
+
changedRemotePaths: string[];
|
|
109
|
+
}): Promise<void> | void;
|
|
110
|
+
beforeSnapshot?(context: RemoteHookContext): Promise<void> | void;
|
|
111
|
+
afterSync?(context: RemoteHookContext & {
|
|
112
|
+
contextCandidates: ContextCandidate[];
|
|
113
|
+
}): Promise<string[] | void> | string[] | void;
|
|
114
|
+
connect?(context: ConnectHookContext): Promise<boolean | void> | boolean | void;
|
|
115
|
+
beforeOpenRemoteEditor?(context: EditorHookContext & {
|
|
116
|
+
contextCandidates: ContextCandidate[];
|
|
117
|
+
}): Promise<string[] | void> | string[] | void;
|
|
118
|
+
afterOpenRemoteEditor?(context: EditorHookContext & {
|
|
119
|
+
contextCandidates: ContextCandidate[];
|
|
120
|
+
}): Promise<string[] | void> | string[] | void;
|
|
121
|
+
};
|
|
122
|
+
export type PushvmConfig = {
|
|
123
|
+
plugins: PushvmPlugin[];
|
|
124
|
+
sync?: ProjectSyncConfig;
|
|
125
|
+
};
|
|
126
|
+
export declare function definePlugin(plugin: PushvmPlugin): PushvmPlugin;
|
|
127
|
+
export declare function defineConfig(config: PushvmConfig): PushvmConfig;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "freestyle-sync",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/src/main.js",
|
|
6
6
|
"exports": {
|
|
@@ -25,7 +25,9 @@
|
|
|
25
25
|
"publish": "npm run check && npm run build && npm run publish:workspaces && npm run publish:root",
|
|
26
26
|
"publish:root": "node scripts/publish-root.mjs",
|
|
27
27
|
"publish:workspaces": "node scripts/publish-workspaces.mjs",
|
|
28
|
-
"start": "node src/main.ts"
|
|
28
|
+
"start": "node src/main.ts",
|
|
29
|
+
"version:patch": "node scripts/version-workspaces.mjs patch",
|
|
30
|
+
"version:workspaces": "node scripts/version-workspaces.mjs"
|
|
29
31
|
},
|
|
30
32
|
"dependencies": {
|
|
31
33
|
"dotenv": "^17.4.2",
|