@openagentsinc/pylon 0.1.14 → 0.1.16

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 (3) hide show
  1. package/README.md +16 -9
  2. package/package.json +1 -1
  3. package/src/index.js +110 -0
package/README.md CHANGED
@@ -13,7 +13,7 @@ npx @openagentsinc/pylon
13
13
  bunx @openagentsinc/pylon
14
14
  npm install -g @openagentsinc/pylon && pylon
15
15
  bun install -g @openagentsinc/pylon && pylon
16
- npx @openagentsinc/pylon --version 0.1.13
16
+ npx @openagentsinc/pylon --version 0.1.16
17
17
  npx @openagentsinc/pylon --no-launch
18
18
  npx @openagentsinc/pylon --no-updates
19
19
  npx @openagentsinc/pylon --download-curated-cache --model gemma-4-e2b --run-diagnostics
@@ -34,8 +34,9 @@ The launcher:
34
34
  - prompts before installing the Rust toolchain via `rustup` if a source build
35
35
  is needed and `cargo` / `rustc` are missing
36
36
  - emits best-effort anonymous installer telemetry to `openagents.com` so the
37
- public stats page can show install starts, completions, source-build fallbacks,
38
- Rust prompts, and smoke-test outcomes
37
+ public stats page can show install starts, completions, source-build
38
+ fallbacks, update checks, restart behavior, Rust prompts, and smoke-test
39
+ outcomes
39
40
  - downloads the archive and published SHA-256 checksum
40
41
  - verifies the checksum before extracting
41
42
  - caches the unpacked binaries under `~/.openagents/pylon/bootstrap/`
@@ -64,12 +65,18 @@ The launcher:
64
65
  without replacing the global npm/bun command
65
66
  - use `--no-updates` to keep the current installed release running without
66
67
  background GitHub release checks; `--version` remains a pinned release run
67
- - for hosted homework/training work, use launcher `0.1.14` or newer so the
68
- cached standalone binary auto-updates while the dashboard is open. The latest
69
- trusted standalone binary still carries the `0.1.13` and `0.1.12` runtime
70
- fixes: no legacy runtime wording, explicit runtime management, current
71
- `target/release/psionic-train` preference, and `cargo run --release`
72
- fallback instead of debug `cargo run`
68
+ - owns the current auto-update contract. Directly extracted GitHub release
69
+ assets do not contain a native updater today; if an operator runs
70
+ `./pylon` from an unpacked archive, that process stays on its compiled
71
+ version until the operator manually replaces the archive or switches back to
72
+ the npm/bun launcher.
73
+ - for hosted homework/training work, use launcher `0.1.16` or newer so the
74
+ cached standalone binary auto-updates while the dashboard is open. The
75
+ `pylon-v0.1.16` standalone binary keeps the long hosted homework ID hashing
76
+ from `0.1.14`, refuses to seal terminal training windows until the worker
77
+ contribution artifact bundle has uploaded and verified for validator replay,
78
+ and packages the minimal Psionic training runtime so standalone installs can
79
+ advertise homework-worker capability.
73
80
  - does not try to install or register a local runtime automatically; the
74
81
  bootstrap stays honest about the separate local Gemma runtime
75
82
  prerequisite instead of mutating the host behind the user's back
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openagentsinc/pylon",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "Bootstrap the standalone OpenAgents Pylon release asset and run first-run smoke checks.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -2023,10 +2023,41 @@ export async function launchInstalledPylonWithUpdates(
2023
2023
  spawnProcessImpl = spawn,
2024
2024
  updateCheckIntervalMs = DEFAULT_UPDATE_CHECK_INTERVAL_MS,
2025
2025
  onStatus = null,
2026
+ telemetryClient = null,
2026
2027
  ...dependencies
2027
2028
  } = {},
