@indigoai-us/hq-cli 5.345.35 → 5.345.36

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.
@@ -50,5 +50,22 @@ export declare const __test__: {
50
50
  waitForUpdateRequest: typeof waitForUpdateRequest;
51
51
  setCurrentPackageUseLease(lease: PackageUseLease | null): void;
52
52
  };
53
+ /**
54
+ * Run `wait` with this process's package-use lease DROPPED, then reacquire the
55
+ * lease before returning.
56
+ *
57
+ * `hq sync` runs under purpose `"command"`, and
58
+ * {@link releasePackageUseLeaseAfterCommandLoad} deliberately keeps that lease
59
+ * for the whole command. hq-cloud's per-root operation lock then waits — by
60
+ * default without a bound — for whichever process is already syncing, so an old
61
+ * `hq` install pinned `hq pkg update` for the entire length of somebody else's
62
+ * lock wait (HQ-DESKTOP-8H). Queuing is not using the package: drop the lease
63
+ * while this process is only waiting, and take it again once the wait is over.
64
+ *
65
+ * A reacquire that throws {@link PackageUseUpdatePendingError} is the correct
66
+ * outcome — an update landed while we queued — and propagates to the caller. On
67
+ * the failure path the original error wins and the reacquire is best-effort.
68
+ */
69
+ export declare function withPackageUseLeaseReleasedDuring<T>(wait: () => Promise<T>, argv?: readonly string[], release?: () => void, reacquire?: (argv: readonly string[]) => unknown): Promise<T>;
53
70
  export {};
54
71
  //# sourceMappingURL=package-use-lease.d.ts.map
@@ -413,4 +413,40 @@ export const __test__ = {
413
413
  currentPackageUseLease = lease;
414
414
  },
415
415
  };
