farming-code 2.2.18 → 2.2.20

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.
@@ -342,10 +342,6 @@ function manifestAssetSafety(asset, manifest, options = {}) {
342
342
  return { safe: true, reason: '' };
343
343
  }
344
344
 
345
- function shellQuote(value) {
346
- return `'${String(value).replace(/'/g, `'\\''`)}'`;
347
- }
348
-
349
345
  function requestWithRedirects(url, options = {}, redirectCount = 0, authOrigin = null) {
350
346
  if (redirectCount > 5) {
351
347
  return Promise.reject(new Error(`too many redirects for ${url}`));
@@ -798,7 +794,16 @@ class FarmingUpdateService {
798
794
 
799
795
  currentInstallState() {
800
796
  const persisted = readJsonFile(this.updateStateFile);
801
- if (this.installMethod === 'npm' && persisted && persisted.method === 'npm') return persisted;
797
+ if (persisted && persisted.method === this.installMethod) return persisted;
798
+ const current = this.currentVersion();
799
+ const currentVersion = normalizeVersion(current.releaseVersion || current.packageVersion);
800
+ if (
801
+ persisted
802
+ && persisted.targetMethod === this.installMethod
803
+ && normalizeVersion(persisted.version) === currentVersion
804
+ ) {
805
+ return persisted;
806
+ }
802
807
  return this.installState;
803
808
  }
804
809
 
@@ -1116,19 +1121,22 @@ class FarmingUpdateService {
1116
1121
  this.runtime,
1117
1122
  this.currentVersion().compatibilityProfile,
1118
1123
  );
1119
- this.installState = {
1124
+ this.persistInstallState({
1120
1125
  phase: 'downloading',
1126
+ method: this.installMethod,
1121
1127
  version: status.selected.version,
1128
+ previousVersion: status.current.releaseVersion || status.current.packageVersion,
1122
1129
  assetName: status.selected.assetName,
1123
1130
  startedAt: new Date(this.now()).toISOString(),
1124
1131
  logPath: path.join(this.configDir, 'farming-update.log'),
1125
- };
1132
+ });
1126
1133
  void this.runInstall(asset).catch(error => {
1127
- this.installState = {
1134
+ this.persistInstallState({
1128
1135
  ...this.installState,
1129
1136
  phase: 'failed',
1130
1137
  error: error.message || String(error),
1131
- };
1138
+ completedAt: new Date(this.now()).toISOString(),
1139
+ });
1132
1140
  });
1133
1141
  return this.installState;
1134
1142
  }
@@ -1221,7 +1229,7 @@ class FarmingUpdateService {
1221
1229
 
1222
1230
  validateArchiveEntries(await this.listArchiveEntries(archivePath));
1223
1231
 
1224
- this.installState = { ...this.installState, phase: 'extracting' };
1232
+ this.persistInstallState({ ...this.installState, phase: 'extracting' });
1225
1233
  await new Promise((resolve, reject) => {
1226
1234
  this.execFile('tar', ['-xzf', archivePath, '-C', tempRoot], (error) => {
1227
1235
  if (error) reject(error);
@@ -1240,23 +1248,38 @@ class FarmingUpdateService {
1240
1248
  throw new Error('downloaded release is missing scripts/install-release.sh');
1241
1249
  }
1242
1250
  const logPath = this.installState.logPath || path.join(this.configDir, 'farming-update.log');
1243
- const installCommand = [
1244
- 'sleep 1',
1245
- `cd ${shellQuote(releaseDir)}`,
1246
- `exec bash scripts/install-release.sh install >> ${shellQuote(logPath)} 2>&1`,
1247
- ].join('; ');
1248
- const child = this.spawn('bash', ['-lc', installCommand], {
1249
- detached: true,
1250
- stdio: 'ignore',
1251
- env: this.installEnvironment(),
1252
- });
1253
- if (child && typeof child.unref === 'function') child.unref();
1254
- this.installState = {
1251
+ const targetMethod = String(releaseMetadata.updateMethod || releaseMetadata.type || this.installMethod);
1252
+ const helperPath = path.join(__dirname, 'bundle-update-helper.js');
1253
+ const nodePath = process.env.FARMING_NODE_BIN || process.execPath;
1254
+ const helperInvocation = nodeScriptInvocation(nodePath, helperPath);
1255
+ const payload = {
1256
+ method: this.installMethod,
1257
+ targetMethod,
1258
+ version: this.installState.version,
1259
+ previousVersion: this.installState.previousVersion,
1260
+ startedAt: this.installState.startedAt,
1261
+ stateFile: this.updateStateFile,
1262
+ logPath,
1263
+ releaseDir,
1264
+ installer,
1265
+ };
1266
+ this.persistInstallState({
1255
1267
  ...this.installState,
1256
1268
  phase: 'installing',
1269
+ targetMethod,
1257
1270
  releaseDir,
1258
1271
  logPath,
1259
- };
1272
+ });
1273
+ const child = this.spawn(helperInvocation.command, helperInvocation.args, {
1274
+ cwd: this.configDir,
1275
+ detached: true,
1276
+ stdio: 'ignore',
1277
+ env: {
1278
+ ...this.installEnvironment(),
1279
+ FARMING_BUNDLE_UPDATE_PAYLOAD: JSON.stringify(payload),
1280
+ },
1281
+ });
1282
+ if (child && typeof child.unref === 'function') child.unref();
1260
1283
  }
1261
1284
  }
1262
1285
 
@@ -10,6 +10,8 @@ const execFileAsync = promisify(execFile);
10
10
  const USAGE_WINDOW_MS = 5 * 60 * 1000;
11
11
  const USAGE_TIMELINE_WINDOW_MS = 24 * 60 * 60 * 1000;
12
12
  const USAGE_TIMELINE_BUCKET_COUNT = 24;
13
+ const USAGE_LIVE_TIMELINE_WINDOW_MS = 60 * 60 * 1000;
14
+ const USAGE_LIVE_TIMELINE_BUCKET_COUNT = 60;
13
15
  const USAGE_DAILY_DAYS = 52 * 7;
14
16
  const USAGE_DAILY_CACHE_MS = 5 * 60 * 1000;
15
17
  const USAGE_LIVE_DAY_CACHE_MS = 5 * 1000;
@@ -1020,6 +1022,12 @@ class UsageMonitor {
1020
1022
  windowMs: historyWindowMs,
1021
1023
  alignToBucket: true,
1022
1024
  });
1025
+ const liveTimeline = buildUsageTimeline(history.providerEvents, {
1026
+ now,
1027
+ windowMs: USAGE_LIVE_TIMELINE_WINDOW_MS,
1028
+ bucketCount: USAGE_LIVE_TIMELINE_BUCKET_COUNT,
1029
+ alignToBucket: true,
1030
+ });
1023
1031
  const openCodeCoverage = history.coverage.find(entry => entry.provider === 'opencode');
1024
1032
  const qoderCoverage = history.coverage.find(entry => entry.provider === 'qoder');
1025
1033
 
@@ -1027,6 +1035,7 @@ class UsageMonitor {
1027
1035
  sampledAt: now,
1028
1036
  windowMs,
1029
1037
  timeline,
1038
+ liveTimeline,
1030
1039
  daily: history.daily,
1031
1040
  providers: [
1032
1041
  {
@@ -1099,6 +1108,8 @@ module.exports = {
1099
1108
  USAGE_WINDOW_MS,
1100
1109
  USAGE_TIMELINE_WINDOW_MS,
1101
1110
  USAGE_TIMELINE_BUCKET_COUNT,
1111
+ USAGE_LIVE_TIMELINE_WINDOW_MS,
1112
+ USAGE_LIVE_TIMELINE_BUCKET_COUNT,
1102
1113
  USAGE_DAILY_DAYS,
1103
1114
  USAGE_DAILY_CACHE_MS,
1104
1115
  USAGE_LIVE_DAY_CACHE_MS,