@meistrari/remy-cli 1.4.0 → 1.4.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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/remy.js +180 -120
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -116,7 +116,7 @@ remy login \
116
116
  --target-application-id <target-application-uuid>
117
117
  ```
118
118
 
119
- Remy stores endpoint configuration in `~/.config/remy/config.json` and tokens in `~/.local/state/remy/tokens.json`. Set `XDG_CONFIG_HOME` or `XDG_STATE_HOME` to use different base directories. It refreshes an expired access token before each Coding Agent API request, so long-running sessions and reconnects remain authenticated. `remy logout` removes tokens but retains endpoint configuration; pass `--api-url` to require that the supplied URL matches the active API host before logging out.
119
+ Remy stores endpoint configuration in `~/.config/remy/config.json` and tokens in `~/.local/state/remy/tokens.json`. Set `XDG_CONFIG_HOME` or `XDG_STATE_HOME` to use different base directories. Before each Coding Agent API request, it reloads the shared token file and refreshes an expired access token. When multiple Remy processes run at once, only one rotates and saves the refresh-token pair; the others wait and then use that newest saved pair. Long-running sessions and reconnects therefore stay authenticated after another process refreshes. `remy logout` removes tokens but retains endpoint configuration; pass `--api-url` to require that the supplied URL matches the active API host before logging out.
120
120
 
121
121
  ## Complete command reference
122
122
 
package/dist/remy.js CHANGED
@@ -33234,16 +33234,21 @@ function loginUsage() {
33234
33234
  }
33235
33235
 
33236
33236
  // src/credential-state.ts
33237
- import { randomUUID as randomUUID2 } from "crypto";
33238
- import { lstat, mkdir as mkdir3, open as open3, readFile as readFile3, rename as rename2, unlink as unlink2 } from "fs/promises";
33237
+ import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
33238
+ import { lstat, mkdir as mkdir3, open as open3, readFile as readFile3, rename as rename2, rmdir, unlink as unlink2 } from "fs/promises";
33239
33239
  import { dirname as dirname3, join as join2 } from "path";
33240
+ import { setTimeout as delay } from "timers/promises";
33240
33241
  var lockName = ".credential-state.lock";
33242
+ var lockOwnerName = "owner.json";
33241
33243
  var journalName = ".credential-promotion.journal.json";
33244
+ var lockRetryMilliseconds = 25;
33242
33245
  async function withCredentialState({
33243
33246
  stateDirectory,
33247
+ signal,
33248
+ lockFilesystem,
33244
33249
  action
33245
33250
  }) {
33246
- const owner = await acquireCredentialStateLock(stateDirectory);
33251
+ const owner = await acquireCredentialStateLock({ stateDirectory, signal, renamePath: lockFilesystem?.renamePath });
33247
33252
  try {
33248
33253
  return await action();
33249
33254
  } finally {
@@ -33318,51 +33323,146 @@ async function removeCredentialTokenWhileLocked({
33318
33323
  function lockPath(stateDirectory) {
33319
33324
  return join2(stateDirectory, lockName);
33320
33325
  }
33321
- async function acquireCredentialStateLock(stateDirectory) {
33326
+ async function acquireCredentialStateLock({
33327
+ stateDirectory,
33328
+ signal,
33329
+ renamePath = rename2
33330
+ }) {
33322
33331
  await mkdir3(stateDirectory, { recursive: true, mode: 448 });
33323
33332
  const owner = { ownerId: randomUUID2(), pid: process.pid };
33324
33333
  const path = lockPath(stateDirectory);
33334
+ const candidatePath = join2(stateDirectory, `.credential-state.candidate.${owner.ownerId}`);
33335
+ await mkdir3(candidatePath, { mode: 448 });
33325
33336
  try {
33326
- await writeExclusivePrivateFile({ path, contents: `${JSON.stringify(owner)}
33337
+ await writeExclusivePrivateFile({ path: join2(candidatePath, lockOwnerName), contents: `${JSON.stringify(owner)}
33327
33338
  ` });
