freestyle-sync 0.1.4 → 0.1.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.
@@ -1,65 +0,0 @@
1
- import { stat } from "node:fs/promises";
2
- import { homedir } from "node:os";
3
- import path from "node:path";
4
- import { definePlugin } from "../../../src/plugin-api.js";
5
- export function shellHistoryPlugin() {
6
- return definePlugin({
7
- name: "@freestyle-sync/shell-history",
8
- async discoverContextCandidates() {
9
- const item = {
10
- source: path.join(homedir(), ".zsh_history"),
11
- remoteRoot: "/root/.zsh_history",
12
- label: "zsh history",
13
- sensitive: true,
14
- preferenceKey: "context:zsh-history",
15
- promptLabel: "zsh history",
16
- };
17
- return await exists(item.source) ? [item] : [];
18
- },
19
- async afterContextSync({ vm, changedRemotePaths, utils }) {
20
- if (!changedRemotePaths.includes("/root/.zsh_history"))
21
- return;
22
- await seedRemoteShellHistory(vm, utils.checkedExec);
23
- },
24
- async afterSync({ vm, utils }) {
25
- await seedRemoteShellHistory(vm, utils.checkedExec);
26
- },
27
- });
28
- }
29
- async function seedRemoteShellHistory(vm, checkedExec) {
30
- await checkedExec(vm, `
31
- set -eu
32
- if [ ! -f /root/.zsh_history ]; then
33
- exit 0
34
- fi
35
- node <<'NODE'
36
- const fs = require('node:fs');
37
-
38
- const zshHistory = '/root/.zsh_history';
39
- const bashHistory = '/root/.bash_history';
40
- const newline = String.fromCharCode(10);
41
- const raw = fs.readFileSync(zshHistory, 'utf8');
42
- const commands = raw
43
- .split(newline)
44
- .map((line) => {
45
- const extended = line.match(/^: [0-9]+:[0-9]+;(.*)$/);
46
- return extended ? extended[1] : line;
47
- })
48
- .map((line) => line.trimEnd())
49
- .filter((line) => line.length > 0);
50
-
51
- fs.writeFileSync(bashHistory, commands.join(newline) + (commands.length > 0 ? newline : ''), { mode: 0o600 });
52
- NODE
53
- chown root:root /root/.zsh_history /root/.bash_history 2>/dev/null || true
54
- chmod 600 /root/.zsh_history /root/.bash_history 2>/dev/null || true
55
- `);
56
- }
57
- async function exists(filePath) {
58
- try {
59
- await stat(filePath);
60
- return true;
61
- }
62
- catch {
63
- return false;
64
- }
65
- }
@@ -1,160 +0,0 @@
1
- import { execFile } from "node:child_process";
2
- import { promisify } from "node:util";
3
- import { freestyle } from "freestyle";
4
- import { definePlugin } from "../../../src/plugin-api.js";
5
- const execFileAsync = promisify(execFile);
6
- export function vscodePlugin() {
7
- return definePlugin({
8
- name: "@freestyle-sync/vscode",
9
- async beforeSnapshot({ vm, utils }) {
10
- await warmVsCodeServerCache(vm, utils.shellQuote, utils.checkedExec).catch((error) => {
11
- console.warn(`VS Code Server cache warm-up skipped: ${error instanceof Error ? error.message : String(error)}`);
12
- });
13
- },
14
- async connect(context) {
15
- const editorScheme = await detectEditorScheme();
16
- if (!editorScheme)
17
- return false;
18
- await openRemoteEditor(context, editorScheme);
19
- return true;
20
- },
21
- });
22
- }
23
- async function warmVsCodeServerCache(vm, shellQuote, checkedExec) {
24
- const commit = await localVsCodeCommit();
25
- if (!commit)
26
- return;
27
- const script = `
28
- set -eu
29
- commit=${shellQuote(commit)}
30
- machine=$(uname -m)
31
- case "$machine" in
32
- x86_64|amd64) arch=x64 ;;
33
- aarch64|arm64) arch=arm64 ;;
34
- armv7l|armv8l) arch=armhf ;;
35
- *) echo "unsupported VS Code Server architecture: $machine" >&2; exit 0 ;;
36
- esac
37
- bin_dir=/root/.vscode-server/bin/$commit
38
- cli_server_dir=/root/.vscode-server/cli/servers/Stable-$commit/server
39
- if { [ -x "$bin_dir/server.sh" ] || [ -x "$bin_dir/bin/code-server" ]; } && [ -x "$cli_server_dir/bin/code-server" ]; then
40
- echo "VS Code Server $commit already cached"
41
- exit 0
42
- fi
43
- tmp=$(mktemp -d /tmp/vmpush-vscode-server.XXXXXX)
44
- trap 'rm -rf "$tmp"' EXIT
45
- url=https://update.code.visualstudio.com/commit:$commit/server-linux-$arch/stable
46
- archive=$tmp/server.tgz
47
- if command -v curl >/dev/null 2>&1; then
48
- curl -fsSL "$url" -o "$archive"
49
- elif command -v wget >/dev/null 2>&1; then
50
- wget -qO "$archive" "$url"
51
- else
52
- echo "curl or wget is required to cache VS Code Server" >&2
53
- exit 0
54
- fi
55
- tar -xzf "$archive" -C "$tmp"
56
- extracted=$(find "$tmp" -mindepth 1 -maxdepth 1 -type d | head -n 1)
57
- if [ -z "$extracted" ]; then
58
- echo "VS Code Server archive did not contain a directory" >&2
59
- exit 1
60
- fi
61
- if ! { [ -x "$bin_dir/server.sh" ] || [ -x "$bin_dir/bin/code-server" ]; }; then
62
- mkdir -p "$bin_dir"
63
- cp -a "$extracted"/. "$bin_dir"/
64
- touch "$bin_dir/0"
65
- fi
66
- if [ ! -x "$cli_server_dir/bin/code-server" ]; then
67
- mkdir -p "$cli_server_dir"
68
- cp -a "$extracted"/. "$cli_server_dir"/
69
- fi
70
- echo "Cached VS Code Server $commit for linux-$arch"
71
- `;
72
- const result = await checkedExec(vm, script);
73
- if (result.stdout?.trim())
74
- console.log(result.stdout.trim());
75
- }
76
- async function localVsCodeCommit() {
77
- try {
78
- const { stdout } = await execFileAsync("code", ["--version"]);
79
- const commit = stdout.split(/\r?\n/)[1]?.trim();
80
- return /^[0-9a-f]{40}$/i.test(commit ?? "") ? commit : undefined;
81
- }
82
- catch {
83
- return undefined;
84
- }
85
- }
86
- async function openRemoteEditor(context, scheme) {
87
- const { vmId, options } = context;
88
- console.log(`Opening ${scheme === "cursor" ? "Cursor" : "VS Code"} Remote SSH window for VM ${vmId}...`);
89
- const { identity, identityId } = await freestyle.identities.create();
90
- await identity.permissions.vms.grant({ vmId });
91
- const { token, tokenId } = await identity.tokens.create();
92
- const remoteWorkspaceUri = `vscode-remote://ssh-remote%2B${vmId}%2C${token}@${vmId}.vm-ssh.freestyle.sh${encodeRemotePath(options.remoteProjectDir)}`;
93
- const uri = `${scheme}://vscode-remote/ssh-remote+${vmId},${token}@${vmId}.vm-ssh.freestyle.sh${encodeRemotePath(options.remoteProjectDir)}?windowId=_blank`;
94
- try {
95
- const preOpenMessages = await context.runBeforeOpenRemoteEditor({ scheme, remoteWorkspaceUri });
96
- for (const message of preOpenMessages)
97
- console.log(message);
98
- await openUri(uri);
99
- }
100
- catch (error) {
101
- await identity.tokens.revoke({ tokenId }).catch(() => undefined);
102
- await freestyle.identities.delete({ identityId }).catch(() => undefined);
103
- throw error;
104
- }
105
- await context.utils.delay(5000);
106
- const postOpenMessages = await context.runAfterOpenRemoteEditor({ scheme, remoteWorkspaceUri });
107
- for (const message of postOpenMessages)
108
- console.log(message);
109
- console.log(`Opened ${scheme === "cursor" ? "Cursor" : "VS Code"}. SSH identity ${identityId} remains active for the editor session.`);
110
- }
111
- async function detectEditorScheme() {
112
- const envText = Object.entries(process.env)
113
- .filter(([key]) => key.startsWith("VSCODE_") || key.startsWith("CURSOR") || key === "TERM_PROGRAM")
114
- .map(([key, value]) => `${key}=${value ?? ""}`)
115
- .join("\n")
116
- .toLowerCase();
117
- if (envText.includes("cursor"))
118
- return "cursor";
119
- if (!envText.includes("term_program=vscode") && !envText.includes("vscode_"))
120
- return undefined;
121
- const parentCommands = await processCommandChain(process.ppid);
122
- if (parentCommands.some((command) => command.toLowerCase().includes("cursor")))
123
- return "cursor";
124
- return "vscode";
125
- }
126
- async function processCommandChain(startPid) {
127
- const commands = [];
128
- let pid = startPid;
129
- for (let depth = 0; depth < 20 && pid > 1; depth += 1) {
130
- try {
131
- const { stdout } = await execFileAsync("ps", ["-p", String(pid), "-o", "ppid=", "-o", "comm="]);
132
- const line = stdout.trim();
133
- if (!line)
134
- break;
135
- const match = line.match(/^(\d+)\s+(.+)$/);
136
- if (!match)
137
- break;
138
- pid = Number(match[1]);
139
- commands.push(match[2]);
140
- }
141
- catch {
142
- break;
143
- }
144
- }
145
- return commands;
146
- }
147
- function encodeRemotePath(remoteProjectDir) {
148
- return remoteProjectDir.split("/").map((segment) => encodeURIComponent(segment)).join("/");
149
- }
150
- async function openUri(uri) {
151
- if (process.platform === "darwin") {
152
- await execFileAsync("open", [uri]);
153
- }
154
- else if (process.platform === "win32") {
155
- await execFileAsync("cmd", ["/c", "start", "", uri]);
156
- }
157
- else {
158
- await execFileAsync("xdg-open", [uri]);
159
- }
160
- }
@@ -1,36 +0,0 @@
1
- import { defineConfig } from "./plugin-api.js";
2
- import { claudeAgentPlugin } from "@freestyle-sync/agent-claude";
3
- import { codexAgentPlugin } from "@freestyle-sync/agent-codex";
4
- import { copilotAgentPlugin } from "@freestyle-sync/agent-copilot";
5
- import { awsAuthPlugin } from "@freestyle-sync/auth-aws";
6
- import { azureAuthPlugin } from "@freestyle-sync/auth-azure";
7
- import { dockerAuthPlugin } from "@freestyle-sync/auth-docker";
8
- import { envAuthPlugin } from "@freestyle-sync/auth-env";
9
- import { gcloudAuthPlugin } from "@freestyle-sync/auth-gcloud";
10
- import { gitAuthPlugin } from "@freestyle-sync/auth-git";
11
- import { githubCliAuthPlugin } from "@freestyle-sync/auth-github-cli";
12
- import { npmAuthPlugin } from "@freestyle-sync/auth-npm";
13
- import { sshAuthPlugin } from "@freestyle-sync/auth-ssh";
14
- import { yarnAuthPlugin } from "@freestyle-sync/auth-yarn";
15
- import { nodeNpmPlugin } from "@freestyle-sync/node-npm";
16
- import { shellHistoryPlugin } from "@freestyle-sync/shell-history";
17
- export default defineConfig({
18
- plugins: [
19
- envAuthPlugin(),
20
- gitAuthPlugin(),
21
- sshAuthPlugin(),
22
- githubCliAuthPlugin(),
23
- npmAuthPlugin(),
24
- yarnAuthPlugin(),
25
- dockerAuthPlugin(),
26
- awsAuthPlugin(),
27
- azureAuthPlugin(),
28
- gcloudAuthPlugin(),
29
- nodeNpmPlugin(),
30
- claudeAgentPlugin(),
31
- codexAgentPlugin(),
32
- copilotAgentPlugin(),
33
- shellHistoryPlugin(),
34
- // vscodePlugin(),
35
- ],
36
- });