loadout-ai 0.9.2 → 0.9.4

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.
@@ -4,6 +4,7 @@ import { join } from "node:path";
4
4
  const LOCK_FILE = "coordination.lock";
5
5
  const DEFAULT_TIMEOUT_MS = 10_000;
6
6
  const MALFORMED_LOCK_STALE_MS = 30_000;
7
+ const localLockTails = new Map();
7
8
  export class CoordinationLockTimeoutError extends Error {
8
9
  constructor(timeoutMs) {
9
10
  super(`Timed out waiting ${timeoutMs}ms for the coordination lock`);
@@ -64,9 +65,25 @@ async function releaseOwnedLock(path, token) {
64
65
  function wait(delayMs) {
65
66
  return new Promise((resolve) => setTimeout(resolve, delayMs));
66
67
  }
67
- /** Serialize coordination mutations across Node processes sharing a project. */
68
- export async function withCoordinationLock(coordinationDir, operation, timeoutMs = DEFAULT_TIMEOUT_MS) {
69
- const path = join(coordinationDir, LOCK_FILE);
68
+ async function withLocalLock(path, operation) {
69
+ const previous = localLockTails.get(path) ?? Promise.resolve();
70
+ let release = () => undefined;
71
+ const current = new Promise((resolve) => {
72
+ release = resolve;
73
+ });
74
+ const tail = previous.then(() => current);
75
+ localLockTails.set(path, tail);
76
+ await previous;
77
+ try {
78
+ return await operation();
79
+ }
80
+ finally {
81
+ release();
82
+ if (localLockTails.get(path) === tail)
83
+ localLockTails.delete(path);
84
+ }
85
+ }
86
+ async function withFileLock(path, operation, timeoutMs) {
70
87
  const deadline = Date.now() + timeoutMs;
71
88
  const token = randomUUID();
72
89
  const owner = {
@@ -138,3 +155,8 @@ export async function withCoordinationLock(coordinationDir, operation, timeoutMs
138
155
  await releaseOwnedLock(path, token);
139
156
  }
140
157
  }
158
+ /** Serialize coordination mutations within this process and across processes. */
159
+ export async function withCoordinationLock(coordinationDir, operation, timeoutMs = DEFAULT_TIMEOUT_MS) {
160
+ const path = join(coordinationDir, LOCK_FILE);
161
+ return withLocalLock(path, () => withFileLock(path, operation, timeoutMs));
162
+ }
@@ -5,8 +5,10 @@ Loadout — manage the skills, tools, and MCP servers your AI agents use.
5
5
  FIRST TIME
6
6
 
7
7
  loadout doctor which agents you have, and whether they are healthy
8
- loadout setup --mode stable preview 30 reviewed skills (nothing changes)
9
- loadout setup --mode stable --yes install them
8
+ loadout setup --mode stable --details
9
+ preview 30 reviewed skills and findings
10
+ loadout setup --mode stable --yes --approve-risk
11
+ install only after reviewing those findings
10
12
 
11
13
  IN A PROJECT
12
14