@retasc/cli 1.31.0 → 1.31.1
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 +10 -0
- package/dist/commands/bind.js +5 -2
- package/dist/lib/launcher.js +65 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,16 @@ release commits and the issues they reference.
|
|
|
6
6
|
|
|
7
7
|
Dates are the npm publish date. Each entry names the RTSC issue behind it.
|
|
8
8
|
|
|
9
|
+
## 1.31.1 (2026-08-23)
|
|
10
|
+
|
|
11
|
+
- **RTSC-715** — setup no longer finishes by wiring a `retasc` command that is not there.
|
|
12
|
+
Run as `npx @retasc/cli@latest bind`, the CLI asked whether `retasc` was on your PATH
|
|
13
|
+
and got yes, because npx puts its own cache directory on the PATH of whatever it runs.
|
|
14
|
+
So the answer was true while `bind` ran and false the moment it exited, and your agent
|
|
15
|
+
started with `ENOENT: Executable not found in $PATH: "retasc"` after a setup that had
|
|
16
|
+
reported success. It now checks that the command it found will still resolve afterwards,
|
|
17
|
+
and falls back to a global install or a pinned `npx` launcher when it will not.
|
|
18
|
+
|
|
9
19
|
## 1.31.0 (2026-08-23)
|
|
10
20
|
|
|
11
21
|
- **RTSC-713** — your agent can set Retasc up for you. It runs `bind` itself now, so
|
package/dist/commands/bind.js
CHANGED
|
@@ -5,7 +5,7 @@ import { loadConfig, patchConfig } from "../config.js";
|
|
|
5
5
|
import { installMarker, printMarkerBlock } from "./mcp.js";
|
|
6
6
|
import { readLocalBinding, resolveBinding } from "../lib/binding.js";
|
|
7
7
|
import { getBinding, setBinding, newWorkspaceId } from "../lib/keystore.js";
|
|
8
|
-
import { resolveLauncher, launcherNote,
|
|
8
|
+
import { resolveLauncher, launcherNote, onDurablePath, selfCommand, versionStamp } from "../lib/launcher.js";
|
|
9
9
|
import { ask, confirm, isInteractive } from "../lib/prompt.js";
|
|
10
10
|
import { clean } from "../lib/text.js";
|
|
11
11
|
import { card, DOT } from "../lib/card.js";
|
|
@@ -177,7 +177,10 @@ export async function chooseInstall(
|
|
|
177
177
|
flag, deps = {}) {
|
|
178
178
|
if (flag === false)
|
|
179
179
|
return false;
|
|
180
|
-
|
|
180
|
+
// RTSC-715 — the same durable-PATH question `resolveLauncher` asks. Under npx a bare
|
|
181
|
+
// `retasc` resolves into the npx cache, so this shortcut used to conclude "nothing to
|
|
182
|
+
// install" on a machine that had nothing installed.
|
|
183
|
+
const onPath = deps.onPath ?? (() => onDurablePath("retasc"));
|
|
181
184
|
// Nothing to install, so nothing to ask.
|
|
182
185
|
if (onPath())
|
|
183
186
|
return true;
|
package/dist/lib/launcher.js
CHANGED
|
@@ -37,6 +37,59 @@ export function runsOk(command, args = []) {
|
|
|
37
37
|
// different program, and pointing a marker at it would be worse than not writing one.
|
|
38
38
|
return /^\d+\.\d+\.\d+/.test(out) ? out : null;
|
|
39
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Is `retasc` on PATH in a way that OUTLIVES this process (RTSC-715)?
|
|
42
|
+
*
|
|
43
|
+
* `runsOk("retasc")` answers a subtly different question, and the difference cost a
|
|
44
|
+
* fresh-machine setup its tools. When `bind` runs under `npx @retasc/cli@latest`, npx puts
|
|
45
|
+
* its own cache directory on the child's PATH, so `retasc` resolves and runs:
|
|
46
|
+
*
|
|
47
|
+
* outside npx: which retasc => /Users/me/.npm-global/bin/retasc
|
|
48
|
+
* inside npx: which retasc => /Users/me/.npm/_npx/ccd2a9…/node_modules/.bin/retasc
|
|
49
|
+
*
|
|
50
|
+
* `resolveLauncher` read that as "already usable, leave it alone" and wrote a bare
|
|
51
|
+
* `retasc` into the marker, marked verified, having genuinely run it. Then npx exited,
|
|
52
|
+
* that directory left PATH, and the MCP client spawning the proxy got
|
|
53
|
+
* `ENOENT: Executable not found in $PATH: "retasc"`. Setup reported success, the Dash
|
|
54
|
+
* showed a healthy workspace, and no tools loaded.
|
|
55
|
+
*
|
|
56
|
+
* The probe was not sloppy. It measured the right thing on the wrong PATH: the one `bind`
|
|
57
|
+
* inherited, rather than the one the agent spawns with later. So resolve the command to a
|
|
58
|
+
* real path and reject the npx cache, which is transient by construction — the whole point
|
|
59
|
+
* of `_npx` is that it is not a durable install.
|
|
60
|
+
*
|
|
61
|
+
* Resolved with `which`/`where` rather than by walking PATH ourselves: that is the lookup
|
|
62
|
+
* the shell will actually do, PATHEXT and all, and reimplementing it is how this class of
|
|
63
|
+
* bug gets a second edition.
|
|
64
|
+
*
|
|
65
|
+
* Anything unresolvable answers FALSE, deliberately. Every caller fallback (global install,
|
|
66
|
+
* absolute path, pinned npx) still produces something that runs, whereas a wrong "yes"
|
|
67
|
+
* produces a marker that cannot start. The two errors are not symmetric.
|
|
68
|
+
*/
|
|
69
|
+
export function onDurablePath(command = "retasc") {
|
|
70
|
+
let r;
|
|
71
|
+
try {
|
|
72
|
+
r = spawnSync(WIN ? "where" : "which", [command], {
|
|
73
|
+
encoding: "utf8",
|
|
74
|
+
shell: WIN,
|
|
75
|
+
timeout: 60_000,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
if (r.error || r.status !== 0)
|
|
82
|
+
return false;
|
|
83
|
+
// `where` can print several matches; the first is the one that would run.
|
|
84
|
+
const resolved = (r.stdout || "").trim().split(/\r?\n/)[0]?.trim();
|
|
85
|
+
if (!resolved)
|
|
86
|
+
return false;
|
|
87
|
+
// The npx cache. Separators on both sides, so a project that happens to live in a
|
|
88
|
+
// directory called `_npx` is not caught by it.
|
|
89
|
+
if (/[\\/]_npx[\\/]/.test(resolved))
|
|
90
|
+
return false;
|
|
91
|
+
return runsOk(resolved) !== null;
|
|
92
|
+
}
|
|
40
93
|
/** npm's global prefix, or null when npm itself can't be run. */
|
|
41
94
|
export function npmGlobalPrefix() {
|
|
42
95
|
let r;
|
|
@@ -156,8 +209,12 @@ function installGlobal(version) {
|
|
|
156
209
|
* anyone asking. It is pinned here for exactly that reason.
|
|
157
210
|
*/
|
|
158
211
|
export function resolveLauncher(opts) {
|
|
159
|
-
// 1. Already usable? Leave it alone.
|
|
160
|
-
|
|
212
|
+
// 1. Already usable, and still usable after we exit? Leave it alone.
|
|
213
|
+
//
|
|
214
|
+
// RTSC-715 — `onDurablePath`, not `runsOk`. Under npx the bare name resolves into the
|
|
215
|
+
// npx cache, which disappears when the command ends, so this branch used to write a
|
|
216
|
+
// marker that could not start.
|
|
217
|
+
if (onDurablePath("retasc")) {
|
|
161
218
|
return { launcher: { command: "retasc", args: [] }, how: "on-path", verified: true };
|
|
162
219
|
}
|
|
163
220
|
const npxLauncher = { command: "npx", args: ["-y", `${PKG}@${opts.version}`] };
|
|
@@ -176,7 +233,12 @@ export function resolveLauncher(opts) {
|
|
|
176
233
|
// 3. Prove it, by running it. An exit code of 0 is not evidence the command resolves:
|
|
177
234
|
// npm can install happily into a prefix whose bin directory PATH never searches.
|
|
178
235
|
if (!failure) {
|
|
179
|
-
|
|
236
|
+
// RTSC-715 — `onDurablePath` here too, and this one is the subtler half. Under npx the
|
|
237
|
+
// bare name still resolves to the npx cache AHEAD of the global bin we just installed
|
|
238
|
+
// into, so a successful install would have been confirmed by running the wrong binary
|
|
239
|
+
// and written the same unusable marker. The absolute-path loop below then covers the
|
|
240
|
+
// real case this branch exists for: installed, but PATH cannot see it.
|
|
241
|
+
if (onDurablePath("retasc")) {
|
|
180
242
|
return { launcher: { command: "retasc", args: [] }, how: "installed", verified: true };
|
|
181
243
|
}
|
|
182
244
|
// Installed, but PATH can't see it. Name the file directly — this is the case a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retasc/cli",
|
|
3
|
-
"version": "1.31.
|
|
3
|
+
"version": "1.31.1",
|
|
4
4
|
"description": "Retasc CLI \u2014 the issue tracker AI agents pull work from. Sign in with GitHub or Google, create projects, mint agent API keys, and wire your agent to the Retasc MCP server in one command.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|