balladeer 0.0.3 → 0.0.5
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/bin/balladeer.js +49 -4
- package/package.json +1 -1
package/bin/balladeer.js
CHANGED
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
* Flags: --yes/-y skip the prompt; --download-only fetch + verify, print the path.
|
|
11
11
|
*/
|
|
12
12
|
const { createHash } = require("node:crypto");
|
|
13
|
-
const { mkdtempSync, writeFileSync, rmSync } = require("node:fs");
|
|
13
|
+
const { existsSync, mkdtempSync, writeFileSync, rmSync } = require("node:fs");
|
|
14
14
|
const { tmpdir } = require("node:os");
|
|
15
|
-
const { join } = require("node:path");
|
|
15
|
+
const { join, sep } = require("node:path");
|
|
16
16
|
const { spawnSync } = require("node:child_process");
|
|
17
17
|
const readline = require("node:readline");
|
|
18
18
|
|
|
@@ -82,10 +82,34 @@ async function main() {
|
|
|
82
82
|
return;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
// Volta, two traps (both hit live on a Volta machine): (1) it prepends its real-node bin dir
|
|
86
|
+
// to a child tool's PATH, so a bare `npm` here is the RAW npm that installs into the node
|
|
87
|
+
// image's globals — while the user's `balladeer` stays Volta's shim serving THIS bootstrapper
|
|
88
|
+
// (split-brain: every run is the installer again); (2) it stamps _VOLTA_TOOL_RECURSION into a
|
|
89
|
+
// shimmed tool's env, and the shim npm passes straight through to the raw npm when it sees it,
|
|
90
|
+
// so merely routing through $VOLTA_HOME/bin/npm changes nothing. Fix: spawn Volta's npm shim
|
|
91
|
+
// WITH the recursion guard scrubbed, so its global-install interception updates the package
|
|
92
|
+
// image the user's shim actually serves.
|
|
93
|
+
const childEnv = { ...process.env };
|
|
94
|
+
delete childEnv._VOLTA_TOOL_RECURSION;
|
|
95
|
+
// Volta detection cannot rely on env: inside a shimmed tool VOLTA_HOME is absent (the env
|
|
96
|
+
// carries only _VOLTA_TOOL_RECURSION). Our own node binary IS Volta's
|
|
97
|
+
// (<volta>/tools/image/node/<v>/bin/node), so derive the root from execPath, honoring
|
|
98
|
+
// VOLTA_HOME when it is set (custom install locations).
|
|
99
|
+
const voltaMarker = `${sep}.volta${sep}`;
|
|
100
|
+
const voltaRoot =
|
|
101
|
+
process.env.VOLTA_HOME ??
|
|
102
|
+
(process.execPath.includes(voltaMarker)
|
|
103
|
+
? process.execPath.slice(0, process.execPath.indexOf(voltaMarker) + voltaMarker.length - 1)
|
|
104
|
+
: null);
|
|
105
|
+
const voltaBin = voltaRoot ? join(voltaRoot, "bin") : null;
|
|
106
|
+
const voltaNpm = voltaBin ? join(voltaBin, "npm") : null;
|
|
107
|
+
const npmCmd = voltaNpm && existsSync(voltaNpm) ? voltaNpm : "npm";
|
|
85
108
|
// --ignore-scripts: the client has no install hooks, and this keeps a hostile tarball from
|
|
86
109
|
// running code at install time (the same flag the script installer passes).
|
|
87
|
-
const r = spawnSync(
|
|
110
|
+
const r = spawnSync(npmCmd, ["install", "-g", "--ignore-scripts", file], {
|
|
88
111
|
stdio: "inherit",
|
|
112
|
+
env: childEnv,
|
|
89
113
|
shell: process.platform === "win32",
|
|
90
114
|
});
|
|
91
115
|
try {
|
|
@@ -95,6 +119,27 @@ async function main() {
|
|
|
95
119
|
fail(`error: npm install -g failed (exit ${r.status ?? "?"}). Fix the npm error above and re-run \`balladeer\`.`, r.status ?? 1);
|
|
96
120
|
}
|
|
97
121
|
|
|
122
|
+
// Never report success on npm's exit code alone: prove the world changed — AS THE USER'S SHELL
|
|
123
|
+
// SEES IT. Probe the Volta shim by absolute path when Volta is present (this process's PATH has
|
|
124
|
+
// Volta's image dirs prepended, so a bare probe can hit a copy the user's shell never resolves),
|
|
125
|
+
// with the recursion guard scrubbed so the shim re-resolves instead of echoing this bootstrapper.
|
|
126
|
+
const voltaShim = voltaBin ? join(voltaBin, "balladeer") : null;
|
|
127
|
+
const probeCmd = voltaShim && existsSync(voltaShim) ? voltaShim : "balladeer";
|
|
128
|
+
const probe = spawnSync(probeCmd, ["--version"], {
|
|
129
|
+
encoding: "utf8",
|
|
130
|
+
env: childEnv,
|
|
131
|
+
shell: process.platform === "win32",
|
|
132
|
+
});
|
|
133
|
+
const probedVersion = (probe.stdout ?? "").trim();
|
|
134
|
+
if (probe.status !== 0 || !/^\d+\.\d+\.\d+/.test(probedVersion)) {
|
|
135
|
+
fail(
|
|
136
|
+
`error: npm reported success, but \`balladeer\` on your PATH is not the client yet.\n` +
|
|
137
|
+
`Your npm setup may install globals somewhere this shell does not look, or a version\n` +
|
|
138
|
+
`manager may be serving a stale copy. Try a fresh shell and \`balladeer --version\`,\n` +
|
|
139
|
+
`or use the script installer:\n\n curl -fsSL ${BASE} | sh\n`,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
98
143
|
// Plain `balladeer login` (the client defaults to hosted central). BASE is the INSTALL host
|
|
99
144
|
// (get.balladeer.ai), an alias that exists only for downloading — teaching it as --server
|
|
100
145
|
// would store it as the machine's permanent server URL. A custom BALLADEER_INSTALL_BASE
|
|
@@ -105,7 +150,7 @@ async function main() {
|
|
|
105
150
|
? "balladeer login"
|
|
106
151
|
: "balladeer login --server <your central server URL>";
|
|
107
152
|
console.error(
|
|
108
|
-
`\n✓ Balladeer client installed.\n\n` +
|
|
153
|
+
`\n✓ Balladeer client installed (${probedVersion}).\n\n` +
|
|
109
154
|
` next ${pairHint} # approve in your browser; no token to copy\n` +
|
|
110
155
|
` then your coding agent gains get_context / consult / propose_decision\n` +
|
|
111
156
|
` agent or let your agent finish the wiring: paste into it -> Read ${BASE}/agent and follow it.\n\n` +
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "balladeer",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Installer for the Balladeer client (decision memory for engineering teams and their AI agents): downloads the sha256-verified client from get.balladeer.ai and installs it globally.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"homepage": "https://balladeer.ai",
|