@thisisamank/noenv-cli 0.2.0 → 0.2.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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.1 — 2026-11-13
4
+
5
+ The shell signs you in on its own again, instead of asking you to run `noenv auth`.
6
+
7
+ ### Fixed
8
+
9
+ - The background sign-in keeps waiting through network errors, server errors, and rate limits. Before, a Wi-Fi drop or a laptop waking from sleep stopped it, and the shell asked you to run `noenv auth`.
10
+ - When a sign-in is pending but the process that waits for it has stopped, the shell starts a new one.
11
+ - After a sign-in fails or its code expires, entering the repository again starts a new sign-in.
12
+
3
13
  ## 0.2.0 — 2026-11-13
4
14
 
5
15
  Coding agents and CI get their secrets with one command, secrets push to Cloudflare Workers, one CLI works with several teams, and `cd` is fast again.
package/dist/noenv.js CHANGED
@@ -79,7 +79,7 @@ import { join as join3 } from "node:path";
79
79
  // package.json
80
80
  var package_default = {
81
81
  name: "@thisisamank/noenv-cli",
82
- version: "0.2.0",
82
+ version: "0.2.1",
83
83
  description: "Encrypted environment variables that load when you cd into a repo. CLI for noenv.",
84
84
  type: "module",
85
85
  bin: {
@@ -342,6 +342,25 @@ async function startSignIn(deployment) {
342
342
  return { pending, started: true };
343
343
  }
344
344
  async function waitForSignIn(deployment, pending) {
345
+ await writeJsonFile(pollerPath(deployment), { pid: process.pid });
346
+ try {
347
+ return await poll(deployment, pending);
348
+ } finally {
349
+ const poller = await readJsonFile(pollerPath(deployment));
350
+ if (poller?.pid === process.pid) await removeFile(pollerPath(deployment));
351
+ }
352
+ }
353
+ async function pollerRunning(deployment) {
354
+ const poller = await readJsonFile(pollerPath(deployment));
355
+ if (!poller) return false;
356
+ try {
357
+ process.kill(poller.pid, 0);
358
+ return true;
359
+ } catch (error) {
360
+ return error.code === "EPERM";
361
+ }
362
+ }
363
+ async function poll(deployment, pending) {
345
364
  while (pending.expiresAt > Date.now()) {
346
365
  await sleep(pending.interval * 1e3);
347
366
  try {
@@ -353,7 +372,7 @@ async function waitForSignIn(deployment, pending) {
353
372
  await ensureIdentity(deployment, session.token);
354
373
  return true;
355
374
  } catch (error) {
356
- if (!(error instanceof ApiError) || error.message !== "authorization_pending") break;
375
+ if (!isRetryable(error)) break;
357
376
  }
358
377
  }
359
378
  await removeFile(pendingPath(deployment));
@@ -373,6 +392,13 @@ function startBackgroundPoller(deployment) {
373
392
  stdio: "ignore"
374
393
  }).unref();
375
394
  }
395
+ function isRetryable(error) {
396
+ if (!(error instanceof ApiError)) return true;
397
+ return error.message === "authorization_pending" || error.status === 429 || error.status >= 500;
398
+ }
399
+ function pollerPath(deployment) {
400
+ return join3(deployment.dir, "sign-in-poller.json");
401
+ }
376
402
  function sessionPath(deployment) {
377
403
  return join3(deployment.dir, "session.json");
378
404
  }
@@ -1838,7 +1864,7 @@ async function load(input, resolved, state, revision, messages) {
1838
1864
  const empty = { url: deployment.url, repo: target.repo, environment: target.environment, previous: {}, retry: false };
1839
1865
  const restore = state ? restoreLines(state) : [];
1840
1866
  if (!await loadSession(deployment)) {
1841
- return { lines: restore, state: await signIn(input, deployment, empty, state, messages), refresh: false };
1867
+ return { lines: restore, state: await signIn(input, deployment, empty, state, entering, messages), refresh: false };
1842
1868
  }
1843
1869
  const entry = await readCache(deployment, target);
1844
1870
  const identity = await loadIdentity(deployment);
@@ -1888,18 +1914,16 @@ async function openEntry(entry, privateKey, target, messages) {
1888
1914
  function sameTarget(state, { target, deployment }) {
1889
1915
  return state.url === deployment.url && state.repo === target.repo && state.environment === target.environment;
1890
1916
  }
1891
- async function signIn(input, deployment, empty, state, messages) {
1917
+ async function signIn(input, deployment, empty, state, entering, messages) {
1892
1918
  const waiting = await readPendingSignIn(deployment);
1893
- if (state?.notified && !(waiting && waiting.expiresAt > Date.now())) {
1894
- messages.push("sign-in was not completed, run `noenv auth` to try again");
1919
+ if (state?.notified && !entering && !(waiting && waiting.expiresAt > Date.now())) {
1920
+ messages.push("sign-in was not completed, enter the repository again or run `noenv auth` to retry");
1895
1921
  return empty;
1896
1922
  }
1897
1923
  try {
1898
1924
  const { pending, started } = await startSignIn(deployment);
1899
- if (started) {
1900
- input.startPoller(deployment);
1901
- input.openBrowser(pending.url);
1902
- }
1925
+ if (started) input.openBrowser(pending.url);
1926
+ if (started || !await input.pollerRunning(deployment)) input.startPoller(deployment);
1903
1927
  if (started || state?.notified !== pending.userCode) {
1904
1928
  const account = deployment.account ? ` to ${deployment.account}` : "";
1905
1929
  messages.push(`sign in${account} to load secrets: open ${pending.url} and confirm the code ${pending.userCode}`);
@@ -2375,6 +2399,7 @@ async function hookEnvCommand([shell]) {
2375
2399
  state,
2376
2400
  resolveDeployment: (repo) => resolveDeployment(repo),
2377
2401
  startPoller: startBackgroundPoller,
2402
+ pollerRunning,
2378
2403
  startWatcher: (deployment) => void startWatcher(deployment),
2379
2404
  openBrowser
2380
2405
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thisisamank/noenv-cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Encrypted environment variables that load when you cd into a repo. CLI for noenv.",
5
5
  "type": "module",
6
6
  "bin": {