wakeloop 0.1.0
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 +309 -0
- package/dist/add-me-membership-Dh1vHFLA.js +14 -0
- package/dist/add-me-membership-Dh1vHFLA.js.map +1 -0
- package/dist/api-client-foundation-Bw60iEgQ.js +6 -0
- package/dist/auth-session-CYafUSmo.js +6 -0
- package/dist/base-url-7O9DNTTC.js +907 -0
- package/dist/base-url-7O9DNTTC.js.map +1 -0
- package/dist/daemon-runtime-lease-BdIKGl39.js +6 -0
- package/dist/dist-BqpHxhFh.js +6 -0
- package/dist/dist-JdCv_fuW.js +10667 -0
- package/dist/dist-JdCv_fuW.js.map +1 -0
- package/dist/lock-BYUpcHBF.js +385 -0
- package/dist/lock-BYUpcHBF.js.map +1 -0
- package/dist/paths-F1dfknFj.js +210 -0
- package/dist/paths-F1dfknFj.js.map +1 -0
- package/dist/urls-B8ZoQgpS.js +102 -0
- package/dist/urls-B8ZoQgpS.js.map +1 -0
- package/dist/wakeloop-dev.js +26 -0
- package/dist/wakeloop-dev.js.map +1 -0
- package/dist/wakeloop.js +109271 -0
- package/dist/wakeloop.js.map +1 -0
- package/package.json +81 -0
- package/skills/README.md +27 -0
- package/skills/wakeloop-cli/SKILL.md +753 -0
- package/skills/wakeloop-cli/playbooks/agent-onboarding.md +164 -0
- package/skills/wakeloop-cli/playbooks/space-ops.md +279 -0
- package/skills/wakeloop-cli/references/commands.md +441 -0
- package/skills/wakeloop-cli/references/runtime-resolution.md +80 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { A as sessionsDir, x as normalizeWakeLoopProfileId, y as locksDir } from "./paths-F1dfknFj.js";
|
|
4
|
+
import process$1 from "node:process";
|
|
5
|
+
import { mkdir, open, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
|
|
9
|
+
//#region src/config/session-profile.ts
|
|
10
|
+
const WAKELOOP_CLI_CONTEXT_ENV_KEY = "WAKELOOP_CLI_CONTEXT_ID";
|
|
11
|
+
const LEGACY_WAKELOOP_CLI_CONTEXT_ENV_KEY = "WAKELOOP_AGENT_SESSION_ID";
|
|
12
|
+
const CLI_CONTEXT_ENV_KEYS = [WAKELOOP_CLI_CONTEXT_ENV_KEY, LEGACY_WAKELOOP_CLI_CONTEXT_ENV_KEY];
|
|
13
|
+
const SESSION_FILE_MAX_LENGTH = 128;
|
|
14
|
+
const SESSION_FILE_HASH_LENGTH = 8;
|
|
15
|
+
function resolveCliContext(profileIdInput) {
|
|
16
|
+
const explicit = normalizeSessionId(profileIdInput);
|
|
17
|
+
if (explicit) return {
|
|
18
|
+
cliContextId: explicit,
|
|
19
|
+
source: "manual"
|
|
20
|
+
};
|
|
21
|
+
for (const key of CLI_CONTEXT_ENV_KEYS) {
|
|
22
|
+
const sessionId = normalizeSessionId(process.env[key]);
|
|
23
|
+
if (sessionId) return {
|
|
24
|
+
cliContextId: sessionId,
|
|
25
|
+
source: `environment:${key}`
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return resolveTerminalSessionId();
|
|
29
|
+
}
|
|
30
|
+
function resolveCliContextId(profileIdInput) {
|
|
31
|
+
return resolveCliContext(profileIdInput)?.cliContextId ?? null;
|
|
32
|
+
}
|
|
33
|
+
function normalizeSessionSource(raw) {
|
|
34
|
+
const value = String(raw ?? "").trim();
|
|
35
|
+
if (!value) return null;
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
async function readCliContextState(input) {
|
|
39
|
+
const cliContextId = resolveSessionStateId(input?.sessionId);
|
|
40
|
+
if (!cliContextId) return null;
|
|
41
|
+
const raw = await readFile(cliContextStatePath(cliContextId), "utf8").catch(() => null);
|
|
42
|
+
if (!raw) return null;
|
|
43
|
+
return parseCliContextState(raw);
|
|
44
|
+
}
|
|
45
|
+
async function listCliContextStates() {
|
|
46
|
+
const entryNames = await readdir(sessionsDir()).catch(() => []);
|
|
47
|
+
const states = [];
|
|
48
|
+
for (const entryName of entryNames) {
|
|
49
|
+
if (!entryName.endsWith(".json")) continue;
|
|
50
|
+
const raw = await readFile(join(sessionsDir(), entryName), "utf8").catch(() => null);
|
|
51
|
+
if (!raw) continue;
|
|
52
|
+
const parsed = parseCliContextState(raw);
|
|
53
|
+
if (!parsed) continue;
|
|
54
|
+
states.push(parsed);
|
|
55
|
+
}
|
|
56
|
+
return states.sort((left, right) => left.sessionId.localeCompare(right.sessionId));
|
|
57
|
+
}
|
|
58
|
+
async function writeCliContextState(input) {
|
|
59
|
+
const cliContext = resolveCliContextStateInput(input) ?? resolveCliContext();
|
|
60
|
+
if (!cliContext) return false;
|
|
61
|
+
await mkdir(sessionsDir(), { recursive: true });
|
|
62
|
+
const existing = await readCliContextState({ sessionId: cliContext.cliContextId });
|
|
63
|
+
const nextWakeLoopProfileId = resolveNextSessionWakeLoopProfileId(existing, input);
|
|
64
|
+
const nextSelectedWakeLoopProfileId = resolveNextSelectedWakeLoopProfileId(existing, input);
|
|
65
|
+
const outputPath = cliContextStatePath(cliContext.cliContextId);
|
|
66
|
+
if (!(nextWakeLoopProfileId || nextSelectedWakeLoopProfileId)) {
|
|
67
|
+
await rm(outputPath, { force: true });
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
await writeCliContextStateFile(outputPath, {
|
|
71
|
+
v: 1,
|
|
72
|
+
sessionId: cliContext.cliContextId,
|
|
73
|
+
cliContextSource: cliContext.source ?? existing?.cliContextSource ?? "manual",
|
|
74
|
+
...nextWakeLoopProfileId ? { wakeLoopProfileId: nextWakeLoopProfileId } : {},
|
|
75
|
+
...nextSelectedWakeLoopProfileId ? { selectedWakeLoopProfileId: nextSelectedWakeLoopProfileId } : {},
|
|
76
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
77
|
+
});
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
function cliContextStatePath(sessionId) {
|
|
81
|
+
return join(sessionsDir(), `${toSafeSessionFile(sessionId)}.json`);
|
|
82
|
+
}
|
|
83
|
+
function toSafeSessionFile(value) {
|
|
84
|
+
const hash = createHash("sha1").update(value, "utf8").digest("hex").slice(0, SESSION_FILE_HASH_LENGTH);
|
|
85
|
+
const safeBaseRaw = value.replace(/[^a-zA-Z0-9._-]+/g, "_");
|
|
86
|
+
const safeBase = safeBaseRaw.length > 0 ? safeBaseRaw : "session";
|
|
87
|
+
const maxBaseLength = Math.max(1, SESSION_FILE_MAX_LENGTH - SESSION_FILE_HASH_LENGTH - 1);
|
|
88
|
+
return `${safeBase.slice(0, maxBaseLength)}-${hash}`;
|
|
89
|
+
}
|
|
90
|
+
function resolveCliContextStateInput(input) {
|
|
91
|
+
const sessionId = normalizeSessionId(input.sessionId);
|
|
92
|
+
if (!sessionId) return null;
|
|
93
|
+
return {
|
|
94
|
+
cliContextId: sessionId,
|
|
95
|
+
source: normalizeSessionSource(input.sessionSource) ?? "manual"
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function resolveSessionStateId(sessionId) {
|
|
99
|
+
const explicit = normalizeSessionId(sessionId);
|
|
100
|
+
if (explicit) return explicit;
|
|
101
|
+
return resolveCliContext()?.cliContextId ?? null;
|
|
102
|
+
}
|
|
103
|
+
function parseCliContextState(raw) {
|
|
104
|
+
let parsed;
|
|
105
|
+
try {
|
|
106
|
+
parsed = JSON.parse(raw);
|
|
107
|
+
} catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
if (parsed.v !== 1) return null;
|
|
111
|
+
const sessionId = normalizeSessionId(parsed.sessionId);
|
|
112
|
+
if (!sessionId) return null;
|
|
113
|
+
const wakeLoopProfileId = resolveStoredSessionWakeLoopProfileId(parsed);
|
|
114
|
+
const selectedWakeLoopProfileId = resolveStoredSelectedWakeLoopProfileId(parsed);
|
|
115
|
+
if (!(wakeLoopProfileId || selectedWakeLoopProfileId)) return null;
|
|
116
|
+
const cliContextSource = normalizeSessionSource(parsed.cliContextSource);
|
|
117
|
+
return {
|
|
118
|
+
v: 1,
|
|
119
|
+
sessionId,
|
|
120
|
+
...cliContextSource ? { cliContextSource } : {},
|
|
121
|
+
...wakeLoopProfileId ? { wakeLoopProfileId } : {},
|
|
122
|
+
...selectedWakeLoopProfileId ? { selectedWakeLoopProfileId } : {},
|
|
123
|
+
updatedAt: typeof parsed.updatedAt === "string" && parsed.updatedAt.trim().length > 0 ? parsed.updatedAt : (/* @__PURE__ */ new Date(0)).toISOString()
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function resolveNextSessionWakeLoopProfileId(existing, input) {
|
|
127
|
+
if (!("wakeLoopProfileId" in input)) return existing?.wakeLoopProfileId;
|
|
128
|
+
return normalizeOptionalWakeLoopProfileId(input.wakeLoopProfileId) ?? void 0;
|
|
129
|
+
}
|
|
130
|
+
function resolveNextSelectedWakeLoopProfileId(existing, input) {
|
|
131
|
+
if (!("selectedWakeLoopProfileId" in input)) return existing?.selectedWakeLoopProfileId;
|
|
132
|
+
return normalizeOptionalWakeLoopProfileId(input.selectedWakeLoopProfileId) ?? void 0;
|
|
133
|
+
}
|
|
134
|
+
async function writeCliContextStateFile(outputPath, payload) {
|
|
135
|
+
const tempPath = `${outputPath}.tmp-${process.pid}-${Date.now()}`;
|
|
136
|
+
const file = await open(tempPath, "w");
|
|
137
|
+
let writeFailure = null;
|
|
138
|
+
try {
|
|
139
|
+
await file.writeFile(`${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
140
|
+
await file.sync();
|
|
141
|
+
} catch (error) {
|
|
142
|
+
writeFailure = error;
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
await file.close();
|
|
146
|
+
} catch (error) {
|
|
147
|
+
if (!writeFailure) writeFailure = error;
|
|
148
|
+
}
|
|
149
|
+
if (writeFailure) {
|
|
150
|
+
await rm(tempPath, { force: true }).catch(() => void 0);
|
|
151
|
+
throw writeFailure;
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
await rename(tempPath, outputPath);
|
|
155
|
+
} catch (error) {
|
|
156
|
+
await rm(tempPath, { force: true }).catch(() => void 0);
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function normalizeSessionId(value) {
|
|
161
|
+
const raw = String(value ?? "").trim();
|
|
162
|
+
if (!raw) return null;
|
|
163
|
+
return raw.slice(0, 256);
|
|
164
|
+
}
|
|
165
|
+
function resolveTerminalSessionId() {
|
|
166
|
+
if (!(process.stdin.isTTY || process.stdout.isTTY)) return null;
|
|
167
|
+
const parentPid = Number(process.ppid);
|
|
168
|
+
if (!Number.isInteger(parentPid) || parentPid <= 1) return null;
|
|
169
|
+
return {
|
|
170
|
+
cliContextId: `terminal-ppid-${parentPid}`,
|
|
171
|
+
source: `terminal:ppid-${parentPid}`
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function resolveStoredSessionWakeLoopProfileId(input) {
|
|
175
|
+
const wakeLoopProfileId = normalizeOptionalWakeLoopProfileId(input.wakeLoopProfileId);
|
|
176
|
+
const legacyProfile = normalizeOptionalWakeLoopProfileId(input.profile);
|
|
177
|
+
if (wakeLoopProfileId && legacyProfile && wakeLoopProfileId !== legacyProfile) throw new Error(`conflicting stored WakeLoop profile identity: wakeLoopProfileId=${wakeLoopProfileId}, profile=${legacyProfile}. Remove or reconcile the legacy profile field so it matches wakeLoopProfileId.`);
|
|
178
|
+
return wakeLoopProfileId ?? legacyProfile;
|
|
179
|
+
}
|
|
180
|
+
function resolveStoredSelectedWakeLoopProfileId(input) {
|
|
181
|
+
return normalizeOptionalWakeLoopProfileId(input.selectedWakeLoopProfileId);
|
|
182
|
+
}
|
|
183
|
+
function normalizeOptionalWakeLoopProfileId(value) {
|
|
184
|
+
if (typeof value !== "string") return null;
|
|
185
|
+
try {
|
|
186
|
+
return normalizeWakeLoopProfileId(value);
|
|
187
|
+
} catch {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/config/lock.ts
|
|
194
|
+
var WakeLoopLockError = class extends Error {
|
|
195
|
+
code = "wakeloop.locked";
|
|
196
|
+
lockPath;
|
|
197
|
+
lockKey;
|
|
198
|
+
metaRaw;
|
|
199
|
+
meta;
|
|
200
|
+
constructor(input) {
|
|
201
|
+
const normalizedMetaRaw = normalizeMetaRaw(input.metaRaw);
|
|
202
|
+
super(buildWakeLoopLockErrorMessage(input.path, normalizedMetaRaw));
|
|
203
|
+
this.name = "WakeLoopLockError";
|
|
204
|
+
this.lockPath = input.path;
|
|
205
|
+
this.lockKey = input.key;
|
|
206
|
+
this.metaRaw = normalizedMetaRaw;
|
|
207
|
+
this.meta = parseWakeLoopLockMeta(normalizedMetaRaw);
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
function isWakeLoopLockError(error) {
|
|
211
|
+
return error instanceof WakeLoopLockError;
|
|
212
|
+
}
|
|
213
|
+
async function acquireLock(input) {
|
|
214
|
+
const wakeLoopProfileId = normalizeWakeLoopProfileId(input.wakeLoopProfileId);
|
|
215
|
+
const sessionId = resolveCliContextId();
|
|
216
|
+
await mkdir(locksDir(wakeLoopProfileId), { recursive: true });
|
|
217
|
+
const path = resolveLockPath({
|
|
218
|
+
wakeLoopProfileId,
|
|
219
|
+
key: input.key
|
|
220
|
+
});
|
|
221
|
+
for (let attempt = 0; attempt < 2; attempt++) try {
|
|
222
|
+
await writeFile(path, `${JSON.stringify({
|
|
223
|
+
pid: process$1.pid,
|
|
224
|
+
wakeLoopProfileId,
|
|
225
|
+
...sessionId ? { sessionId } : {},
|
|
226
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
227
|
+
...input.meta ? { ...input.meta } : {}
|
|
228
|
+
})}\n`, {
|
|
229
|
+
encoding: "utf8",
|
|
230
|
+
flag: "wx"
|
|
231
|
+
});
|
|
232
|
+
return { path };
|
|
233
|
+
} catch {
|
|
234
|
+
const existingLock = await readLockSnapshot(path);
|
|
235
|
+
if (await tryCleanupStaleLockPath(path, existingLock)) continue;
|
|
236
|
+
throw new WakeLoopLockError({
|
|
237
|
+
path,
|
|
238
|
+
key: input.key,
|
|
239
|
+
metaRaw: existingLock.metaRaw ?? void 0
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
throw new WakeLoopLockError({
|
|
243
|
+
path,
|
|
244
|
+
key: input.key
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
async function releaseLock(lock) {
|
|
248
|
+
await rm(lock.path, { force: true });
|
|
249
|
+
}
|
|
250
|
+
async function runWithCleanupPreservingRunError(input) {
|
|
251
|
+
let runResult;
|
|
252
|
+
let runSucceeded = false;
|
|
253
|
+
let runError;
|
|
254
|
+
try {
|
|
255
|
+
runResult = await input.run();
|
|
256
|
+
runSucceeded = true;
|
|
257
|
+
} catch (error) {
|
|
258
|
+
runError = error;
|
|
259
|
+
}
|
|
260
|
+
try {
|
|
261
|
+
await input.cleanup();
|
|
262
|
+
} catch (cleanupError) {
|
|
263
|
+
if (!runSucceeded) {
|
|
264
|
+
input.onCleanupErrorAfterRunFailure?.(cleanupError);
|
|
265
|
+
throw runError;
|
|
266
|
+
}
|
|
267
|
+
throw cleanupError;
|
|
268
|
+
}
|
|
269
|
+
if (!runSucceeded) throw runError;
|
|
270
|
+
return runResult;
|
|
271
|
+
}
|
|
272
|
+
async function runWithHeldLock(input) {
|
|
273
|
+
return await runWithCleanupPreservingRunError({
|
|
274
|
+
run: input.run,
|
|
275
|
+
cleanup: () => releaseLock(input.lock),
|
|
276
|
+
onCleanupErrorAfterRunFailure: (releaseError) => {
|
|
277
|
+
warnLockReleaseFailure({
|
|
278
|
+
error: releaseError,
|
|
279
|
+
lock: input.lock,
|
|
280
|
+
releaseContext: input.releaseContext
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
async function readLockMeta(input) {
|
|
286
|
+
return (await readLockSnapshot(resolveLockPath({
|
|
287
|
+
wakeLoopProfileId: input.wakeLoopProfileId,
|
|
288
|
+
key: input.key
|
|
289
|
+
}))).meta;
|
|
290
|
+
}
|
|
291
|
+
async function tryCleanupStaleLock(input) {
|
|
292
|
+
return await tryCleanupStaleLockPath(resolveLockPath({
|
|
293
|
+
wakeLoopProfileId: input.wakeLoopProfileId,
|
|
294
|
+
key: input.key
|
|
295
|
+
}));
|
|
296
|
+
}
|
|
297
|
+
function resolveLockPath(input) {
|
|
298
|
+
return join(locksDir(normalizeWakeLoopProfileId(input.wakeLoopProfileId)), `${sanitizeFilename(input.key)}.lock`);
|
|
299
|
+
}
|
|
300
|
+
function sanitizeFilename(value) {
|
|
301
|
+
return value.replace(/[^a-zA-Z0-9._-]+/g, "_");
|
|
302
|
+
}
|
|
303
|
+
function safeParse(value) {
|
|
304
|
+
try {
|
|
305
|
+
return JSON.parse(value);
|
|
306
|
+
} catch {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
function normalizeMetaRaw(metaRaw) {
|
|
311
|
+
if (typeof metaRaw !== "string") return null;
|
|
312
|
+
const normalized = metaRaw.trim();
|
|
313
|
+
return normalized.length > 0 ? normalized : null;
|
|
314
|
+
}
|
|
315
|
+
function parseWakeLoopLockMeta(metaRaw) {
|
|
316
|
+
if (!metaRaw) return null;
|
|
317
|
+
const parsed = safeParse(metaRaw);
|
|
318
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
319
|
+
return parsed;
|
|
320
|
+
}
|
|
321
|
+
function buildWakeLoopLockErrorMessage(path, metaRaw) {
|
|
322
|
+
if (!metaRaw) return `space is locked (${path})`;
|
|
323
|
+
return `space is locked (${path}). Meta: ${metaRaw}`;
|
|
324
|
+
}
|
|
325
|
+
function getPidFromMeta(meta) {
|
|
326
|
+
if (!meta || typeof meta !== "object") return null;
|
|
327
|
+
const pid = meta.pid;
|
|
328
|
+
return typeof pid === "number" ? pid : null;
|
|
329
|
+
}
|
|
330
|
+
async function readLockSnapshot(path) {
|
|
331
|
+
const normalizedMetaRaw = normalizeMetaRaw(await readFile(path, "utf8").catch((error) => {
|
|
332
|
+
if (getErrorCode(error) === "ENOENT") return null;
|
|
333
|
+
throw error;
|
|
334
|
+
}) ?? void 0);
|
|
335
|
+
if (normalizedMetaRaw === null) return {
|
|
336
|
+
metaRaw: null,
|
|
337
|
+
meta: null,
|
|
338
|
+
pid: null,
|
|
339
|
+
hasStalePid: false
|
|
340
|
+
};
|
|
341
|
+
const meta = parseWakeLoopLockMeta(normalizedMetaRaw);
|
|
342
|
+
const pid = getPidFromMeta(meta);
|
|
343
|
+
return {
|
|
344
|
+
metaRaw: normalizedMetaRaw,
|
|
345
|
+
meta,
|
|
346
|
+
pid,
|
|
347
|
+
hasStalePid: pid !== null && !isPidAlive(pid)
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
async function tryCleanupStaleLockPath(path, initialSnapshot) {
|
|
351
|
+
const firstSnapshot = initialSnapshot ?? await readLockSnapshot(path);
|
|
352
|
+
if (firstSnapshot.metaRaw === null || firstSnapshot.pid === null || !firstSnapshot.hasStalePid) return false;
|
|
353
|
+
const confirmedSnapshot = await readLockSnapshot(path);
|
|
354
|
+
if (confirmedSnapshot.metaRaw !== firstSnapshot.metaRaw || confirmedSnapshot.pid !== firstSnapshot.pid || !confirmedSnapshot.hasStalePid) return false;
|
|
355
|
+
await rm(path, { force: true });
|
|
356
|
+
return true;
|
|
357
|
+
}
|
|
358
|
+
function isPidAlive(pid) {
|
|
359
|
+
try {
|
|
360
|
+
process$1.kill(pid, 0);
|
|
361
|
+
return true;
|
|
362
|
+
} catch (err) {
|
|
363
|
+
if (getErrorCode(err) === "ESRCH") return false;
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
function getErrorCode(err) {
|
|
368
|
+
if (!err || typeof err !== "object") return;
|
|
369
|
+
const code = err.code;
|
|
370
|
+
return typeof code === "string" ? code : void 0;
|
|
371
|
+
}
|
|
372
|
+
function warnLockReleaseFailure(input) {
|
|
373
|
+
console.warn("[wakeloop.lock.release.warning]", {
|
|
374
|
+
lockPath: input.lock.path,
|
|
375
|
+
releaseError: toErrorMessage(input.error),
|
|
376
|
+
releaseContext: input.releaseContext ?? {}
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
function toErrorMessage(error) {
|
|
380
|
+
return error instanceof Error ? error.message : String(error);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
//#endregion
|
|
384
|
+
export { runWithHeldLock as a, WAKELOOP_CLI_CONTEXT_ENV_KEY as c, resolveCliContext as d, resolveCliContextId as f, releaseLock as i, listCliContextStates as l, isWakeLoopLockError as n, tryCleanupStaleLock as o, writeCliContextState as p, readLockMeta as r, LEGACY_WAKELOOP_CLI_CONTEXT_ENV_KEY as s, acquireLock as t, readCliContextState as u };
|
|
385
|
+
//# sourceMappingURL=lock-BYUpcHBF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lock-BYUpcHBF.js","names":["resolveLocksDir","process"],"sources":["../src/config/session-profile.ts","../src/config/lock.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { mkdir, open, readdir, readFile, rename, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n normalizeWakeLoopProfileId,\n sessionsDir,\n type WakeLoopProfileId,\n} from \"./paths\";\n\nexport const WAKELOOP_CLI_CONTEXT_ENV_KEY = \"WAKELOOP_CLI_CONTEXT_ID\";\nexport const LEGACY_WAKELOOP_CLI_CONTEXT_ENV_KEY = \"WAKELOOP_AGENT_SESSION_ID\";\n\nexport const CLI_CONTEXT_ENV_KEYS = [\n WAKELOOP_CLI_CONTEXT_ENV_KEY,\n LEGACY_WAKELOOP_CLI_CONTEXT_ENV_KEY,\n] as const;\n\nconst SESSION_FILE_MAX_LENGTH = 128;\nconst SESSION_FILE_HASH_LENGTH = 8;\n\nexport type CliContextResolution = {\n cliContextId: string;\n source: string;\n};\n\nexport type CliContextStateV1 = {\n v: 1;\n sessionId: string;\n updatedAt: string;\n cliContextSource?: string;\n wakeLoopProfileId?: string;\n selectedWakeLoopProfileId?: string;\n};\n\nexport function resolveCliContext(\n profileIdInput?: string\n): CliContextResolution | null {\n const explicit = normalizeSessionId(profileIdInput);\n if (explicit) {\n return {\n cliContextId: explicit,\n source: \"manual\",\n };\n }\n\n for (const key of CLI_CONTEXT_ENV_KEYS) {\n const sessionId = normalizeSessionId(process.env[key]);\n if (sessionId) {\n return {\n cliContextId: sessionId,\n source: `environment:${key}`,\n };\n }\n }\n\n return resolveTerminalSessionId();\n}\n\nexport function resolveCliContextId(profileIdInput?: string): string | null {\n return resolveCliContext(profileIdInput)?.cliContextId ?? null;\n}\n\nexport function buildSessionProfilePayload(\n session: CliContextResolution,\n wakeLoopProfileId: WakeLoopProfileId\n): CliContextStateV1 {\n return {\n v: 1,\n sessionId: session.cliContextId,\n cliContextSource: session.source,\n wakeLoopProfileId: normalizeWakeLoopProfileId(wakeLoopProfileId),\n updatedAt: new Date().toISOString(),\n };\n}\n\nexport function formatCliContextSource(source: string): string {\n if (source === \"manual\") {\n return \"manual\";\n }\n if (source.startsWith(\"environment:\")) {\n return `environment:${source.slice(\"environment:\".length)}`;\n }\n if (source.startsWith(\"terminal:\")) {\n return \"terminal-fingerprint\";\n }\n return source;\n}\n\nexport function normalizeCliContextResolution(\n value: unknown\n): CliContextResolution | null {\n if (!value || typeof value !== \"object\") {\n return null;\n }\n\n const maybe = value as {\n cliContextId?: unknown;\n source?: unknown;\n };\n const cliContextId = normalizeSessionId(maybe.cliContextId);\n const source = normalizeSessionSource(maybe.source);\n if (!(cliContextId && source)) {\n return null;\n }\n\n return { cliContextId, source };\n}\n\nfunction normalizeSessionSource(raw: unknown): string | null {\n const value = String(raw ?? \"\").trim();\n if (!value) {\n return null;\n }\n return value;\n}\n\nexport async function setSessionWakeLoopProfileId(\n wakeLoopProfileId: WakeLoopProfileId\n): Promise<boolean> {\n return await writeCliContextState({\n wakeLoopProfileId,\n });\n}\n\nexport async function getSessionWakeLoopProfileId(): Promise<WakeLoopProfileId | null> {\n return (await readCliContextState())?.wakeLoopProfileId ?? null;\n}\n\nexport async function clearSessionWakeLoopProfileId(): Promise<boolean> {\n return await writeCliContextState({\n wakeLoopProfileId: null,\n });\n}\n\nexport async function readCliContextState(input?: {\n sessionId?: string;\n}): Promise<CliContextStateV1 | null> {\n const cliContextId = resolveSessionStateId(input?.sessionId);\n if (!cliContextId) {\n return null;\n }\n\n const raw = await readFile(cliContextStatePath(cliContextId), \"utf8\").catch(\n () => null\n );\n if (!raw) {\n return null;\n }\n\n return parseCliContextState(raw);\n}\n\nexport async function listCliContextStates(): Promise<CliContextStateV1[]> {\n const entryNames = await readdir(sessionsDir()).catch(() => []);\n const states: CliContextStateV1[] = [];\n for (const entryName of entryNames) {\n if (!entryName.endsWith(\".json\")) {\n continue;\n }\n const raw = await readFile(join(sessionsDir(), entryName), \"utf8\").catch(\n () => null\n );\n if (!raw) {\n continue;\n }\n const parsed = parseCliContextState(raw);\n if (!parsed) {\n continue;\n }\n states.push(parsed);\n }\n return states.sort((left, right) =>\n left.sessionId.localeCompare(right.sessionId)\n );\n}\n\nexport async function writeCliContextState(input: {\n sessionId?: string;\n sessionSource?: string;\n wakeLoopProfileId?: string | null;\n selectedWakeLoopProfileId?: string | null;\n}): Promise<boolean> {\n const cliContext = resolveCliContextStateInput(input) ?? resolveCliContext();\n if (!cliContext) {\n return false;\n }\n\n await mkdir(sessionsDir(), { recursive: true });\n const existing = await readCliContextState({\n sessionId: cliContext.cliContextId,\n });\n const nextWakeLoopProfileId = resolveNextSessionWakeLoopProfileId(\n existing,\n input\n );\n const nextSelectedWakeLoopProfileId = resolveNextSelectedWakeLoopProfileId(\n existing,\n input\n );\n const outputPath = cliContextStatePath(cliContext.cliContextId);\n\n if (!(nextWakeLoopProfileId || nextSelectedWakeLoopProfileId)) {\n await rm(outputPath, { force: true });\n return true;\n }\n\n const payload: CliContextStateV1 = {\n v: 1,\n sessionId: cliContext.cliContextId,\n cliContextSource:\n cliContext.source ?? existing?.cliContextSource ?? \"manual\",\n ...(nextWakeLoopProfileId\n ? { wakeLoopProfileId: nextWakeLoopProfileId }\n : {}),\n ...(nextSelectedWakeLoopProfileId\n ? { selectedWakeLoopProfileId: nextSelectedWakeLoopProfileId }\n : {}),\n updatedAt: new Date().toISOString(),\n };\n\n await writeCliContextStateFile(outputPath, payload);\n return true;\n}\n\nexport function cliContextStatePath(sessionId: string): string {\n return join(sessionsDir(), `${toSafeSessionFile(sessionId)}.json`);\n}\n\nfunction toSafeSessionFile(value: string): string {\n const hash = createHash(\"sha1\")\n .update(value, \"utf8\")\n .digest(\"hex\")\n .slice(0, SESSION_FILE_HASH_LENGTH);\n const safeBaseRaw = value.replace(/[^a-zA-Z0-9._-]+/g, \"_\");\n const safeBase = safeBaseRaw.length > 0 ? safeBaseRaw : \"session\";\n const maxBaseLength = Math.max(\n 1,\n SESSION_FILE_MAX_LENGTH - SESSION_FILE_HASH_LENGTH - 1\n );\n const truncatedBase = safeBase.slice(0, maxBaseLength);\n return `${truncatedBase}-${hash}`;\n}\n\nfunction resolveCliContextStateInput(input: {\n sessionId?: string;\n sessionSource?: string;\n}): CliContextResolution | null {\n const sessionId = normalizeSessionId(input.sessionId);\n if (!sessionId) {\n return null;\n }\n return {\n cliContextId: sessionId,\n source: normalizeSessionSource(input.sessionSource) ?? \"manual\",\n };\n}\n\nfunction resolveSessionStateId(sessionId?: string): string | null {\n const explicit = normalizeSessionId(sessionId);\n if (explicit) {\n return explicit;\n }\n return resolveCliContext()?.cliContextId ?? null;\n}\n\nfunction parseCliContextState(raw: string): CliContextStateV1 | null {\n let parsed: Partial<CliContextStateV1> & {\n profile?: unknown;\n };\n try {\n parsed = JSON.parse(raw) as Partial<CliContextStateV1> & {\n profile?: unknown;\n };\n } catch {\n return null;\n }\n\n if (parsed.v !== 1) {\n return null;\n }\n const sessionId = normalizeSessionId(parsed.sessionId);\n if (!sessionId) {\n return null;\n }\n const wakeLoopProfileId = resolveStoredSessionWakeLoopProfileId(parsed);\n const selectedWakeLoopProfileId =\n resolveStoredSelectedWakeLoopProfileId(parsed);\n if (!(wakeLoopProfileId || selectedWakeLoopProfileId)) {\n return null;\n }\n const cliContextSource = normalizeSessionSource(parsed.cliContextSource);\n return {\n v: 1,\n sessionId,\n ...(cliContextSource ? { cliContextSource } : {}),\n ...(wakeLoopProfileId ? { wakeLoopProfileId } : {}),\n ...(selectedWakeLoopProfileId ? { selectedWakeLoopProfileId } : {}),\n updatedAt:\n typeof parsed.updatedAt === \"string\" && parsed.updatedAt.trim().length > 0\n ? parsed.updatedAt\n : new Date(0).toISOString(),\n };\n}\n\nfunction resolveNextSessionWakeLoopProfileId(\n existing: CliContextStateV1 | null,\n input: {\n wakeLoopProfileId?: string | null;\n selectedWakeLoopProfileId?: string | null;\n }\n): string | undefined {\n if (!(\"wakeLoopProfileId\" in input)) {\n return existing?.wakeLoopProfileId;\n }\n return (\n normalizeOptionalWakeLoopProfileId(input.wakeLoopProfileId) ?? undefined\n );\n}\n\nfunction resolveNextSelectedWakeLoopProfileId(\n existing: CliContextStateV1 | null,\n input: {\n wakeLoopProfileId?: string | null;\n selectedWakeLoopProfileId?: string | null;\n }\n): string | undefined {\n if (!(\"selectedWakeLoopProfileId\" in input)) {\n return existing?.selectedWakeLoopProfileId;\n }\n return (\n normalizeOptionalWakeLoopProfileId(input.selectedWakeLoopProfileId) ??\n undefined\n );\n}\n\nasync function writeCliContextStateFile(\n outputPath: string,\n payload: CliContextStateV1\n): Promise<void> {\n const tempPath = `${outputPath}.tmp-${process.pid}-${Date.now()}`;\n const file = await open(tempPath, \"w\");\n let writeFailure: unknown = null;\n try {\n await file.writeFile(`${JSON.stringify(payload, null, 2)}\\n`, \"utf8\");\n await file.sync();\n } catch (error) {\n writeFailure = error;\n }\n try {\n await file.close();\n } catch (error) {\n if (!writeFailure) {\n writeFailure = error;\n }\n }\n if (writeFailure) {\n await rm(tempPath, { force: true }).catch(() => undefined);\n throw writeFailure;\n }\n\n try {\n await rename(tempPath, outputPath);\n } catch (error) {\n await rm(tempPath, { force: true }).catch(() => undefined);\n throw error;\n }\n}\n\nfunction normalizeSessionId(value: unknown): string | null {\n const raw = String(value ?? \"\").trim();\n if (!raw) {\n return null;\n }\n return raw.slice(0, 256);\n}\n\nfunction resolveTerminalSessionId(): CliContextResolution | null {\n if (!(process.stdin.isTTY || process.stdout.isTTY)) {\n return null;\n }\n\n const parentPid = Number(process.ppid);\n if (!Number.isInteger(parentPid) || parentPid <= 1) {\n return null;\n }\n\n return {\n cliContextId: `terminal-ppid-${parentPid}`,\n source: `terminal:ppid-${parentPid}`,\n };\n}\n\nfunction resolveStoredSessionWakeLoopProfileId(input: {\n wakeLoopProfileId?: unknown;\n profile?: unknown;\n}): WakeLoopProfileId | null {\n const wakeLoopProfileId = normalizeOptionalWakeLoopProfileId(\n input.wakeLoopProfileId\n );\n const legacyProfile = normalizeOptionalWakeLoopProfileId(input.profile);\n if (\n wakeLoopProfileId &&\n legacyProfile &&\n wakeLoopProfileId !== legacyProfile\n ) {\n throw new Error(\n `conflicting stored WakeLoop profile identity: wakeLoopProfileId=${wakeLoopProfileId}, profile=${legacyProfile}. Remove or reconcile the legacy profile field so it matches wakeLoopProfileId.`\n );\n }\n return wakeLoopProfileId ?? legacyProfile;\n}\n\nfunction resolveStoredSelectedWakeLoopProfileId(input: {\n selectedWakeLoopProfileId?: unknown;\n}): WakeLoopProfileId | null {\n return normalizeOptionalWakeLoopProfileId(input.selectedWakeLoopProfileId);\n}\n\nfunction normalizeOptionalWakeLoopProfileId(\n value: unknown\n): WakeLoopProfileId | null {\n if (typeof value !== \"string\") {\n return null;\n }\n try {\n return normalizeWakeLoopProfileId(value);\n } catch {\n return null;\n }\n}\n","import { mkdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport process from \"node:process\";\nimport {\n normalizeWakeLoopProfileId,\n locksDir as resolveLocksDir,\n} from \"./paths\";\nimport { resolveCliContextId } from \"./session-profile\";\n\nexport type WakeLoopLock = {\n path: string;\n};\n\nexport type WakeLoopLockMeta = Record<string, unknown>;\ntype HeldLockReleaseContext = Record<string, unknown>;\n\nexport class WakeLoopLockError extends Error {\n readonly code = \"wakeloop.locked\";\n readonly lockPath: string;\n readonly lockKey: string;\n readonly metaRaw: string | null;\n readonly meta: WakeLoopLockMeta | null;\n\n constructor(input: { path: string; key: string; metaRaw?: string }) {\n const normalizedMetaRaw = normalizeMetaRaw(input.metaRaw);\n super(buildWakeLoopLockErrorMessage(input.path, normalizedMetaRaw));\n this.name = \"WakeLoopLockError\";\n this.lockPath = input.path;\n this.lockKey = input.key;\n this.metaRaw = normalizedMetaRaw;\n this.meta = parseWakeLoopLockMeta(normalizedMetaRaw);\n }\n}\n\nexport function isWakeLoopLockError(\n error: unknown\n): error is WakeLoopLockError {\n return error instanceof WakeLoopLockError;\n}\n\nexport async function acquireLock(input: {\n wakeLoopProfileId: string;\n key: string;\n meta?: WakeLoopLockMeta;\n}): Promise<WakeLoopLock> {\n const wakeLoopProfileId = normalizeWakeLoopProfileId(input.wakeLoopProfileId);\n const sessionId = resolveCliContextId();\n const dir = resolveLocksDir(wakeLoopProfileId);\n await mkdir(dir, { recursive: true });\n\n const path = resolveLockPath({\n wakeLoopProfileId,\n key: input.key,\n });\n\n // Exclusive create, with basic stale-lock recovery.\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n await writeFile(\n path,\n `${JSON.stringify({\n pid: process.pid,\n wakeLoopProfileId,\n ...(sessionId ? { sessionId } : {}),\n at: new Date().toISOString(),\n ...(input.meta ? { ...input.meta } : {}),\n })}\\n`,\n {\n encoding: \"utf8\",\n flag: \"wx\",\n }\n );\n return { path };\n } catch {\n const existingLock = await readLockSnapshot(path);\n\n if (await tryCleanupStaleLockPath(path, existingLock)) {\n continue;\n }\n\n throw new WakeLoopLockError({\n path,\n key: input.key,\n metaRaw: existingLock.metaRaw ?? undefined,\n });\n }\n }\n\n throw new WakeLoopLockError({\n path,\n key: input.key,\n });\n}\n\nexport async function releaseLock(lock: WakeLoopLock): Promise<void> {\n await rm(lock.path, { force: true });\n}\n\nexport async function runWithCleanupPreservingRunError<T>(input: {\n run: () => Promise<T>;\n cleanup: () => Promise<void>;\n onCleanupErrorAfterRunFailure?: (cleanupError: unknown) => void;\n}): Promise<T> {\n let runResult: T | undefined;\n let runSucceeded = false;\n let runError: unknown;\n\n try {\n runResult = await input.run();\n runSucceeded = true;\n } catch (error) {\n runError = error;\n }\n\n try {\n await input.cleanup();\n } catch (cleanupError) {\n if (!runSucceeded) {\n input.onCleanupErrorAfterRunFailure?.(cleanupError);\n throw runError;\n }\n throw cleanupError;\n }\n\n if (!runSucceeded) {\n throw runError;\n }\n\n return runResult as T;\n}\n\nexport async function runWithHeldLock<T>(input: {\n lock: WakeLoopLock;\n run: () => Promise<T>;\n releaseContext?: HeldLockReleaseContext;\n}): Promise<T> {\n return await runWithCleanupPreservingRunError({\n run: input.run,\n cleanup: () => releaseLock(input.lock),\n onCleanupErrorAfterRunFailure: (releaseError) => {\n warnLockReleaseFailure({\n error: releaseError,\n lock: input.lock,\n releaseContext: input.releaseContext,\n });\n },\n });\n}\n\nexport async function readLockMeta(input: {\n wakeLoopProfileId: string;\n key: string;\n}): Promise<WakeLoopLockMeta | null> {\n const existingLock = await readLockSnapshot(\n resolveLockPath({\n wakeLoopProfileId: input.wakeLoopProfileId,\n key: input.key,\n })\n );\n return existingLock.meta;\n}\n\nexport async function tryCleanupStaleLock(input: {\n wakeLoopProfileId: string;\n key: string;\n}): Promise<boolean> {\n return await tryCleanupStaleLockPath(\n resolveLockPath({\n wakeLoopProfileId: input.wakeLoopProfileId,\n key: input.key,\n })\n );\n}\n\ntype LockSnapshot = {\n metaRaw: string | null;\n meta: WakeLoopLockMeta | null;\n pid: number | null;\n hasStalePid: boolean;\n};\n\nfunction resolveLockPath(input: {\n wakeLoopProfileId: string;\n key: string;\n}): string {\n const wakeLoopProfileId = normalizeWakeLoopProfileId(input.wakeLoopProfileId);\n return join(\n resolveLocksDir(wakeLoopProfileId),\n `${sanitizeFilename(input.key)}.lock`\n );\n}\n\nfunction sanitizeFilename(value: string): string {\n return value.replace(/[^a-zA-Z0-9._-]+/g, \"_\");\n}\n\nfunction safeParse(value: string): unknown {\n try {\n return JSON.parse(value);\n } catch {\n return null;\n }\n}\n\nfunction normalizeMetaRaw(metaRaw: string | undefined): string | null {\n if (typeof metaRaw !== \"string\") {\n return null;\n }\n const normalized = metaRaw.trim();\n return normalized.length > 0 ? normalized : null;\n}\n\nfunction parseWakeLoopLockMeta(\n metaRaw: string | null\n): WakeLoopLockMeta | null {\n if (!metaRaw) {\n return null;\n }\n const parsed = safeParse(metaRaw);\n if (!parsed || typeof parsed !== \"object\") {\n return null;\n }\n return parsed as WakeLoopLockMeta;\n}\n\nfunction buildWakeLoopLockErrorMessage(\n path: string,\n metaRaw: string | null\n): string {\n if (!metaRaw) {\n return `space is locked (${path})`;\n }\n return `space is locked (${path}). Meta: ${metaRaw}`;\n}\n\nfunction getPidFromMeta(meta: unknown): number | null {\n if (!meta || typeof meta !== \"object\") {\n return null;\n }\n const pid = (meta as Record<string, unknown>).pid;\n return typeof pid === \"number\" ? pid : null;\n}\n\nasync function readLockSnapshot(path: string): Promise<LockSnapshot> {\n const metaRaw = await readFile(path, \"utf8\").catch((error) => {\n if (getErrorCode(error) === \"ENOENT\") {\n return null;\n }\n throw error;\n });\n const normalizedMetaRaw = normalizeMetaRaw(metaRaw ?? undefined);\n if (normalizedMetaRaw === null) {\n return {\n metaRaw: null,\n meta: null,\n pid: null,\n hasStalePid: false,\n };\n }\n\n const meta = parseWakeLoopLockMeta(normalizedMetaRaw);\n const pid = getPidFromMeta(meta);\n return {\n metaRaw: normalizedMetaRaw,\n meta,\n pid,\n hasStalePid: pid !== null && !isPidAlive(pid),\n };\n}\n\nasync function tryCleanupStaleLockPath(\n path: string,\n initialSnapshot?: LockSnapshot\n): Promise<boolean> {\n const firstSnapshot = initialSnapshot ?? (await readLockSnapshot(path));\n\n if (\n firstSnapshot.metaRaw === null ||\n firstSnapshot.pid === null ||\n !firstSnapshot.hasStalePid\n ) {\n return false;\n }\n\n const confirmedSnapshot = await readLockSnapshot(path);\n if (\n confirmedSnapshot.metaRaw !== firstSnapshot.metaRaw ||\n confirmedSnapshot.pid !== firstSnapshot.pid ||\n !confirmedSnapshot.hasStalePid\n ) {\n return false;\n }\n\n await rm(path, { force: true });\n return true;\n}\n\nfunction isPidAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n if (getErrorCode(err) === \"ESRCH\") {\n return false;\n }\n return true;\n }\n}\n\nfunction getErrorCode(err: unknown): string | undefined {\n if (!err || typeof err !== \"object\") {\n return undefined;\n }\n const code = (err as { code?: unknown }).code;\n return typeof code === \"string\" ? code : undefined;\n}\n\nfunction warnLockReleaseFailure(input: {\n error: unknown;\n lock: WakeLoopLock;\n releaseContext?: HeldLockReleaseContext;\n}): void {\n console.warn(\"[wakeloop.lock.release.warning]\", {\n lockPath: input.lock.path,\n releaseError: toErrorMessage(input.error),\n releaseContext: input.releaseContext ?? {},\n });\n}\n\nfunction toErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { basename, dirname, join, parse } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
|
|
6
|
+
//#region src/config/paths.ts
|
|
7
|
+
const MAX_ACCOUNT_PATH_SEGMENT_LENGTH = 128;
|
|
8
|
+
const FALLBACK_ACCOUNT_HOST_KEY = "unauthenticated";
|
|
9
|
+
const FALLBACK_ACCOUNT_USER_KEY = "local";
|
|
10
|
+
const WAKELOOP_HOME_ENV_KEY = "WAKELOOP_HOME";
|
|
11
|
+
const WAKELOOP_ENV_PRESET_ENV_KEY = "WAKELOOP_ENV_PRESET";
|
|
12
|
+
const DEFAULT_WAKELOOP_ENV_PRESET = "prod";
|
|
13
|
+
const WAKELOOP_DEFAULT_HOME_DIR_BY_PRESET = {
|
|
14
|
+
prod: ".wakeloop",
|
|
15
|
+
"dev-local": ".wakeloop-dev",
|
|
16
|
+
canary: ".wakeloop-canary"
|
|
17
|
+
};
|
|
18
|
+
const WAKELOOP_ENV_PRESET_BY_ENTRY_NAME = {
|
|
19
|
+
wakeloop: "prod",
|
|
20
|
+
"wakeloop-dev": "dev-local",
|
|
21
|
+
"wakeloop-canary": "canary"
|
|
22
|
+
};
|
|
23
|
+
function normalizeWakeLoopProfileId(value) {
|
|
24
|
+
const raw = String(value ?? "").trim();
|
|
25
|
+
if (raw.length === 0) throw new Error("wakeLoopProfileId is required");
|
|
26
|
+
const safe = raw.replace(/[^a-zA-Z0-9._-]+/g, "_").toLowerCase();
|
|
27
|
+
if (!safe || safe === "." || safe === "..") throw new Error("wakeLoopProfileId is invalid");
|
|
28
|
+
if (safe.length > MAX_ACCOUNT_PATH_SEGMENT_LENGTH) throw new Error("wakeLoopProfileId is too long");
|
|
29
|
+
return safe;
|
|
30
|
+
}
|
|
31
|
+
function resolveWakeLoopEnvPreset(input = {}) {
|
|
32
|
+
const fromEnv = normalizeWakeLoopEnvPreset((input.env ?? process.env)[WAKELOOP_ENV_PRESET_ENV_KEY]);
|
|
33
|
+
if (fromEnv) return fromEnv;
|
|
34
|
+
return resolveWakeLoopEnvPresetFromArgv(input.argv ?? process.argv);
|
|
35
|
+
}
|
|
36
|
+
function resolveDefaultWakeLoopHomeDirname(preset) {
|
|
37
|
+
return WAKELOOP_DEFAULT_HOME_DIR_BY_PRESET[preset];
|
|
38
|
+
}
|
|
39
|
+
function resolveWakeLoopRootDir(input = {}) {
|
|
40
|
+
const env = input.env ?? process.env;
|
|
41
|
+
const fromEnv = String(env[WAKELOOP_HOME_ENV_KEY] ?? "").trim();
|
|
42
|
+
if (fromEnv) return fromEnv;
|
|
43
|
+
const preset = resolveWakeLoopEnvPreset(input);
|
|
44
|
+
return join(resolveHomeDirectory(input), resolveDefaultWakeLoopHomeDirname(preset));
|
|
45
|
+
}
|
|
46
|
+
function wakeLoopRootDir() {
|
|
47
|
+
return resolveWakeLoopRootDir();
|
|
48
|
+
}
|
|
49
|
+
function wakeLoopBackupsDir() {
|
|
50
|
+
const root = wakeLoopRootDir();
|
|
51
|
+
return join(dirname(root), `${basename(root)}-backups`);
|
|
52
|
+
}
|
|
53
|
+
function accountsDir() {
|
|
54
|
+
return join(wakeLoopRootDir(), "accounts");
|
|
55
|
+
}
|
|
56
|
+
function deviceDir(input = {}) {
|
|
57
|
+
return join(resolveWakeLoopRootDir(input), "device");
|
|
58
|
+
}
|
|
59
|
+
function deviceSkillsDir(input = {}) {
|
|
60
|
+
return join(deviceDir(input), "skills");
|
|
61
|
+
}
|
|
62
|
+
function devicePreferencesPath(input = {}) {
|
|
63
|
+
return join(deviceDir(input), "preferences.json");
|
|
64
|
+
}
|
|
65
|
+
function deviceAgentRuntimePath(input = {}) {
|
|
66
|
+
return join(deviceDir(input), "agent-runtime.json");
|
|
67
|
+
}
|
|
68
|
+
function deviceProvidersDir(input = {}) {
|
|
69
|
+
return join(deviceDir(input), "providers");
|
|
70
|
+
}
|
|
71
|
+
function deviceProviderDir(providerId, input = {}) {
|
|
72
|
+
return join(deviceProvidersDir(input), normalizePathSegment(providerId, "unknown"));
|
|
73
|
+
}
|
|
74
|
+
function deviceProviderProfilesDir(providerId, input = {}) {
|
|
75
|
+
return join(deviceProviderDir(providerId, input), "profiles");
|
|
76
|
+
}
|
|
77
|
+
function deviceProviderProfileDir(providerId, profileId, input = {}) {
|
|
78
|
+
return join(deviceProviderProfilesDir(providerId, input), normalizePathSegment(profileId, "unknown"));
|
|
79
|
+
}
|
|
80
|
+
function deviceOpenClawProfileDir(profileId, input = {}) {
|
|
81
|
+
return deviceProviderProfileDir("openclaw", profileId, input);
|
|
82
|
+
}
|
|
83
|
+
function deviceOpenClawProfileWorkspaceDir(profileId, input = {}) {
|
|
84
|
+
return join(deviceOpenClawProfileDir(profileId, input), "workspace");
|
|
85
|
+
}
|
|
86
|
+
function deviceOpenClawProfileBootstrapPath(profileId, input = {}) {
|
|
87
|
+
return join(deviceOpenClawProfileDir(profileId, input), "bootstrap.json");
|
|
88
|
+
}
|
|
89
|
+
function deviceSkillsStorePath(input = {}) {
|
|
90
|
+
return join(deviceSkillsDir(input), "store.json");
|
|
91
|
+
}
|
|
92
|
+
function deviceSkillsCustomTargetsPath(input = {}) {
|
|
93
|
+
return join(deviceSkillsDir(input), "custom-targets.json");
|
|
94
|
+
}
|
|
95
|
+
function deviceSkillsInstallsPath(input = {}) {
|
|
96
|
+
return join(deviceSkillsDir(input), "installs.json");
|
|
97
|
+
}
|
|
98
|
+
function legacyRuntimeConfigPath(input = {}) {
|
|
99
|
+
return join(resolveWakeLoopRootDir(input), "config.json");
|
|
100
|
+
}
|
|
101
|
+
function normalizeAccountHostKey(value) {
|
|
102
|
+
return normalizePathSegment(value, FALLBACK_ACCOUNT_HOST_KEY);
|
|
103
|
+
}
|
|
104
|
+
function normalizeAccountUserKey(value) {
|
|
105
|
+
return normalizePathSegment(value, FALLBACK_ACCOUNT_USER_KEY);
|
|
106
|
+
}
|
|
107
|
+
function normalizeAccountKey(input) {
|
|
108
|
+
return {
|
|
109
|
+
hostKey: normalizeAccountHostKey(input.hostKey),
|
|
110
|
+
userKey: normalizeAccountUserKey(input.userKey)
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function accountDir(account) {
|
|
114
|
+
const normalized = normalizeAccountKey(account);
|
|
115
|
+
return join(accountsDir(), normalized.hostKey, normalized.userKey);
|
|
116
|
+
}
|
|
117
|
+
function accountProfilesDir(account) {
|
|
118
|
+
return join(accountDir(account), "profiles");
|
|
119
|
+
}
|
|
120
|
+
function accountProfileDir(account, wakeLoopProfileId) {
|
|
121
|
+
return join(accountProfilesDir(account), normalizeWakeLoopProfileId(wakeLoopProfileId));
|
|
122
|
+
}
|
|
123
|
+
function accountProfileViewPath(account, wakeLoopProfileId) {
|
|
124
|
+
return join(accountProfileDir(account, wakeLoopProfileId), "view.json");
|
|
125
|
+
}
|
|
126
|
+
function accountProfileLocalMetaPath(account, wakeLoopProfileId) {
|
|
127
|
+
return join(accountProfileDir(account, wakeLoopProfileId), "local-meta.json");
|
|
128
|
+
}
|
|
129
|
+
function accountProfileWorkspacePath(account, wakeLoopProfileId) {
|
|
130
|
+
return join(accountProfileDir(account, wakeLoopProfileId), "workspace");
|
|
131
|
+
}
|
|
132
|
+
function accountProfileSpaceCacheDir(account, wakeLoopProfileId) {
|
|
133
|
+
return join(accountProfileDir(account, wakeLoopProfileId), "space-cache");
|
|
134
|
+
}
|
|
135
|
+
function legacyAccountProfileSpacesDir(account, wakeLoopProfileId) {
|
|
136
|
+
return join(accountProfileDir(account, wakeLoopProfileId), "spaces");
|
|
137
|
+
}
|
|
138
|
+
function profileDir(wakeLoopProfileId) {
|
|
139
|
+
return join(wakeLoopRootDir(), "profiles", wakeLoopProfileId);
|
|
140
|
+
}
|
|
141
|
+
function runtimeDir(input = {}) {
|
|
142
|
+
return join(resolveWakeLoopRootDir(input), "runtime");
|
|
143
|
+
}
|
|
144
|
+
function runtimeLogsDir() {
|
|
145
|
+
return join(runtimeDir(), "logs");
|
|
146
|
+
}
|
|
147
|
+
function sessionsDir() {
|
|
148
|
+
return join(runtimeDir(), "sessions");
|
|
149
|
+
}
|
|
150
|
+
function systemDir(input = {}) {
|
|
151
|
+
return join(resolveWakeLoopRootDir(input), "system");
|
|
152
|
+
}
|
|
153
|
+
function skillsDir() {
|
|
154
|
+
return join(wakeLoopRootDir(), "skills");
|
|
155
|
+
}
|
|
156
|
+
function spacesDir(wakeLoopProfileId) {
|
|
157
|
+
return join(profileDir(wakeLoopProfileId), "spaces");
|
|
158
|
+
}
|
|
159
|
+
function locksDir(wakeLoopProfileId) {
|
|
160
|
+
return join(runtimeDir(), "locks", wakeLoopProfileId);
|
|
161
|
+
}
|
|
162
|
+
function profileViewPath(wakeLoopProfileId) {
|
|
163
|
+
return join(profileDir(wakeLoopProfileId), "view.json");
|
|
164
|
+
}
|
|
165
|
+
function normalizePathSegment(value, fallback) {
|
|
166
|
+
const normalized = String(value ?? "").trim().toLowerCase();
|
|
167
|
+
if (!normalized) return fallback;
|
|
168
|
+
const safe = normalized.replace(/[^a-z0-9._-]+/g, "_");
|
|
169
|
+
if (!safe) return fallback;
|
|
170
|
+
if (safe === "." || safe === "..") return fallback;
|
|
171
|
+
return safe.slice(0, MAX_ACCOUNT_PATH_SEGMENT_LENGTH);
|
|
172
|
+
}
|
|
173
|
+
function resolveWakeLoopEnvPresetFromArgv(argv) {
|
|
174
|
+
return resolveKnownWakeLoopEnvPresetFromArgv(argv) ?? DEFAULT_WAKELOOP_ENV_PRESET;
|
|
175
|
+
}
|
|
176
|
+
function resolveKnownWakeLoopEnvPresetFromArgv(argv) {
|
|
177
|
+
const entryName = resolveWakeLoopCliEntryNameFromArgv(argv);
|
|
178
|
+
if (!entryName) return null;
|
|
179
|
+
return WAKELOOP_ENV_PRESET_BY_ENTRY_NAME[entryName] ?? null;
|
|
180
|
+
}
|
|
181
|
+
function resolveWakeLoopCliEntryNameFromArgv(argv) {
|
|
182
|
+
return resolveCliEntryName(argv[1]);
|
|
183
|
+
}
|
|
184
|
+
function resolveCliEntryName(value) {
|
|
185
|
+
const raw = String(value ?? "").trim();
|
|
186
|
+
if (!raw) return null;
|
|
187
|
+
const normalizedName = parse(raw).name.trim().toLowerCase();
|
|
188
|
+
if (!normalizedName) return null;
|
|
189
|
+
if (!isWakeLoopCliEntryName(normalizedName)) return null;
|
|
190
|
+
return normalizedName;
|
|
191
|
+
}
|
|
192
|
+
function isWakeLoopCliEntryName(value) {
|
|
193
|
+
return value in WAKELOOP_ENV_PRESET_BY_ENTRY_NAME;
|
|
194
|
+
}
|
|
195
|
+
function normalizeWakeLoopEnvPreset(value) {
|
|
196
|
+
const normalized = String(value ?? "").trim().toLowerCase();
|
|
197
|
+
if (normalized === "prod" || normalized === "dev-local" || normalized === "canary") return normalized;
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
function resolveHomeDirectory(input) {
|
|
201
|
+
if (input.homeDir) return input.homeDir;
|
|
202
|
+
const env = input.env ?? process.env;
|
|
203
|
+
const fromEnv = String(env.HOME ?? "").trim();
|
|
204
|
+
if (fromEnv) return fromEnv;
|
|
205
|
+
return homedir();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
//#endregion
|
|
209
|
+
export { sessionsDir as A, profileViewPath as C, resolveWakeLoopRootDir as D, resolveWakeLoopEnvPreset as E, wakeLoopRootDir as F, spacesDir as M, systemDir as N, runtimeDir as O, wakeLoopBackupsDir as P, profileDir as S, resolveWakeLoopCliEntryNameFromArgv as T, legacyAccountProfileSpacesDir as _, accountProfileWorkspacePath as a, normalizeAccountKey as b, deviceDir as c, deviceOpenClawProfileWorkspaceDir as d, devicePreferencesPath as f, deviceSkillsStorePath as g, deviceSkillsInstallsPath as h, accountProfileViewPath as i, skillsDir as j, runtimeLogsDir as k, deviceOpenClawProfileBootstrapPath as l, deviceSkillsDir as m, accountProfileLocalMetaPath as n, accountsDir as o, deviceSkillsCustomTargetsPath as p, accountProfileSpaceCacheDir as r, deviceAgentRuntimePath as s, WAKELOOP_HOME_ENV_KEY as t, deviceOpenClawProfileDir as u, legacyRuntimeConfigPath as v, resolveDefaultWakeLoopHomeDirname as w, normalizeWakeLoopProfileId as x, locksDir as y };
|
|
210
|
+
//# sourceMappingURL=paths-F1dfknFj.js.map
|