2028
2029
  ) {
2030
+ const currentReleaseTag =
2031
+ options.tagName ?? `pylon-v${normalizeVersion(options.version)}`;
2032
+ const updateTelemetryBase = {
2033
+ current_release_tag: currentReleaseTag,
2034
+ current_version: normalizeVersion(options.version),
2035
+ os: options.target?.os ?? null,
2036
+ arch: options.target?.arch ?? null,
2037
+ platform_key:
2038
+ options.target?.os && options.target?.arch
2039
+ ? `${options.target.os}-${options.target.arch}`
2040
+ : null,
2041
+ install_source: installSourceForTelemetry(
2042
+ options.installMethod,
2043
+ Boolean(options.cached),
2044
+ ),
2045
+ update_check_interval_ms: updateCheckIntervalMs,
2046
+ };
2047
+
2029
2048
  if (options.noUpdates || options.pinnedVersion) {
2049
+ emitTelemetry(
2050
+ telemetryClient,
2051
+ options.noUpdates
2052
+ ? "installer_update_disabled"
2053
+ : "installer_update_pinned_run",
2054
+ {
2055
+ ...updateTelemetryBase,
2056
+ update_mode: options.noUpdates ? "no_updates" : "pinned_version",
2057
+ update_reason: options.noUpdates ? "--no-updates" : "--version",
2058
+ },
2059
+ );
2060
+ await telemetryClient?.flush?.();
2030
2061
  return launchInstalledPylon(options, { ...dependencies, onStatus });
2031
2062
  }
2032
2063
 
@@ -2035,6 +2066,7 @@ export async function launchInstalledPylonWithUpdates(
2035
2066
  version: normalizeVersion(options.version),
2036
2067
  };
2037
2068
  let lastUpdateError = null;
2069
+ let pendingRestartTelemetry = null;
2038
2070
 
2039
2071
  while (true) {
2040
2072
  const pylonTuiPath = path.resolve(current.pylonTuiPath);
@@ -2043,6 +2075,14 @@ export async function launchInstalledPylonWithUpdates(
2043
2075
  "Starting Pylon terminal UI",
2044
2076
  `${path.basename(pylonTuiPath)} manages the earning worker`,
2045
2077
  );
2078
+ if (pendingRestartTelemetry) {
2079
+ emitTelemetry(telemetryClient, "installer_update_restart_succeeded", {
2080
+ ...pendingRestartTelemetry,
2081
+ restarted_release_tag: current.tagName,
2082
+ restarted_version: current.version,
2083
+ });
2084
+ pendingRestartTelemetry = null;
2085
+ }
2046
2086
  const child = spawnPylonTui(pylonTuiPath, current, spawnProcessImpl);
2047
2087
  const childExit = waitForChildExit(child);
2048
2088
  let restartForUpdate = false;
@@ -2065,6 +2105,12 @@ export async function launchInstalledPylonWithUpdates(
2065
2105
  );
2066
2106
  }
2067
2107
 
2108
+ emitTelemetry(telemetryClient, "installer_update_check_started", {
2109
+ ...updateTelemetryBase,
2110
+ observed_release_tag: current.tagName,
2111
+ observed_version: current.version,
2112
+ });
2113
+
2068
2114
  try {
2069
2115
  const install = await ensureReleaseInstallImpl(
2070
2116
  {
@@ -2080,12 +2126,70 @@ export async function launchInstalledPylonWithUpdates(
2080
2126
  if (!isNewerPylonVersion(install.version, current.version)) {
2081
2127
  continue;
2082
2128
  }
2129
+ emitTelemetry(telemetryClient, "installer_update_available", {
2130
+ ...updateTelemetryBase,
2131
+ observed_release_tag: current.tagName,
2132
+ observed_version: current.version,
2133
+ available_release_tag: install.tagName,
2134
+ available_version: install.version,
2135
+ available_install_source: installSourceForTelemetry(
2136
+ install.installMethod,
2137
+ Boolean(install.cached),
2138
+ ),
2139
+ });
2140
+ if (
2141
+ install.installMethod === RELEASE_ASSET_INSTALL_METHOD &&
2142
+ !install.cached
2143
+ ) {
2144
+ emitTelemetry(telemetryClient, "installer_update_downloaded", {
2145
+ ...updateTelemetryBase,
2146
+ observed_release_tag: current.tagName,
2147
+ observed_version: current.version,
2148
+ available_release_tag: install.tagName,
2149
+ available_version: install.version,
2150
+ });
2151
+ emitTelemetry(telemetryClient, "installer_update_verified", {
2152
+ ...updateTelemetryBase,
2153
+ observed_release_tag: current.tagName,
2154
+ observed_version: current.version,
2155
+ available_release_tag: install.tagName,
2156
+ available_version: install.version,
2157
+ });
2158
+ }
2159
+ emitTelemetry(telemetryClient, "installer_update_applied", {
2160
+ ...updateTelemetryBase,
2161
+ previous_release_tag: current.tagName,
2162
+ previous_version: current.version,
2163
+ applied_release_tag: install.tagName,
2164
+ applied_version: install.version,
2165
+ applied_install_source: installSourceForTelemetry(
2166
+ install.installMethod,
2167
+ Boolean(install.cached),
2168
+ ),
2169
+ });
2083
2170
  emitStatus(
2084
2171
  onStatus,
2085
2172
  "Installed newer Pylon release",
2086
2173
  `${install.tagName}; restarting dashboard`,
2087
2174
  );
2175
+ emitTelemetry(telemetryClient, "installer_update_restart_attempted", {
2176
+ ...updateTelemetryBase,
2177
+ previous_release_tag: current.tagName,
2178
+ previous_version: current.version,
2179
+ restart_target_release_tag: install.tagName,
2180
+ restart_target_version: install.version,
2181
+ });
2088
2182
  await stopChild(child);
2183
+ pendingRestartTelemetry = {
2184
+ previous_release_tag: current.tagName,
2185
+ previous_version: current.version,
2186
+ applied_release_tag: install.tagName,
2187
+ applied_version: install.version,
2188
+ applied_install_source: installSourceForTelemetry(
2189
+ install.installMethod,
2190
+ Boolean(install.cached),
2191
+ ),
2192
+ };
2089
2193
  current = {
2090
2194
  ...options,
2091
2195
  ...install,
@@ -2094,6 +2198,12 @@ export async function launchInstalledPylonWithUpdates(
2094
2198
  restartForUpdate = true;
2095
2199
  } catch (error) {
2096
2200
  const message = error instanceof Error ? error.message : String(error);
2201
+ emitTelemetry(telemetryClient, "installer_update_failed", {
2202
+ ...updateTelemetryBase,
2203
+ observed_release_tag: current.tagName,
2204
+ observed_version: current.version,
2205
+ ...telemetryFailureContext(error, "update_check"),
2206
+ });
2097
2207
  if (message !== lastUpdateError) {
2098
2208
  emitStatus(onStatus, "Pylon update check failed", message);
2099
2209
  lastUpdateError = message;