33328
- return owner;
33339
+ while (true) {
33340
+ throwIfAborted(signal);
33341
+ const recordedState = await readLockOwnerState(path);
33342
+ if (recordedState.status === "missing") {
33343
+ try {
33344
+ await renamePath(candidatePath, path);
33345
+ return owner;
33346
+ } catch (error93) {
33347
+ if (!isLockContentionError(error93))
33348
+ throw error93;
33349
+ continue;
33350
+ }
33351
+ }
33352
+ if (recordedState.status === "malformed")
33353
+ throw new Error("another Remy credential operation is active");
33354
+ const recordedOwner = recordedState.owner;
33355
+ if (!isPidAbsent(recordedOwner.pid)) {
33356
+ await waitForCredentialStateLock(signal);
33357
+ continue;
33358
+ }
33359
+ const confirmedState = await readLockOwnerState(path);
33360
+ if (confirmedState.status === "missing")
33361
+ continue;
33362
+ if (confirmedState.status === "malformed")
33363
+ throw new Error("another Remy credential operation is active");
33364
+ const confirmedOwner = confirmedState.owner;
33365
+ if (!sameLockOwner(confirmedOwner, recordedOwner) || !isPidAbsent(confirmedOwner.pid)) {
33366
+ await waitForCredentialStateLock(signal);
33367
+ continue;
33368
+ }
33369
+ await moveStaleLockAside({ stateDirectory, path, owner: recordedOwner, signal, renamePath });
33370
+ }
33329
33371
  } catch (error93) {
33330
- if (!isExistsError(error93))
33331
- throw error93;
33372
+ await removeLockDirectory({ path: candidatePath });
33373
+ throw error93;
33332
33374
  }
33333
- const recordedOwner = await readLockOwner(path);
33334
- if (!recordedOwner || !isPidAbsent(recordedOwner.pid))
33335
- throw new Error("another Remy credential operation is active");
33336
- const stalePath = join2(stateDirectory, `.credential-state.stale.${recordedOwner.ownerId}.${randomUUID2()}`);
33375
+ }
33376
+ async function moveStaleLockAside({
33377
+ stateDirectory,
33378
+ path,
33379
+ owner,
33380
+ signal,
33381
+ renamePath
33382
+ }) {
33383
+ const stalePath = join2(stateDirectory, `.credential-state.stale.${lockOwnerFingerprint(owner)}`);
33337
33384
  try {
33338
- await rename2(path, stalePath);
33339
- await removeIfPresent({ path: stalePath });
33340
- } catch {
33341
- throw new Error("another Remy credential operation is active");
33385
+ await renamePath(path, stalePath);
33386
+ } catch (error93) {
33387
+ if (isLockContentionError(error93)) {
33388
+ await waitForCredentialStateLock(signal);
33389
+ return;
33390
+ }
33391
+ if (isMissingFileError(error93))
33392
+ return;
33393
+ throw error93;
33342
33394
  }
33395
+ }
33396
+ function lockOwnerFingerprint(owner) {
33397
+ return createHash2("sha256").update(`${owner.ownerId}\x00${owner.pid}`).digest("hex");
33398
+ }
33399
+ function sameLockOwner(left, right) {
33400
+ return left?.ownerId === right.ownerId && left.pid === right.pid;
33401
+ }
33402
+ async function waitForCredentialStateLock(signal) {
33403
+ throwIfAborted(signal);
33343
33404
  try {
33344
- await writeExclusivePrivateFile({ path, contents: `${JSON.stringify(owner)}
33345
- ` });
33346
- return owner;
33347
- } catch {
33348
- throw new Error("another Remy credential operation is active");
33405
+ await delay(lockRetryMilliseconds, undefined, signal ? { signal } : undefined);
33406
+ } catch (error93) {
33407
+ if (signal?.aborted)
33408
+ throw signal.reason ?? error93;
33409
+ throw error93;
33349
33410
  }
33350
33411
  }
33412
+ function throwIfAborted(signal) {
33413
+ if (signal?.aborted)
33414
+ throw signal.reason ?? new Error("Credential operation aborted.");
33415
+ }
33351
33416
  async function releaseCredentialStateLock({ stateDirectory, owner }) {
33352
33417
  const path = lockPath(stateDirectory);
33353
33418
  const currentOwner = await readLockOwner(path);
33354
33419
  if (!currentOwner || currentOwner.ownerId !== owner.ownerId)
33355
33420
  return;
33356
- await removeIfPresent({ path });
33421
+ const releasedPath = join2(stateDirectory, `.credential-state.released.${owner.ownerId}.${randomUUID2()}`);
33422
+ try {
33423
+ await rename2(path, releasedPath);
33424
+ } catch (error93) {
33425
+ if (isMissingFileError(error93))
33426
+ return;
33427
+ throw error93;
33428
+ }
33429
+ await removeLockDirectory({ path: releasedPath });
33357
33430
  }
