@lucasschirm/devinp 0.1.11 → 0.1.13
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 +36 -10
- package/bin/command.js +11 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,11 +34,21 @@ invalid JSON (… 0 bytes)"*. It now works harder to get the whole document:
|
|
|
34
34
|
- Prices are captured through a temp file in `os.tmpdir()` — a pipe stream from
|
|
35
35
|
`devin` can be truncated mid-write, so `devinp` points `devin`'s stdout at a
|
|
36
36
|
real file first. The temp file is always removed after the run.
|
|
37
|
-
- **Retries
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
- **Retries that take the terminal away from `devin`.** If an attempt yields no
|
|
38
|
+
usable JSON, `devinp` runs `devin` again, each time stripping more of the
|
|
39
|
+
interactive terminal off it:
|
|
40
|
+
|
|
41
|
+
| # | stdout goes to | environment | controlling terminal |
|
|
42
|
+
| - | ------------ | -------------------------------------------------------- | --------------------- |
|
|
43
|
+
| 1 | temp file | yours, untouched | yes — the healthy path, one `devin` call |
|
|
44
|
+
| 2 | temp file | `PAGER=cat`, `GIT_PAGER=cat`, `TERM=dumb`, `NO_COLOR=1`, `CI=1` | **none** |
|
|
45
|
+
| 3 | pipe | same | **none** |
|
|
46
|
+
|
|
47
|
+
Spawned in its own session, `devin` cannot open `/dev/tty`: a pager or a TUI
|
|
48
|
+
that paints a "click to show more" view onto the terminal has nowhere to
|
|
49
|
+
draw, so the document has to come out of stdout. Nothing lands on the screen
|
|
50
|
+
you are typing in, and Ctrl-C there no longer kills the lookup. The first
|
|
51
|
+
attempt that parses wins, so the healthy path is unchanged.
|
|
42
52
|
- Noise around the document is tolerated: ANSI colours, an update banner in
|
|
43
53
|
front, or the `pass a slug to --model` hint behind are stripped before the
|
|
44
54
|
JSON is parsed.
|
|
@@ -46,9 +56,11 @@ invalid JSON (… 0 bytes)"*. It now works harder to get the whole document:
|
|
|
46
56
|
prints a warning, and renders the partial table.
|
|
47
57
|
- A real CLI failure (not signed in, network down) is reported as-is instead of
|
|
48
58
|
being retried.
|
|
49
|
-
- If nothing worked, the error lists
|
|
50
|
-
timeout — and how to feed the data in yourself. That always works,
|
|
51
|
-
redirect or a pipe makes `devin` write the whole document in one go:
|
|
59
|
+
- If nothing worked, the error lists all three attempts — bytes, exit code,
|
|
60
|
+
stderr, timeout — and how to feed the data in yourself. That always works,
|
|
61
|
+
because a redirect or a pipe makes `devin` write the whole document in one go:
|
|
62
|
+
(and if it does not, `command -v devin` tells you whether devinp is even
|
|
63
|
+
talking to the CLI and not to a shell function or agent wrapper around it).
|
|
52
64
|
|
|
53
65
|
```sh
|
|
54
66
|
devin models list --format json > models.json && devinp --source models.json
|
|
@@ -125,11 +137,25 @@ so `npm publish`, git-URL installs, and `npm link` always ship a fresh bundle.
|
|
|
125
137
|
|
|
126
138
|
## Publishing
|
|
127
139
|
|
|
128
|
-
`.github/workflows/publish.yml`
|
|
129
|
-
[npm trusted publishing](https://docs.npmjs.
|
|
140
|
+
`.github/workflows/publish.yml` publishes a patch release on every push to main
|
|
141
|
+
with [npm trusted publishing](https://docs.npmjs.org/trusted-publishers) (OIDC —
|
|
130
142
|
no `NPM_TOKEN`). Requires the trusted publisher to be configured on npmjs.com:
|
|
131
143
|
repository `lucasschirm/devinp`, workflow `publish.yml`.
|
|
132
144
|
|
|
145
|
+
It **never commits to main** — the branch ruleset requires every change to
|
|
146
|
+
arrive through a pull request, and a rejected release commit used to strand the
|
|
147
|
+
publish step that ran after it (GH013, then `npm publish` skipped). The released
|
|
148
|
+
version therefore lives in the npm registry and in the git tag, not in main's
|
|
149
|
+
`package.json`:
|
|
150
|
+
|
|
151
|
+
```sh
|
|
152
|
+
git ls-remote --tags origin # released versions
|
|
153
|
+
npm view @lucasschirm/devinp version # latest published
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The workflow takes the first patch number that is free in both places, so a tag
|
|
157
|
+
left behind by an older run cannot wedge it.
|
|
158
|
+
|
|
133
159
|
## License
|
|
134
160
|
|
|
135
161
|
MIT
|
package/bin/command.js
CHANGED
|
@@ -55095,10 +55095,11 @@ var NON_INTERACTIVE_ENV = {
|
|
|
55095
55095
|
NO_COLOR: "1",
|
|
55096
55096
|
CI: "1"
|
|
55097
55097
|
};
|
|
55098
|
+
var DETACHED_SPAWN = { detached: true, windowsHide: true };
|
|
55098
55099
|
var STRATEGIES = [
|
|
55099
55100
|
{ label: "temp file", file: true, env: null },
|
|
55100
|
-
{ label: "temp file
|
|
55101
|
-
{ label: "pipe
|
|
55101
|
+
{ label: "temp file, paging disabled, no controlling terminal", file: true, env: NON_INTERACTIVE_ENV, detached: true },
|
|
55102
|
+
{ label: "pipe, paging disabled, no controlling terminal", file: false, env: NON_INTERACTIVE_ENV, detached: true }
|
|
55102
55103
|
];
|
|
55103
55104
|
var ANSI = /\u001b\[[0-9;?]*[ -/]*[@-~]|\u001b\][\s\S]*?(?:\u0007|\u001b\\)|\u001b[@-Z\\-_]/g;
|
|
55104
55105
|
function stripAnsi(text) {
|
|
@@ -55120,11 +55121,12 @@ function parseJsonLoosely(text) {
|
|
|
55120
55121
|
}
|
|
55121
55122
|
return null;
|
|
55122
55123
|
}
|
|
55123
|
-
function spawnDevin({ command, env, stdout, timeoutMs }) {
|
|
55124
|
+
function spawnDevin({ command, env, stdout, timeoutMs, detached = false }) {
|
|
55124
55125
|
return new Promise((resolve, reject) => {
|
|
55125
55126
|
const child = spawn(command, ["models", "list", "--format", "json"], {
|
|
55126
55127
|
stdio: ["ignore", stdout, "pipe"],
|
|
55127
|
-
...env ? { env: { ...process.env, ...env } } : {}
|
|
55128
|
+
...env ? { env: { ...process.env, ...env } } : {},
|
|
55129
|
+
...detached ? DETACHED_SPAWN : {}
|
|
55128
55130
|
});
|
|
55129
55131
|
let stdoutText = "";
|
|
55130
55132
|
let stderr = "";
|
|
@@ -55149,11 +55151,11 @@ function spawnDevin({ command, env, stdout, timeoutMs }) {
|
|
|
55149
55151
|
});
|
|
55150
55152
|
});
|
|
55151
55153
|
}
|
|
55152
|
-
async function captureToFile({ command, env, timeoutMs }) {
|
|
55154
|
+
async function captureToFile({ command, env, timeoutMs, detached }) {
|
|
55153
55155
|
const file = join2(tmpdir(), `devinp-models-${process.pid}-${Date.now()}.json`);
|
|
55154
55156
|
const handle = await open(file, "w");
|
|
55155
55157
|
try {
|
|
55156
|
-
const result = await spawnDevin({ command, env, stdout: handle.fd, timeoutMs });
|
|
55158
|
+
const result = await spawnDevin({ command, env, stdout: handle.fd, timeoutMs, detached });
|
|
55157
55159
|
result.stdout = await readFile2(file, "utf8");
|
|
55158
55160
|
return result;
|
|
55159
55161
|
} finally {
|
|
@@ -55167,7 +55169,7 @@ async function runDevinJson({ command = "devin", timeoutMs = DEVIN_TIMEOUT_MS }
|
|
|
55167
55169
|
for (const [index, strategy] of STRATEGIES.entries()) {
|
|
55168
55170
|
let result;
|
|
55169
55171
|
try {
|
|
55170
|
-
result = strategy.file ? await captureToFile({ command, env: strategy.env, timeoutMs }) : await spawnDevin({ command, env: strategy.env, stdout: "pipe", timeoutMs });
|
|
55172
|
+
result = strategy.file ? await captureToFile({ command, env: strategy.env, timeoutMs, detached: strategy.detached }) : await spawnDevin({ command, env: strategy.env, stdout: "pipe", timeoutMs, detached: strategy.detached });
|
|
55171
55173
|
} catch (error) {
|
|
55172
55174
|
if (error.code === "ENOENT") throw error;
|
|
55173
55175
|
attempts.push({ label: strategy.label, bytes: 0, code: null, stderr: "", timedOut: false, note: error.message });
|
|
@@ -55222,7 +55224,7 @@ function describeFailure(attempts, timeoutMs) {
|
|
|
55222
55224
|
const lines = [];
|
|
55223
55225
|
if (bytes === 0) {
|
|
55224
55226
|
lines.push(
|
|
55225
|
-
'Unable to get model prices: `devin models list --format json` exited without writing the JSON to stdout (0 bytes).
|
|
55227
|
+
'Unable to get model prices: `devin models list --format json` exited without writing the JSON to stdout (0 bytes). devinp re-ran it with paging disabled and in a session with no controlling terminal, so the CLI had no terminal to paint a "click to show more" view on \u2014 whatever swallowed the output sits between devinp and `devin` (a shell function or agent wrapper around it, or a broken install).'
|
|
55226
55228
|
);
|
|
55227
55229
|
} else {
|
|
55228
55230
|
let parseError = "";
|
|
@@ -55239,7 +55241,7 @@ function describeFailure(attempts, timeoutMs) {
|
|
|
55239
55241
|
lines.push("Capture the JSON yourself and hand it to devinp \u2014 piping or redirecting makes `devin` write the whole document in one go:");
|
|
55240
55242
|
lines.push(" devin models list --format json > models.json && devinp --source models.json");
|
|
55241
55243
|
lines.push(" devin models list --format json | devinp --source=-");
|
|
55242
|
-
lines.push("
|
|
55244
|
+
lines.push("Check `command -v devin` \u2014 if that is not the real CLI, devinp is asking the wrong program. If a plain redirect still prints a paged view, update the CLI (`devin update`).");
|
|
55243
55245
|
return lines.join("\n");
|
|
55244
55246
|
}
|
|
55245
55247
|
async function readStdin() {
|