416
+ /**
417
+ * Run `wait` with this process's package-use lease DROPPED, then reacquire the
418
+ * lease before returning.
419
+ *
420
+ * `hq sync` runs under purpose `"command"`, and
421
+ * {@link releasePackageUseLeaseAfterCommandLoad} deliberately keeps that lease
422
+ * for the whole command. hq-cloud's per-root operation lock then waits — by
423
+ * default without a bound — for whichever process is already syncing, so an old
424
+ * `hq` install pinned `hq pkg update` for the entire length of somebody else's
425
+ * lock wait (HQ-DESKTOP-8H). Queuing is not using the package: drop the lease
426
+ * while this process is only waiting, and take it again once the wait is over.
427
+ *
428
+ * A reacquire that throws {@link PackageUseUpdatePendingError} is the correct
429
+ * outcome — an update landed while we queued — and propagates to the caller. On
430
+ * the failure path the original error wins and the reacquire is best-effort.
431
+ */
432
+ export async function withPackageUseLeaseReleasedDuring(wait, argv = process.argv, release = releaseCurrentPackageUseLease, reacquire = acquireCurrentPackageUseLease) {
433
+ if (currentPackageUseLease === null)
434
+ return wait();
435
+ release();
436
+ let result;
437
+ try {
438
+ result = await wait();
439
+ }
440
+ catch (error) {
441
+ try {
442
+ reacquire(argv);
443
+ }
444
+ catch {
445
+ // The caller's error is the one worth reporting.
446
+ }
447
+ throw error;
448
+ }
449
+ reacquire(argv);
450
+ return result;
451
+ }
416
452
  //# sourceMappingURL=package-use-lease.js.map
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Take hq-cloud's per-root operation lock for a sync pass from hq-cli, so the
3
+ * wait for an existing holder happens OUTSIDE this process's package-use lease.
4
+ *
5
+ * `sync()` normally wraps itself in `withOperationLock`, which waits for a live
6
+ * holder with no bound unless `HQ_OP_LOCK_TIMEOUT` says otherwise. `hq sync`
7
+ * runs under package-use purpose `"command"`, whose lease is held for the whole
8
+ * command, so the queued process pinned the installed `hq` version — and
9
+ * therefore blocked `hq pkg update` — for the entire length of somebody else's
10
+ * sync (HQ-DESKTOP-8H).
11
+ *
12
+ * Acquiring the lock here instead lets the lease be dropped across the wait and
13
+ * retaken the moment the lock is held, before any sync work runs.
14
+ * `operationLockAlreadyHeld` is the seam hq-cloud exposes for a caller that owns
15
+ * the lock; the lock is NOT reentrant in-process, so the flag is required rather
16
+ * than optional.
17
+ */
18
+ import { type SyncOptions, type SyncResult } from "@indigoai-us/hq-cloud";
19
+ import { type LockHandle } from "@indigoai-us/hq-cloud/operation-lock";
20
+ export interface SyncUnderOperationLockDeps<Options, Result> {
21
+ sync: (options: Options & {
22
+ operationLockAlreadyHeld: true;
23
+ }) => Promise<Result>;
24
+ /** Injected in tests; defaults to hq-cloud's wait-capable acquisition. */
25
+ acquireLock?: (hqRoot: string) => Promise<LockHandle>;
26
+ /** Injected in tests; defaults to the real lease drop/retake. */
27
+ withLeaseReleased?: <T>(wait: () => Promise<T>) => Promise<T>;
28
+ }
29
+ export declare function syncUnderOperationLock<Options extends {
30
+ hqRoot: string;
31
+ }, Result>(options: Options, deps: SyncUnderOperationLockDeps<Options, Result>): Promise<Result>;
32
+ /**
33
+ * The production sync leg: hq-cloud's `sync()` under a lock this process takes
34
+ * itself. Every `hq sync` path in `src/commands/cloud.ts` calls this.
35
+ */
36
+ export declare function syncLeg(options: SyncOptions): Promise<SyncResult>;
37
+ //# sourceMappingURL=sync-operation-lock.d.ts.map
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Take hq-cloud's per-root operation lock for a sync pass from hq-cli, so the
3
+ * wait for an existing holder happens OUTSIDE this process's package-use lease.
4
+ *
5
+ * `sync()` normally wraps itself in `withOperationLock`, which waits for a live
6
+ * holder with no bound unless `HQ_OP_LOCK_TIMEOUT` says otherwise. `hq sync`
7
+ * runs under package-use purpose `"command"`, whose lease is held for the whole
8
+ * command, so the queued process pinned the installed `hq` version — and
9
+ * therefore blocked `hq pkg update` — for the entire length of somebody else's
10
+ * sync (HQ-DESKTOP-8H).
11
+ *
12
+ * Acquiring the lock here instead lets the lease be dropped across the wait and
13
+ * retaken the moment the lock is held, before any sync work runs.
14
+ * `operationLockAlreadyHeld` is the seam hq-cloud exposes for a caller that owns
15
+ * the lock; the lock is NOT reentrant in-process, so the flag is required rather
16
+ * than optional.
17
+ */
18
+ import { sync } from "@indigoai-us/hq-cloud";
19
+ import { acquireOperationLockAsync, } from "@indigoai-us/hq-cloud/operation-lock";
20
+ import { withPackageUseLeaseReleasedDuring } from "./package-use-lease.js";
21
+ export async function syncUnderOperationLock(options, deps) {
22
+ const acquireLock = deps.acquireLock ?? ((hqRoot) => acquireOperationLockAsync(hqRoot, "sync"));
23
+ const withLeaseReleased = deps.withLeaseReleased ??
24
+ ((wait) => withPackageUseLeaseReleasedDuring(wait));
25
+ const handle = await withLeaseReleased(() => acquireLock(options.hqRoot));
26
+ try {
27
+ return await deps.sync({ ...options, operationLockAlreadyHeld: true });
28
+ }
29
+ finally {
30
+ handle.release();
31
+ }
32
+ }
33
+ /**
34
+ * The production sync leg: hq-cloud's `sync()` under a lock this process takes
35
+ * itself. Every `hq sync` path in `src/commands/cloud.ts` calls this.
36
+ */
37
+ export function syncLeg(options) {
38
+ return syncUnderOperationLock(options, { sync });
39
+ }
40
+ //# sourceMappingURL=sync-operation-lock.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.345.35",
3
+ "version": "5.345.36",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -48,7 +48,7 @@
48
48
  "@aws-sdk/client-iot-data-plane": "^3.1096.0",
49
49
  "@aws-sdk/client-s3": "^3.1049.0",
50
50
  "@aws-sdk/dsql-signer": "^3.1146.0",
51
- "@indigoai-us/hq-cloud": "~6.18.33",
51
+ "@indigoai-us/hq-cloud": "~6.18.50",
52
52
  "@indigoai-us/hq-flags-client": "^0.1.2",
53
53
  "@modelcontextprotocol/sdk": "1.29.0",
54
54
  "@sentry/node": "^10.49.0",