33358
33431
  async function readLockOwner(path) {
33432
+ const state = await readLockOwnerState(path);
33433
+ return state.status === "valid" ? state.owner : undefined;
33434
+ }
33435
+ async function readLockOwnerState(path) {
33436
+ const firstObservation = await observeLockOwner(path);
33437
+ if (firstObservation.status !== "owner-missing")
33438
+ return firstObservation;
33439
+ const secondObservation = await observeLockOwner(path);
33440
+ return secondObservation.status === "owner-missing" ? { status: "malformed" } : secondObservation;
33441
+ }
33442
+ async function observeLockOwner(path) {
33443
+ let ownerPath;
33359
33444
  try {
33360
- const parsed = JSON.parse(await readFile3(path, "utf8"));
33445
+ const metadata = await lstat(path);
33446
+ ownerPath = metadata.isDirectory() ? join2(path, lockOwnerName) : path;
33447
+ } catch (error93) {
33448
+ return isMissingFileError(error93) ? { status: "missing" } : { status: "malformed" };
33449
+ }
33450
+ try {
33451
+ const parsed = JSON.parse(await readFile3(ownerPath, "utf8"));
33361
33452
  if (!isLockOwner(parsed))
33362
- return;
33363
- return parsed;
33364
- } catch {
33365
- return;
33453
+ return { status: "malformed" };
33454
+ return { status: "valid", owner: parsed };
33455
+ } catch (error93) {
33456
+ return isMissingFileError(error93) ? { status: "owner-missing" } : { status: "malformed" };
33457
+ }
33458
+ }
33459
+ async function removeLockDirectory({ path }) {
33460
+ await removeIfPresent({ path: join2(path, lockOwnerName) });
33461
+ try {
33462
+ await rmdir(path);
33463
+ } catch (error93) {
33464
+ if (!isMissingFileError(error93))
33465
+ throw error93;
33366
33466
  }
33367
33467
  }
33368
33468
  function isLockOwner(value) {
@@ -33474,8 +33574,8 @@ async function syncParentDirectory(path) {
33474
33574
  await handle.close();
33475
33575
  }
33476
33576
  }
