@sylphx/flow 2.15.2 → 2.15.3
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/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/src/services/auto-upgrade.ts +53 -53
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# @sylphx/flow
|
|
2
2
|
|
|
3
|
+
## 2.15.3 (2025-12-17)
|
|
4
|
+
|
|
5
|
+
### ⚡️ Performance
|
|
6
|
+
|
|
7
|
+
- **auto-upgrade:** simplify - no TTL, always background check ([5621a21](https://github.com/SylphxAI/flow/commit/5621a21ab2a3eeb54f3fecadd32c19269bd22312))
|
|
8
|
+
- **auto-upgrade:** cache target current version too ([229a400](https://github.com/SylphxAI/flow/commit/229a4002bde6da3540c014eb39e8a941e072a4db))
|
|
9
|
+
|
|
3
10
|
## 2.15.2 (2025-12-17)
|
|
4
11
|
|
|
5
12
|
### ⚡️ Performance
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sylphx/flow",
|
|
3
|
-
"version": "2.15.
|
|
3
|
+
"version": "2.15.3",
|
|
4
4
|
"description": "One CLI to rule them all. Unified orchestration layer for Claude Code, OpenCode, Cursor and all AI development tools. Auto-detection, auto-installation, auto-upgrade.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,14 +19,13 @@ import { TargetInstaller } from './target-installer.js';
|
|
|
19
19
|
const __filename = fileURLToPath(import.meta.url);
|
|
20
20
|
const __dirname = path.dirname(__filename);
|
|
21
21
|
|
|
22
|
-
//
|
|
23
|
-
const
|
|
24
|
-
const CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
22
|
+
// Version info file (stores last background check result)
|
|
23
|
+
const VERSION_FILE = path.join(os.homedir(), '.sylphx-flow', 'versions.json');
|
|
25
24
|
|
|
26
|
-
interface
|
|
25
|
+
interface VersionInfo {
|
|
27
26
|
flowLatest?: string;
|
|
28
27
|
targetLatest?: Record<string, string>;
|
|
29
|
-
|
|
28
|
+
targetCurrent?: Record<string, string>;
|
|
30
29
|
}
|
|
31
30
|
|
|
32
31
|
const execAsync = promisify(exec);
|
|
@@ -56,14 +55,14 @@ export class AutoUpgrade {
|
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
/**
|
|
59
|
-
* Read version
|
|
58
|
+
* Read version info from last background check
|
|
60
59
|
*/
|
|
61
|
-
private async
|
|
60
|
+
private async readVersionInfo(): Promise<VersionInfo | null> {
|
|
62
61
|
try {
|
|
63
|
-
if (!existsSync(
|
|
62
|
+
if (!existsSync(VERSION_FILE)) {
|
|
64
63
|
return null;
|
|
65
64
|
}
|
|
66
|
-
const data = await fs.readFile(
|
|
65
|
+
const data = await fs.readFile(VERSION_FILE, 'utf-8');
|
|
67
66
|
return JSON.parse(data);
|
|
68
67
|
} catch {
|
|
69
68
|
return null;
|
|
@@ -71,13 +70,13 @@ export class AutoUpgrade {
|
|
|
71
70
|
}
|
|
72
71
|
|
|
73
72
|
/**
|
|
74
|
-
* Write version
|
|
73
|
+
* Write version info
|
|
75
74
|
*/
|
|
76
|
-
private async
|
|
75
|
+
private async writeVersionInfo(info: VersionInfo): Promise<void> {
|
|
77
76
|
try {
|
|
78
|
-
const dir = path.dirname(
|
|
77
|
+
const dir = path.dirname(VERSION_FILE);
|
|
79
78
|
await fs.mkdir(dir, { recursive: true });
|
|
80
|
-
await fs.writeFile(
|
|
79
|
+
await fs.writeFile(VERSION_FILE, JSON.stringify(info, null, 2));
|
|
81
80
|
} catch {
|
|
82
81
|
// Silent fail
|
|
83
82
|
}
|
|
@@ -97,18 +96,18 @@ export class AutoUpgrade {
|
|
|
97
96
|
}
|
|
98
97
|
|
|
99
98
|
/**
|
|
100
|
-
* Check for available upgrades
|
|
101
|
-
*
|
|
99
|
+
* Check for available upgrades (instant, reads from last background check)
|
|
100
|
+
* Background check runs every time for fresh data next run
|
|
102
101
|
*/
|
|
103
102
|
async checkForUpgrades(targetId?: string): Promise<UpgradeStatus> {
|
|
104
|
-
const
|
|
103
|
+
const info = await this.readVersionInfo();
|
|
105
104
|
const currentVersion = await this.getCurrentFlowVersion();
|
|
106
105
|
|
|
107
|
-
// Trigger background check for next run (non-blocking)
|
|
106
|
+
// Trigger background check for next run (non-blocking, every time)
|
|
108
107
|
this.checkInBackground(targetId);
|
|
109
108
|
|
|
110
|
-
// No
|
|
111
|
-
if (!
|
|
109
|
+
// No previous check = no upgrade info yet
|
|
110
|
+
if (!info) {
|
|
112
111
|
return {
|
|
113
112
|
flowNeedsUpgrade: false,
|
|
114
113
|
targetNeedsUpgrade: false,
|
|
@@ -117,26 +116,19 @@ export class AutoUpgrade {
|
|
|
117
116
|
};
|
|
118
117
|
}
|
|
119
118
|
|
|
120
|
-
// Check if Flow needs upgrade
|
|
119
|
+
// Check if Flow needs upgrade
|
|
121
120
|
const flowVersion =
|
|
122
|
-
|
|
123
|
-
? { current: currentVersion, latest:
|
|
121
|
+
info.flowLatest && info.flowLatest !== currentVersion
|
|
122
|
+
? { current: currentVersion, latest: info.flowLatest }
|
|
124
123
|
: null;
|
|
125
124
|
|
|
126
|
-
// Check if target needs upgrade
|
|
125
|
+
// Check if target needs upgrade
|
|
127
126
|
let targetVersion: { current: string; latest: string } | null = null;
|
|
128
|
-
if (targetId &&
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const match = stdout.match(/v?(\d+\.\d+\.\d+)/);
|
|
134
|
-
if (match && match[1] !== cache.targetLatest[targetId]) {
|
|
135
|
-
targetVersion = { current: match[1], latest: cache.targetLatest[targetId] };
|
|
136
|
-
}
|
|
137
|
-
} catch {
|
|
138
|
-
// Silent
|
|
139
|
-
}
|
|
127
|
+
if (targetId && info.targetLatest?.[targetId] && info.targetCurrent?.[targetId]) {
|
|
128
|
+
const current = info.targetCurrent[targetId];
|
|
129
|
+
const latest = info.targetLatest[targetId];
|
|
130
|
+
if (current !== latest) {
|
|
131
|
+
targetVersion = { current, latest };
|
|
140
132
|
}
|
|
141
133
|
}
|
|
142
134
|
|
|
@@ -150,7 +142,7 @@ export class AutoUpgrade {
|
|
|
150
142
|
|
|
151
143
|
/**
|
|
152
144
|
* Check versions in background (non-blocking)
|
|
153
|
-
*
|
|
145
|
+
* Runs every time, updates info for next run
|
|
154
146
|
*/
|
|
155
147
|
private checkInBackground(targetId?: string): void {
|
|
156
148
|
// Fire and forget - don't await
|
|
@@ -163,44 +155,52 @@ export class AutoUpgrade {
|
|
|
163
155
|
* Perform the actual version check (called in background)
|
|
164
156
|
*/
|
|
165
157
|
private async performBackgroundCheck(targetId?: string): Promise<void> {
|
|
166
|
-
const
|
|
158
|
+
const oldInfo = await this.readVersionInfo();
|
|
167
159
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const newCache: VersionCache = {
|
|
174
|
-
checkedAt: Date.now(),
|
|
175
|
-
targetLatest: cache?.targetLatest || {},
|
|
160
|
+
const newInfo: VersionInfo = {
|
|
161
|
+
targetLatest: oldInfo?.targetLatest || {},
|
|
162
|
+
targetCurrent: oldInfo?.targetCurrent || {},
|
|
176
163
|
};
|
|
177
164
|
|
|
178
165
|
// Check Flow version from npm (with timeout)
|
|
179
166
|
try {
|
|
180
167
|
const { stdout } = await execAsync('npm view @sylphx/flow version', { timeout: 5000 });
|
|
181
|
-
|
|
168
|
+
newInfo.flowLatest = stdout.trim();
|
|
182
169
|
} catch {
|
|
183
|
-
// Keep old
|
|
184
|
-
|
|
170
|
+
// Keep old value if check fails
|
|
171
|
+
newInfo.flowLatest = oldInfo?.flowLatest;
|
|
185
172
|
}
|
|
186
173
|
|
|
187
|
-
// Check target version from npm (with timeout)
|
|
174
|
+
// Check target version from npm and local (with timeout)
|
|
188
175
|
if (targetId) {
|
|
189
176
|
const installation = this.targetInstaller.getInstallationInfo(targetId);
|
|
190
177
|
if (installation) {
|
|
178
|
+
// Check latest version from npm
|
|
191
179
|
try {
|
|
192
180
|
const { stdout } = await execAsync(`npm view ${installation.package} version`, {
|
|
193
181
|
timeout: 5000,
|
|
194
182
|
});
|
|
195
|
-
|
|
196
|
-
|
|
183
|
+
newInfo.targetLatest = newInfo.targetLatest || {};
|
|
184
|
+
newInfo.targetLatest[targetId] = stdout.trim();
|
|
185
|
+
} catch {
|
|
186
|
+
// Keep old value
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Check current installed version (local command)
|
|
190
|
+
try {
|
|
191
|
+
const { stdout } = await execAsync(installation.checkCommand, { timeout: 5000 });
|
|
192
|
+
const match = stdout.match(/v?(\d+\.\d+\.\d+)/);
|
|
193
|
+
if (match) {
|
|
194
|
+
newInfo.targetCurrent = newInfo.targetCurrent || {};
|
|
195
|
+
newInfo.targetCurrent[targetId] = match[1];
|
|
196
|
+
}
|
|
197
197
|
} catch {
|
|
198
|
-
// Keep old
|
|
198
|
+
// Keep old value
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
-
await this.
|
|
203
|
+
await this.writeVersionInfo(newInfo);
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
/**
|