@openagentsinc/pylon 0.1.2 → 0.1.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/README.md +16 -2
- package/bin/pylon +26 -0
- package/package.json +2 -2
- package/src/cli.js +12 -2
- package/src/index.js +89 -1
package/README.md
CHANGED
|
@@ -10,6 +10,9 @@ available.
|
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
12
|
npx @openagentsinc/pylon
|
|
13
|
+
bunx @openagentsinc/pylon
|
|
14
|
+
npm install -g @openagentsinc/pylon && pylon
|
|
15
|
+
bun install -g @openagentsinc/pylon && pylon
|
|
13
16
|
npx @openagentsinc/pylon --version 0.0.1-rc4
|
|
14
17
|
npx @openagentsinc/pylon --no-launch
|
|
15
18
|
npx @openagentsinc/pylon --download-curated-cache --model gemma-4-e2b --diagnostic-repeats 2
|
|
@@ -18,8 +21,10 @@ npx @openagentsinc/pylon --verbose
|
|
|
18
21
|
|
|
19
22
|
The launcher:
|
|
20
23
|
|
|
21
|
-
-
|
|
22
|
-
|
|
24
|
+
- supports direct `npx` / `bunx` execution plus global `npm install -g` /
|
|
25
|
+
`bun install -g` installs with the same `pylon` command
|
|
26
|
+
- checks GitHub for the latest tagged `pylon-v...` release on each default run,
|
|
27
|
+
or resolves a specific tagged `Pylon` version when `--version` is provided
|
|
23
28
|
- resolves the correct `pylon-v<version>-<os>-<arch>.tar.gz` asset for the
|
|
24
29
|
current machine
|
|
25
30
|
- falls back to the exact tagged source checkout and builds `pylon` plus
|
|
@@ -29,8 +34,13 @@ The launcher:
|
|
|
29
34
|
- downloads the archive and published SHA-256 checksum
|
|
30
35
|
- verifies the checksum before extracting
|
|
31
36
|
- caches the unpacked binaries under `~/.openagents/pylon/bootstrap/`
|
|
37
|
+
- never links or copies those cached standalone binaries into a shared global
|
|
38
|
+
bin directory, so the package-managed `pylon` launcher remains the command on
|
|
39
|
+
`PATH`
|
|
32
40
|
- prints status lines such as release resolution, runtime checks, and local
|
|
33
41
|
model scanning while it runs
|
|
42
|
+
- ends first run with an explicit verdict such as `fully online`, `runtime
|
|
43
|
+
ready`, or `installed but runtime missing`, plus exact next-step guidance
|
|
34
44
|
- runs `pylon --help`, `init`, `status --json`, and `inventory --json`
|
|
35
45
|
- runs `pylon gemma diagnose <model> --json`
|
|
36
46
|
- only runs `pylon gemma download <model>` when `--download-curated-cache` is
|
|
@@ -39,6 +49,9 @@ The launcher:
|
|
|
39
49
|
- falls back to `curl` for release metadata and asset downloads when the Node
|
|
40
50
|
fetch path fails in constrained network contexts
|
|
41
51
|
- opens `pylon-tui` by default after the smoke path unless `--no-launch` is set
|
|
52
|
+
- does not try to install or register a local runtime automatically; the
|
|
53
|
+
bootstrap stays honest about the separate Ollama-compatible runtime
|
|
54
|
+
prerequisite instead of mutating the host behind the user's back
|
|
42
55
|
|
|
43
56
|
## Publish
|
|
44
57
|
|
|
@@ -46,5 +59,6 @@ Publish directly from this package directory:
|
|
|
46
59
|
|
|
47
60
|
```bash
|
|
48
61
|
cd packages/pylon-bootstrap
|
|
62
|
+
npm pack --dry-run
|
|
49
63
|
npm publish
|
|
50
64
|
```
|
package/bin/pylon
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
set -eu
|
|
4
|
+
|
|
5
|
+
SCRIPT_PATH="$0"
|
|
6
|
+
while [ -L "$SCRIPT_PATH" ]; do
|
|
7
|
+
LINK_TARGET=$(readlink "$SCRIPT_PATH")
|
|
8
|
+
case "$LINK_TARGET" in
|
|
9
|
+
/*) SCRIPT_PATH="$LINK_TARGET" ;;
|
|
10
|
+
*) SCRIPT_PATH="$(dirname -- "$SCRIPT_PATH")/$LINK_TARGET" ;;
|
|
11
|
+
esac
|
|
12
|
+
done
|
|
13
|
+
|
|
14
|
+
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$SCRIPT_PATH")" && pwd)
|
|
15
|
+
LAUNCHER_JS="${SCRIPT_DIR}/pylon.js"
|
|
16
|
+
|
|
17
|
+
if command -v node >/dev/null 2>&1; then
|
|
18
|
+
exec node "$LAUNCHER_JS" "$@"
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
if command -v bun >/dev/null 2>&1; then
|
|
22
|
+
exec bun "$LAUNCHER_JS" "$@"
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
echo "pylon launcher requires Node.js or Bun on PATH." >&2
|
|
26
|
+
exit 1
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openagentsinc/pylon",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Bootstrap the standalone OpenAgents Pylon release asset and run first-run smoke checks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"pylon": "./bin/pylon
|
|
7
|
+
"pylon": "./bin/pylon"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"bin",
|
package/src/cli.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
bootstrapInstalledPylon,
|
|
8
8
|
ensureReleaseInstall,
|
|
9
9
|
launchInstalledPylonTui,
|
|
10
|
+
resolveBootstrapOutcome,
|
|
10
11
|
renderBootstrapSummary,
|
|
11
12
|
} from "./index.js";
|
|
12
13
|
|
|
@@ -67,6 +68,8 @@ function createReporter({ enableColor = process.stdout.isTTY && !process.env.NO_
|
|
|
67
68
|
export function usage() {
|
|
68
69
|
return `Usage:
|
|
69
70
|
npx @openagentsinc/pylon [options]
|
|
71
|
+
bunx @openagentsinc/pylon [options]
|
|
72
|
+
pylon [options]
|
|
70
73
|
|
|
71
74
|
Description:
|
|
72
75
|
Download the latest tagged standalone Pylon release asset for this machine,
|
|
@@ -74,7 +77,9 @@ Description:
|
|
|
74
77
|
asset exists for the local platform, fetch the exact tagged source checkout
|
|
75
78
|
and build it locally instead. Cache the binaries, run the first-run smoke
|
|
76
79
|
path, and then open the Pylon terminal UI by default with live status
|
|
77
|
-
updates.
|
|
80
|
+
updates. The launcher checks GitHub for newer tagged pylon-v... releases on
|
|
81
|
+
each default run, but only caches the standalone binaries under the local
|
|
82
|
+
bootstrap root; it does not replace your global npm or bun pylon command.
|
|
78
83
|
|
|
79
84
|
Options:
|
|
80
85
|
--version <x.y.z> Resolve a specific Pylon release.
|
|
@@ -244,7 +249,12 @@ export async function main(argv = process.argv.slice(2), dependencies = {}) {
|
|
|
244
249
|
if (options.json) {
|
|
245
250
|
console.log(JSON.stringify(summary, null, 2));
|
|
246
251
|
} else {
|
|
247
|
-
|
|
252
|
+
const outcome = resolveBootstrapOutcome(summary);
|
|
253
|
+
if (outcome.level === "success") {
|
|
254
|
+
reporter?.success(`Pylon ${outcome.verdict}`, outcome.detail);
|
|
255
|
+
} else {
|
|
256
|
+
reporter?.warning(`Pylon ${outcome.verdict}`, outcome.detail);
|
|
257
|
+
}
|
|
248
258
|
console.log(renderBootstrapSummary(summary));
|
|
249
259
|
if (!options.noLaunch) {
|
|
250
260
|
await launchInstalledPylonTuiImpl(
|
package/src/index.js
CHANGED
|
@@ -17,6 +17,7 @@ export const DEFAULT_FETCH_TIMEOUT_MS = 15_000;
|
|
|
17
17
|
const PYLON_RELEASE_TAG_PREFIX = "pylon-v";
|
|
18
18
|
const RELEASE_ASSET_INSTALL_METHOD = "release_asset";
|
|
19
19
|
const SOURCE_BUILD_INSTALL_METHOD = "source_build";
|
|
20
|
+
const PREFERRED_RUNTIME_MODEL_NAME = "gemma4:e4b";
|
|
20
21
|
|
|
21
22
|
function emitStatus(onStatus, message, detail = null) {
|
|
22
23
|
if (typeof onStatus === "function") {
|
|
@@ -1133,7 +1134,7 @@ export async function ensureReleaseInstall(
|
|
|
1133
1134
|
|
|
1134
1135
|
emitStatus(
|
|
1135
1136
|
onStatus,
|
|
1136
|
-
"
|
|
1137
|
+
"Checking for newer tagged Pylon releases",
|
|
1137
1138
|
options.version ? `requested ${options.version}` : "default release track",
|
|
1138
1139
|
);
|
|
1139
1140
|
const target = resolvePlatformTarget(options.platform, options.arch);
|
|
@@ -1483,14 +1484,99 @@ export async function launchInstalledPylonTui(
|
|
|
1483
1484
|
});
|
|
1484
1485
|
}
|
|
1485
1486
|
|
|
1487
|
+
export function resolveBootstrapOutcome(summary) {
|
|
1488
|
+
const runtimeState =
|
|
1489
|
+
summary.status?.snapshot?.runtime?.authoritative_status ?? "unknown";
|
|
1490
|
+
const localGemma = summary.status?.snapshot?.availability?.local_gemma ?? {};
|
|
1491
|
+
const readyModel = localGemma.ready_model ?? null;
|
|
1492
|
+
const localGemmaError = localGemma.last_error ?? null;
|
|
1493
|
+
const diagnosticStatus = summary.diagnosticResult?.status ?? null;
|
|
1494
|
+
|
|
1495
|
+
if (runtimeState === "online") {
|
|
1496
|
+
return {
|
|
1497
|
+
level: "success",
|
|
1498
|
+
verdict: "fully online",
|
|
1499
|
+
detail: readyModel
|
|
1500
|
+
? `loaded runtime model ${readyModel}`
|
|
1501
|
+
: "eligible local Gemma supply is online",
|
|
1502
|
+
};
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
if (readyModel) {
|
|
1506
|
+
return {
|
|
1507
|
+
level: "success",
|
|
1508
|
+
verdict: "runtime ready",
|
|
1509
|
+
detail: `loaded runtime model ${readyModel}`,
|
|
1510
|
+
};
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
const loweredError = (localGemmaError ?? "").toLowerCase();
|
|
1514
|
+
if (loweredError.includes("/api/tags") || loweredError.includes("not reachable")) {
|
|
1515
|
+
return {
|
|
1516
|
+
level: "warning",
|
|
1517
|
+
verdict: "installed but runtime missing",
|
|
1518
|
+
detail:
|
|
1519
|
+
"no Ollama-compatible local runtime is answering /api/tags yet",
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
if (
|
|
1524
|
+
diagnosticStatus &&
|
|
1525
|
+
diagnosticStatus !== "completed" &&
|
|
1526
|
+
diagnosticStatus !== "passed" &&
|
|
1527
|
+
diagnosticStatus !== "healthy"
|
|
1528
|
+
) {
|
|
1529
|
+
return {
|
|
1530
|
+
level: "warning",
|
|
1531
|
+
verdict: "installed but runtime not yet usable",
|
|
1532
|
+
detail: diagnosticStatus,
|
|
1533
|
+
};
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
return {
|
|
1537
|
+
level: "warning",
|
|
1538
|
+
verdict: "installed",
|
|
1539
|
+
detail: "complete the local runtime setup before bringing the node online",
|
|
1540
|
+
};
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
function renderBootstrapNextSteps(summary, outcome) {
|
|
1544
|
+
const lines = [
|
|
1545
|
+
"Launcher path: use the same npx/bunx command again, or install globally and run `pylon`.",
|
|
1546
|
+
];
|
|
1547
|
+
|
|
1548
|
+
if (outcome.verdict === "fully online" || outcome.verdict === "runtime ready") {
|
|
1549
|
+
lines.push("Next step: open the TUI with `pylon`, or keep using the package-managed launcher.");
|
|
1550
|
+
return lines;
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
if (summary.target?.os === "darwin") {
|
|
1554
|
+
lines.push(
|
|
1555
|
+
"Runtime setup (macOS default): `brew install ollama`, `brew services start ollama`, `ollama pull gemma4:e4b`.",
|
|
1556
|
+
);
|
|
1557
|
+
} else {
|
|
1558
|
+
lines.push(
|
|
1559
|
+
"Runtime setup: start an Ollama-compatible local runtime at `local_gemma_base_url` and load `gemma4:e4b`.",
|
|
1560
|
+
);
|
|
1561
|
+
}
|
|
1562
|
+
lines.push(
|
|
1563
|
+
"Persistent PATH command: `npm install -g @openagentsinc/pylon` or `bun install -g @openagentsinc/pylon`, then run `pylon`.",
|
|
1564
|
+
);
|
|
1565
|
+
return lines;
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1486
1568
|
export function renderBootstrapSummary(summary) {
|
|
1569
|
+
const outcome = resolveBootstrapOutcome(summary);
|
|
1487
1570
|
const lines = [
|
|
1571
|
+
`Onboarding verdict: ${outcome.verdict}`,
|
|
1572
|
+
`Verdict detail: ${outcome.detail}`,
|
|
1488
1573
|
`Pylon release: ${summary.version} (${summary.target.os}-${summary.target.arch})`,
|
|
1489
1574
|
`Archive source: ${summary.tagName}`,
|
|
1490
1575
|
`Installed from cache: ${summary.cached ? "yes" : "no"}`,
|
|
1491
1576
|
`Pylon binary: ${summary.binaries.pylon}`,
|
|
1492
1577
|
`Pylon TUI: ${summary.binaries.pylonTui}`,
|
|
1493
1578
|
`Config path: ${summary.configPath ?? "unknown"}`,
|
|
1579
|
+
`Preferred runtime model name: ${PREFERRED_RUNTIME_MODEL_NAME}`,
|
|
1494
1580
|
];
|
|
1495
1581
|
|
|
1496
1582
|
const statusState =
|
|
@@ -1549,5 +1635,7 @@ export function renderBootstrapSummary(summary) {
|
|
|
1549
1635
|
}
|
|
1550
1636
|
}
|
|
1551
1637
|
|
|
1638
|
+
lines.push(...renderBootstrapNextSteps(summary, outcome));
|
|
1639
|
+
|
|
1552
1640
|
return lines.join("\n");
|
|
1553
1641
|
}
|