33477
- function isExistsError(error93) {
33478
- return error93 instanceof Error && "code" in error93 && error93.code === "EEXIST";
33577
+ function isLockContentionError(error93) {
33578
+ return error93 instanceof Error && "code" in error93 && (error93.code === "EEXIST" || error93.code === "ENOTEMPTY" || error93.code === "EISDIR" || error93.code === "ENOTDIR");
33479
33579
  }
33480
33580
  function isMissingFileError(error93) {
33481
33581
  return error93 instanceof Error && "code" in error93 && error93.code === "ENOENT";
@@ -37197,7 +37297,7 @@ var compactMarkRows = 9;
37197
37297
  var compactMinWidth = 48;
37198
37298
  var compactMinHeight = 20;
37199
37299
  var markBrightnessGain = 4.2;
37200
- var remyCliVersion = "1.4.0";
37300
+ var remyCliVersion = "1.4.1";
37201
37301
  async function showRemySplash({
37202
37302
  createRenderer = createRemyRenderer,
37203
37303
  durationMs = splashDurationMs,
@@ -37610,7 +37710,7 @@ function createCliShutdown({ abortSignal }) {
37610
37710
  function exitCodeForSignal(signal) {
37611
37711
  return signal === "SIGINT" ? 130 : 143;
37612
37712
  }
37613
- function throwIfAborted(signal) {
37713
+ function throwIfAborted2(signal) {
37614
37714
  if (signal?.aborted)
37615
37715
  throw signal.reason ?? new CliInterruptedError("SIGINT");
37616
37716
  }
@@ -37678,19 +37778,20 @@ ${approvalUrl}
37678
37778
  let journalPrepared = false;
37679
37779
  try {
37680
37780
  const tokens = await flow.authenticate();
37681
- throwIfAborted(dependencies.abortSignal);
37781
+ throwIfAborted2(dependencies.abortSignal);
37682
37782
  const candidateAuthConfiguration = toAuthConfiguration({ configuration, tokenPath: candidateTokenPath });
37683
37783
  const candidateClient = createCodingAgentClient({
37684
37784
  apiUrl: configuration.apiUrl,
37685
37785
  getAccessToken: async (signal) => await requireAccessToken(candidateAuthConfiguration, signal)
37686
37786
  });
37687
37787
  const identity = await materializeRemoteCurrentUser({ client: candidateClient, signal: dependencies.abortSignal });
37688
- throwIfAborted(dependencies.abortSignal);
37788
+ throwIfAborted2(dependencies.abortSignal);
37689
37789
  await onCandidateIdentityValidated?.({ email: identity.email });
37690
- throwIfAborted(dependencies.abortSignal);
37691
- throwIfAborted(dependencies.abortSignal);
37790
+ throwIfAborted2(dependencies.abortSignal);
37791
+ throwIfAborted2(dependencies.abortSignal);
37692
37792
  await withCredentialState({
37693
37793
  stateDirectory: dirname6(paths.tokenPath),
37794
+ signal: dependencies.abortSignal,
37694
37795
  action: async () => {
37695
37796
  await recoverCredentialPromotionWhileLocked({
37696
37797
  stateDirectory: dirname6(paths.tokenPath),
@@ -37762,7 +37863,7 @@ ${approvalUrl}
37762
37863
  });
37763
37864
  }
37764
37865
  });
37765
- throwIfAborted(dependencies.abortSignal);
37866
+ throwIfAborted2(dependencies.abortSignal);
37766
37867
  dependencies.output.writeStderr(`Signed in as ${tokens.user.email ?? tokens.user.name ?? "authenticated user"}.
37767
37868
  `);
37768
37869
  } catch (error93) {
@@ -37782,6 +37883,7 @@ async function logout({ dependencies, flags }) {
37782
37883
  const removeTokenFile = dependencies.removeTokenFile ?? unlink3;
37783
37884
  await withCredentialState({
37784
37885
  stateDirectory: dirname6(paths.tokenPath),
37886
+ signal: dependencies.abortSignal,
37785
37887
  action: async () => {
37786
37888
  await recoverCredentialPromotionWhileLocked({
37787
37889
  stateDirectory: dirname6(paths.tokenPath),
@@ -37838,6 +37940,7 @@ async function createAuthenticatedClient(dependencies) {
37838
37940
  const paths = resolveCliPaths(dependencies.environment);
37839
37941
  const snapshot = await withCredentialState({
37840
37942
  stateDirectory: dirname6(paths.tokenPath),
37943
+ signal: dependencies.abortSignal,
37841
37944
  action: async () => {
37842
37945
  await recoverCredentialPromotionWhileLocked({
37843
37946
  stateDirectory: dirname6(paths.tokenPath),
@@ -37846,64 +37949,33 @@ async function createAuthenticatedClient(dependencies) {
37846
37949
  ...dependencies.credentialStateFilesystem
37847
37950
  });
37848
37951
  const configuration = await readCliConfiguration(paths.configPath);
37849
- const tokenGeneration = await readOptionalTokenFile(paths.tokenPath);
37850
- return { configuration, tokenGeneration };
37952
+ return { configuration };
37851
37953
  }
37852
37954
  });
37853
37955
  const authConfiguration = toAuthConfiguration({ configuration: snapshot.configuration, tokenPath: paths.tokenPath });
37854
37956
  const identity = await loadStoredIdentity(authConfiguration);
37855
37957
  const getAccessToken = createRefreshingAccessTokenProvider({ dependencies, paths, snapshot });
37856
- try {
37857
- await getAccessToken(dependencies.abortSignal);
37858
- const client = createCodingAgentClient({
37859
- apiUrl: snapshot.configuration.apiUrl,
37860
- getAccessToken
37861
- });
37862
- const remoteIdentity = await materializeRemoteCurrentUser({ client, signal: dependencies.abortSignal });
37863
- return {
37864
- authConfiguration,
37865
- client,
37866
- identity,
37867
- authenticatedEmail: remoteIdentity.email
37868
- };
37869
- } catch (error93) {
37870
- if (error93 instanceof LoginRequiredError) {
37871
- await withCredentialState({
37872
- stateDirectory: dirname6(paths.tokenPath),
37873
- action: async () => {
37874
- await recoverCredentialPromotionWhileLocked({
37875
- stateDirectory: dirname6(paths.tokenPath),
37876
- configPath: paths.configPath,
37877
- tokenPath: paths.tokenPath,
37878
- ...dependencies.credentialStateFilesystem
37879
- });
37880
- await assertCredentialSnapshotCurrent({ paths, snapshot });
37881
- await removeCredentialTokenWhileLocked({
37882
- tokenPath: paths.tokenPath,
37883
- removeFile: dependencies.credentialStateFilesystem?.removeFile,
37884
- syncDirectory: dependencies.credentialStateFilesystem?.syncDirectory
37885
- });
37886
- }
37887
- });
37888
- }
37889
- throw error93;
37890
- }
37958
+ const client = createCodingAgentClient({
37959
+ apiUrl: snapshot.configuration.apiUrl,
37960
+ getAccessToken
37961
+ });
37962
+ const remoteIdentity = await materializeRemoteCurrentUser({ client, signal: dependencies.abortSignal });
37963
+ return {
37964
+ authConfiguration,
37965
+ client,
37966
+ identity,
37967
+ authenticatedEmail: remoteIdentity.email
37968
+ };
37891
37969
  }
37892
37970
  function createRefreshingAccessTokenProvider({
37893
37971
  dependencies,
37894
37972
  paths,
37895
37973
  snapshot
37896
37974
  }) {
37897
- let tokenGeneration = snapshot.tokenGeneration;
37898
37975
  let pendingAccessToken;
37899
37976
  return async (signal) => {
37900
- if (!pendingAccessToken) {
37901
- const expectedTokenGeneration = tokenGeneration;
37902
- pendingAccessToken = refreshAccessToken({ dependencies, paths, configuration: snapshot.configuration, expectedTokenGeneration, signal }).then(({ accessToken: accessToken2, tokenGeneration: refreshedTokenGeneration }) => {
37903
- tokenGeneration = refreshedTokenGeneration;
37904
- return accessToken2;
37905
- });
37906
- }
37977
+ if (!pendingAccessToken)
37978
+ pendingAccessToken = refreshAccessToken({ dependencies, paths, configuration: snapshot.configuration, signal });
37907
37979
  const accessToken = pendingAccessToken;
37908
37980
  try {
37909
37981
  return await accessToken;
@@ -37917,33 +37989,13 @@ async function refreshAccessToken({
37917
37989
  dependencies,
37918
37990
  paths,
37919
37991
  configuration,
37920
- expectedTokenGeneration,
37921
37992
  signal
37922
37993
  }) {
37923
37994
  const candidateTokenPath = await createCandidateTokenPath(paths.tokenPath);
37924
37995
  try {
37925
- await withCredentialState({
37926
- stateDirectory: dirname6(paths.tokenPath),
37927
- action: async () => {
37928
- await recoverCredentialPromotionWhileLocked({
37929
- stateDirectory: dirname6(paths.tokenPath),
37930
- configPath: paths.configPath,
37931
- tokenPath: paths.tokenPath,
37932
- ...dependencies.credentialStateFilesystem
37933
- });
37934
- await assertCredentialSnapshotCurrent({
37935
- paths,
37936
- snapshot: { configuration, tokenGeneration: expectedTokenGeneration }
37937
- });
37938
- if (expectedTokenGeneration !== undefined)
37939
- await writeFile4(candidateTokenPath, expectedTokenGeneration, { mode: 384 });
37940
- }
37941
- });
37942
- const candidateAuthConfiguration = toAuthConfiguration({ configuration, tokenPath: candidateTokenPath });
37943
- const accessToken = await requireAccessToken(candidateAuthConfiguration, signal);
37944
- const candidateTokenGeneration = await readFile5(candidateTokenPath, "utf8");
37945
- await withCredentialState({
37996
+ return await withCredentialState({
37946
37997
  stateDirectory: dirname6(paths.tokenPath),
37998
+ signal,
37947
37999
  action: async () => {
37948
38000
  await recoverCredentialPromotionWhileLocked({
37949
38001
  stateDirectory: dirname6(paths.tokenPath),
@@ -37951,11 +38003,28 @@ async function refreshAccessToken({
37951
38003
  tokenPath: paths.tokenPath,
37952
38004
  ...dependencies.credentialStateFilesystem
37953
38005
  });
37954
- await assertCredentialSnapshotCurrent({
37955
- paths,
37956
- snapshot: { configuration, tokenGeneration: expectedTokenGeneration }
37957
- });
37958
- if (candidateTokenGeneration !== expectedTokenGeneration) {
38006
+ const currentConfiguration = await readCliConfiguration(paths.configPath);
38007
+ if (!sameCliConfiguration(currentConfiguration, configuration))
38008
+ throw new Error("Credential configuration changed while preparing authentication. Retry the command.");
38009
+ const currentTokenGeneration = await readOptionalTokenFile(paths.tokenPath);
38010
+ if (currentTokenGeneration !== undefined)
38011
+ await writeFile4(candidateTokenPath, currentTokenGeneration, { mode: 384 });
38012
+ const candidateAuthConfiguration = toAuthConfiguration({ configuration, tokenPath: candidateTokenPath });
38013
+ let accessToken;
38014
+ try {
38015
+ accessToken = await requireAccessToken(candidateAuthConfiguration, signal);
38016
+ } catch (error93) {
38017
+ if (error93 instanceof LoginRequiredError) {
38018
+ await removeCredentialTokenWhileLocked({
38019
+ tokenPath: paths.tokenPath,
38020
+ removeFile: dependencies.credentialStateFilesystem?.removeFile,
38021
+ syncDirectory: dependencies.credentialStateFilesystem?.syncDirectory
38022
+ });
38023
+ }
38024
+ throw error93;
38025
+ }
38026
+ const candidateTokenGeneration = await readFile5(candidateTokenPath, "utf8");
38027
+ if (candidateTokenGeneration !== currentTokenGeneration) {
37959
38028
  await replaceCredentialTokenWhileLocked({
37960
38029
  sourcePath: candidateTokenPath,
37961
38030
  tokenPath: paths.tokenPath,
@@ -37963,22 +38032,13 @@ async function refreshAccessToken({
37963
38032
  syncDirectory: dependencies.credentialStateFilesystem?.syncDirectory
37964
38033
  });
37965
38034
  }
38035
+ return accessToken;
37966
38036
  }
37967
38037
  });
37968
- return { accessToken, tokenGeneration: candidateTokenGeneration };
37969
38038
  } finally {
37970
38039
  await removeCandidateToken({ path: candidateTokenPath, removeTokenFile: unlink3 });
37971
38040
  }
37972
38041
  }
37973
- async function assertCredentialSnapshotCurrent({
37974
- paths,
37975
- snapshot
37976
- }) {
37977
- const currentConfiguration = await readCliConfiguration(paths.configPath);
37978
- const currentTokenGeneration = await readOptionalTokenFile(paths.tokenPath);
37979
- if (!sameCliConfiguration(currentConfiguration, snapshot.configuration) || currentTokenGeneration !== snapshot.tokenGeneration)
37980
- throw new Error("Credential state changed while preparing authentication. Retry the command.");
37981
- }
37982
38042
  async function readOptionalTokenFile(path) {
37983
38043
  try {
37984
38044
  return await readFile5(path, "utf8");
@@ -38007,7 +38067,7 @@ async function dashboard({
38007
38067
  bootstrap
38008
38068
  }) {
38009
38069
  assertInteractiveDashboard(dependencies);
38010
- throwIfAborted(dependencies.abortSignal);
38070
+ throwIfAborted2(dependencies.abortSignal);
38011
38071
  const { operations, repositories, initialSessions } = bootstrap;
38012
38072
  const openDashboardTui = dependencies.openDashboardTui ?? createDashboardTui;
38013
38073
  const pages = [initialSessions];
@@ -38188,7 +38248,7 @@ async function authenticateBareDashboard({
38188
38248
  splash?.completeAuthentication({ email: email5 });
38189
38249
  }
38190
38250
  });
38191
- throwIfAborted(dependencies.abortSignal);
38251
+ throwIfAborted2(dependencies.abortSignal);
38192
38252
  return await awaitWithAbort({
38193
38253
  value: prepareDashboardBootstrap({
38194
38254
  dependencies,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/remy-cli",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "Remy, the Coding Agent terminal client.",
5
5
  "type": "module",
6
6
  "bin": {