@codyswann/lisa 3.5.1 → 3.5.3
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/dist/core/learnings-file-safety.d.ts +23 -0
- package/dist/core/learnings-file-safety.d.ts.map +1 -1
- package/dist/core/learnings-file-safety.js +34 -0
- package/dist/core/learnings-file-safety.js.map +1 -1
- package/dist/core/learnings-lock-capability.d.ts +45 -0
- package/dist/core/learnings-lock-capability.d.ts.map +1 -0
- package/dist/core/learnings-lock-capability.js +196 -0
- package/dist/core/learnings-lock-capability.js.map +1 -0
- package/dist/core/learnings-lock-fs.d.ts +29 -0
- package/dist/core/learnings-lock-fs.d.ts.map +1 -0
- package/dist/core/learnings-lock-fs.js +56 -0
- package/dist/core/learnings-lock-fs.js.map +1 -0
- package/dist/core/learnings-lock.d.ts +10 -0
- package/dist/core/learnings-lock.d.ts.map +1 -1
- package/dist/core/learnings-lock.js +36 -45
- package/dist/core/learnings-lock.js.map +1 -1
- package/dist/core/learnings-overflow.d.ts.map +1 -1
- package/dist/core/learnings-overflow.js +20 -11
- package/dist/core/learnings-overflow.js.map +1 -1
- package/dist/core/learnings-writer.d.ts.map +1 -1
- package/dist/core/learnings-writer.js +9 -3
- package/dist/core/learnings-writer.js.map +1 -1
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +3 -0
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
|
@@ -25,6 +25,29 @@ export declare function resolveSafeLearningTarget(projectRoot: string, relativeF
|
|
|
25
25
|
* @returns Existing content, or undefined when the file does not exist
|
|
26
26
|
*/
|
|
27
27
|
export declare function readExistingLearnings(target: string): Promise<string | undefined>;
|
|
28
|
+
/** A locked ledger transaction found its read-image already overwritten. */
|
|
29
|
+
export declare class LearningsConcurrentWriteError extends Error {
|
|
30
|
+
/**
|
|
31
|
+
* Build the operator-readable concurrent-write diagnosis.
|
|
32
|
+
* @param target - Resolved learnings file path
|
|
33
|
+
*/
|
|
34
|
+
constructor(target: string);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Prove the ledger still holds the bytes this transaction read before letting
|
|
38
|
+
* an atomic rename publish over them.
|
|
39
|
+
*
|
|
40
|
+
* The ledger is read-modify-write, so a writer that publishes over an image it
|
|
41
|
+
* did not read erases whatever landed in between. The lock is what prevents
|
|
42
|
+
* that, and this is the arm that makes a lock failure LOUD: the whole class of
|
|
43
|
+
* bugs here (CodySwannGT/lisa#2488, and the 19 entries lost to a merge before
|
|
44
|
+
* it) is defined by nothing noticing. This detects an interloper rather than
|
|
45
|
+
* excluding one — it is the second line, not the lock — but it converts a
|
|
46
|
+
* silent lost learning into a failed capture the caller can retry.
|
|
47
|
+
* @param target - Resolved learnings file path
|
|
48
|
+
* @param preImage - Content this transaction read under the lock
|
|
49
|
+
*/
|
|
50
|
+
export declare function assertLearningsUnchanged(target: string, preImage: string | undefined): Promise<void>;
|
|
28
51
|
/**
|
|
29
52
|
* Reject parent-directory symlinks that resolve outside the project root.
|
|
30
53
|
* @param root - Resolved project root
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"learnings-file-safety.d.ts","sourceRoot":"","sources":["../../src/core/learnings-file-safety.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAkBpD;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAyC7B;AAkBD;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAYf"}
|
|
1
|
+
{"version":3,"file":"learnings-file-safety.d.ts","sourceRoot":"","sources":["../../src/core/learnings-file-safety.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAkBpD;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAyC7B;AAED,4EAA4E;AAC5E,qBAAa,6BAA8B,SAAQ,KAAK;IACtD;;;OAGG;gBACS,MAAM,EAAE,MAAM;CAS3B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,OAAO,CAAC,IAAI,CAAC,CAKf;AAkBD;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAYf"}
|
|
@@ -78,6 +78,40 @@ export async function readExistingLearnings(target) {
|
|
|
78
78
|
throw error;
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
|
+
/** A locked ledger transaction found its read-image already overwritten. */
|
|
82
|
+
export class LearningsConcurrentWriteError extends Error {
|
|
83
|
+
/**
|
|
84
|
+
* Build the operator-readable concurrent-write diagnosis.
|
|
85
|
+
* @param target - Resolved learnings file path
|
|
86
|
+
*/
|
|
87
|
+
constructor(target) {
|
|
88
|
+
super(`Refusing to publish project learnings: ${target} changed after this ` +
|
|
89
|
+
`write read it, so publishing would erase another writer's entry. ` +
|
|
90
|
+
`Nothing was written and no entry was lost — retry the capture. If ` +
|
|
91
|
+
`this repeats, the ledger lock is not holding.`);
|
|
92
|
+
this.name = "LearningsConcurrentWriteError";
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Prove the ledger still holds the bytes this transaction read before letting
|
|
97
|
+
* an atomic rename publish over them.
|
|
98
|
+
*
|
|
99
|
+
* The ledger is read-modify-write, so a writer that publishes over an image it
|
|
100
|
+
* did not read erases whatever landed in between. The lock is what prevents
|
|
101
|
+
* that, and this is the arm that makes a lock failure LOUD: the whole class of
|
|
102
|
+
* bugs here (CodySwannGT/lisa#2488, and the 19 entries lost to a merge before
|
|
103
|
+
* it) is defined by nothing noticing. This detects an interloper rather than
|
|
104
|
+
* excluding one — it is the second line, not the lock — but it converts a
|
|
105
|
+
* silent lost learning into a failed capture the caller can retry.
|
|
106
|
+
* @param target - Resolved learnings file path
|
|
107
|
+
* @param preImage - Content this transaction read under the lock
|
|
108
|
+
*/
|
|
109
|
+
export async function assertLearningsUnchanged(target, preImage) {
|
|
110
|
+
const current = await readExistingLearnings(target);
|
|
111
|
+
if (current !== preImage) {
|
|
112
|
+
throw new LearningsConcurrentWriteError(target);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
81
115
|
/**
|
|
82
116
|
* Throw the shared conflict diagnosis when an over-budget file is corrupted.
|
|
83
117
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"learnings-file-safety.js","sourceRoot":"","sources":["../../src/core/learnings-file-safety.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"learnings-file-safety.js","sourceRoot":"","sources":["../../src/core/learnings-file-safety.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Identity of one lock generation, as observed by a would-be reclaimer. */
|
|
2
|
+
export interface LockGenerationIdentity {
|
|
3
|
+
/** Device of the inode judged stale. */
|
|
4
|
+
readonly dev: number;
|
|
5
|
+
/** Inode judged stale. */
|
|
6
|
+
readonly ino: number;
|
|
7
|
+
/** Owner token when the lock was parseable; undefined when unowned. */
|
|
8
|
+
readonly token: string | undefined;
|
|
9
|
+
/** Owner pid when the lock was parseable. */
|
|
10
|
+
readonly pid: number | undefined;
|
|
11
|
+
/** Owner creation timestamp when the lock was parseable. */
|
|
12
|
+
readonly createdAt: number | undefined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Run an operation while holding the sole right to delete one lock generation.
|
|
16
|
+
*
|
|
17
|
+
* The capability is what makes the caller's verify-then-unlink safe, and the
|
|
18
|
+
* argument is not probabilistic:
|
|
19
|
+
*
|
|
20
|
+
* 1. Two reclaimers that observed the same lock derive the same capability
|
|
21
|
+
* path — dev, ino, and the owner triple are immutable for a lock file's
|
|
22
|
+
* lifetime, since owner metadata is written in full *before* it is linked
|
|
23
|
+
* into place and never rewritten — and the exclusive create admits exactly
|
|
24
|
+
* one of them. The loser deletes nothing at all.
|
|
25
|
+
* 2. The lock path can therefore only change while the capability is held if
|
|
26
|
+
* its own owner released it, and the caller has already proven that owner's
|
|
27
|
+
* process is gone. A dead process performs no unlink.
|
|
28
|
+
* 3. An acquisition cannot intervene either: acquiring requires the lock path
|
|
29
|
+
* to be free, and freeing it requires one of the two deletions ruled out
|
|
30
|
+
* above.
|
|
31
|
+
*
|
|
32
|
+
* So between the caller's proof and its unlink, the lock path still holds
|
|
33
|
+
* exactly the generation that was proven stale. This cannot interleave.
|
|
34
|
+
*
|
|
35
|
+
* Never spins: a live contender means someone else is already reclaiming this
|
|
36
|
+
* very generation, so `whenContended` is returned immediately and the caller's
|
|
37
|
+
* own acquire loop — which owns the wall-clock budget — does the waiting.
|
|
38
|
+
* @param lockPath - Shared lock path
|
|
39
|
+
* @param identity - Identity of the generation to be deleted
|
|
40
|
+
* @param whenContended - Result to return when another live holder has it
|
|
41
|
+
* @param operation - Work performed while the capability is held
|
|
42
|
+
* @returns The operation's result, or `whenContended`
|
|
43
|
+
*/
|
|
44
|
+
export declare function withReclaimCapability<T>(lockPath: string, identity: LockGenerationIdentity, whenContended: T, operation: () => Promise<T>): Promise<T>;
|
|
45
|
+
//# sourceMappingURL=learnings-lock-capability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"learnings-lock-capability.d.ts","sourceRoot":"","sources":["../../src/core/learnings-lock-capability.ts"],"names":[],"mappings":"AAyBA,4EAA4E;AAC5E,MAAM,WAAW,sBAAsB;IACrC,wCAAwC;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,0BAA0B;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,6CAA6C;IAC7C,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,4DAA4D;IAC5D,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAC3C,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,sBAAsB,EAChC,aAAa,EAAE,CAAC,EAChB,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,CAUZ"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The exclusive right to delete one stale lock generation.
|
|
3
|
+
*
|
|
4
|
+
* Deleting a stale lock is a two-syscall sequence — prove the path still holds
|
|
5
|
+
* the inode judged stale, then unlink it — and POSIX offers no "unlink only if
|
|
6
|
+
* still this inode". Narrowing that window is not a fix
|
|
7
|
+
* (CodySwannGT/lisa#2488): a second reclaimer whose proof predated the first
|
|
8
|
+
* one's unlink deleted whichever lock had *since* been acquired at the path, so
|
|
9
|
+
* two writers held the same "exclusive" lock, both read the ledger, and one
|
|
10
|
+
* learning vanished with no error at all.
|
|
11
|
+
*
|
|
12
|
+
* The window is closed by making the RIGHT to delete a generation exclusive
|
|
13
|
+
* rather than by shrinking the window. This module publishes that right as a
|
|
14
|
+
* capability file created with `O_CREAT|O_EXCL`, at a path that is a pure
|
|
15
|
+
* function of the generation's identity.
|
|
16
|
+
* @module core/learnings-lock-capability
|
|
17
|
+
*/
|
|
18
|
+
import { createHash } from "node:crypto";
|
|
19
|
+
import { readFile, rename, writeFile } from "node:fs/promises";
|
|
20
|
+
import { isProcessLive, removeFileIfPresent, statFile, } from "./learnings-lock-fs.js";
|
|
21
|
+
/**
|
|
22
|
+
* Run an operation while holding the sole right to delete one lock generation.
|
|
23
|
+
*
|
|
24
|
+
* The capability is what makes the caller's verify-then-unlink safe, and the
|
|
25
|
+
* argument is not probabilistic:
|
|
26
|
+
*
|
|
27
|
+
* 1. Two reclaimers that observed the same lock derive the same capability
|
|
28
|
+
* path — dev, ino, and the owner triple are immutable for a lock file's
|
|
29
|
+
* lifetime, since owner metadata is written in full *before* it is linked
|
|
30
|
+
* into place and never rewritten — and the exclusive create admits exactly
|
|
31
|
+
* one of them. The loser deletes nothing at all.
|
|
32
|
+
* 2. The lock path can therefore only change while the capability is held if
|
|
33
|
+
* its own owner released it, and the caller has already proven that owner's
|
|
34
|
+
* process is gone. A dead process performs no unlink.
|
|
35
|
+
* 3. An acquisition cannot intervene either: acquiring requires the lock path
|
|
36
|
+
* to be free, and freeing it requires one of the two deletions ruled out
|
|
37
|
+
* above.
|
|
38
|
+
*
|
|
39
|
+
* So between the caller's proof and its unlink, the lock path still holds
|
|
40
|
+
* exactly the generation that was proven stale. This cannot interleave.
|
|
41
|
+
*
|
|
42
|
+
* Never spins: a live contender means someone else is already reclaiming this
|
|
43
|
+
* very generation, so `whenContended` is returned immediately and the caller's
|
|
44
|
+
* own acquire loop — which owns the wall-clock budget — does the waiting.
|
|
45
|
+
* @param lockPath - Shared lock path
|
|
46
|
+
* @param identity - Identity of the generation to be deleted
|
|
47
|
+
* @param whenContended - Result to return when another live holder has it
|
|
48
|
+
* @param operation - Work performed while the capability is held
|
|
49
|
+
* @returns The operation's result, or `whenContended`
|
|
50
|
+
*/
|
|
51
|
+
export async function withReclaimCapability(lockPath, identity, whenContended, operation) {
|
|
52
|
+
const capability = reclaimCapabilityPath(lockPath, identity);
|
|
53
|
+
if (!(await claimReclaimCapability(capability))) {
|
|
54
|
+
return whenContended;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
return await operation();
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
await removeFileIfPresent(capability);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Derive the capability path guarding one lock generation.
|
|
65
|
+
*
|
|
66
|
+
* The name is a pure function of the observed identity, so every observer of
|
|
67
|
+
* the same lock contends for the same path and no observer of a *different*
|
|
68
|
+
* lock is ever excluded by it. A hash collision would only serialize more
|
|
69
|
+
* reclaimers, never fewer, so it would cost liveness and never safety.
|
|
70
|
+
* @param lockPath - Shared lock path
|
|
71
|
+
* @param identity - Identity of the generation to be deleted
|
|
72
|
+
* @returns Capability path for that generation
|
|
73
|
+
*/
|
|
74
|
+
function reclaimCapabilityPath(lockPath, identity) {
|
|
75
|
+
const serialized = JSON.stringify([
|
|
76
|
+
identity.dev,
|
|
77
|
+
identity.ino,
|
|
78
|
+
identity.token ?? null,
|
|
79
|
+
identity.pid ?? null,
|
|
80
|
+
identity.createdAt ?? null,
|
|
81
|
+
]);
|
|
82
|
+
const digest = createHash("sha256").update(serialized).digest("hex");
|
|
83
|
+
return `${lockPath}.${digest.slice(0, 32)}.reclaim`;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Take the capability, recovering it only from a provably dead holder.
|
|
87
|
+
* @param capability - Generation-scoped capability path
|
|
88
|
+
* @returns Whether this process now holds the capability
|
|
89
|
+
*/
|
|
90
|
+
async function claimReclaimCapability(capability) {
|
|
91
|
+
if (await createReclaimCapability(capability)) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
if (!(await breakDeadReclaimCapability(capability))) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
return createReclaimCapability(capability);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Publish this process as the capability holder with an exclusive create.
|
|
101
|
+
* @param capability - Generation-scoped capability path
|
|
102
|
+
* @returns Whether the exclusive create succeeded
|
|
103
|
+
*/
|
|
104
|
+
async function createReclaimCapability(capability) {
|
|
105
|
+
const holder = { pid: process.pid, createdAt: Date.now() };
|
|
106
|
+
try {
|
|
107
|
+
await writeFile(capability, JSON.stringify(holder), {
|
|
108
|
+
encoding: "utf8",
|
|
109
|
+
flag: "wx",
|
|
110
|
+
});
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
if (error.code === "EEXIST") {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Release a capability abandoned by a reclaimer that crashed mid-reclaim.
|
|
122
|
+
*
|
|
123
|
+
* Only an `ESRCH`-dead holder is ever displaced, because a dead process
|
|
124
|
+
* executes no unlink — so displacing it cannot produce a second live deleter,
|
|
125
|
+
* which is the entire property this capability exists to guarantee. A holder
|
|
126
|
+
* that is alive, unreadable, or merely old is left alone: the lock then stays
|
|
127
|
+
* unreclaimable and writers fail loudly against their acquire budget, which is
|
|
128
|
+
* strictly better than the silent lost write being guarded against.
|
|
129
|
+
*
|
|
130
|
+
* The displacement itself is a single rename — atomic, and conditional on the
|
|
131
|
+
* source still existing — so concurrent breakers cannot both win. The freed
|
|
132
|
+
* capability is then re-taken by whoever wins the exclusive create, which is
|
|
133
|
+
* not necessarily this process.
|
|
134
|
+
* @param capability - Generation-scoped capability path
|
|
135
|
+
* @returns Whether the capability was freed and may be re-taken
|
|
136
|
+
*/
|
|
137
|
+
async function breakDeadReclaimCapability(capability) {
|
|
138
|
+
const holder = await readReclaimHolder(capability);
|
|
139
|
+
if (holder === undefined || isProcessLive(holder.pid)) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
const discarded = `${capability}.${crypto.randomUUID()}.broken`;
|
|
143
|
+
try {
|
|
144
|
+
await rename(capability, discarded);
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
if (error.code === "ENOENT") {
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
await removeFileIfPresent(discarded);
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Read bounded capability-holder metadata; anything else is unreadable.
|
|
157
|
+
* @param capability - Generation-scoped capability path
|
|
158
|
+
* @returns Parsed holder, or undefined when it cannot be trusted
|
|
159
|
+
*/
|
|
160
|
+
async function readReclaimHolder(capability) {
|
|
161
|
+
const metadata = await statFile(capability);
|
|
162
|
+
if (metadata === undefined || !metadata.isFile() || metadata.size > 512) {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
const parsed = JSON.parse(await readFile(capability, "utf8"));
|
|
167
|
+
return isReclaimHolder(parsed) ? parsed : undefined;
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Narrow parsed capability metadata to the exact holder shape.
|
|
175
|
+
* @param value - Parsed metadata
|
|
176
|
+
* @returns Whether the metadata is a reclaim holder
|
|
177
|
+
*/
|
|
178
|
+
function isReclaimHolder(value) {
|
|
179
|
+
if (value === null ||
|
|
180
|
+
typeof value !== "object" ||
|
|
181
|
+
Object.getPrototypeOf(value) !== Object.prototype) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
const keys = Reflect.ownKeys(value);
|
|
185
|
+
if (keys.length !== 2 ||
|
|
186
|
+
keys.some(key => typeof key !== "string" || !["pid", "createdAt"].includes(key))) {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
const holder = value;
|
|
190
|
+
return (typeof holder.pid === "number" &&
|
|
191
|
+
Number.isSafeInteger(holder.pid) &&
|
|
192
|
+
holder.pid > 0 &&
|
|
193
|
+
typeof holder.createdAt === "number" &&
|
|
194
|
+
Number.isSafeInteger(holder.createdAt));
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=learnings-lock-capability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"learnings-lock-capability.js","sourceRoot":"","sources":["../../src/core/learnings-lock-capability.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem and process primitives shared by the file lock and its stale-lock
|
|
3
|
+
* reclaim capability.
|
|
4
|
+
*
|
|
5
|
+
* Extracted verbatim from `learnings-lock.ts` so the reclaim capability
|
|
6
|
+
* (`learnings-lock-capability.ts`) can reuse the exact same probes the lock
|
|
7
|
+
* itself uses. A second, subtly different copy of "is this process alive" or
|
|
8
|
+
* "is an absent file an error" is precisely how a lock grows a hole.
|
|
9
|
+
* @module core/learnings-lock-fs
|
|
10
|
+
*/
|
|
11
|
+
import { lstat } from "node:fs/promises";
|
|
12
|
+
/**
|
|
13
|
+
* Read file metadata without treating an absent path as an error.
|
|
14
|
+
* @param filePath - Filesystem path
|
|
15
|
+
* @returns File metadata or undefined
|
|
16
|
+
*/
|
|
17
|
+
export declare function statFile(filePath: string): Promise<Awaited<ReturnType<typeof lstat>> | undefined>;
|
|
18
|
+
/**
|
|
19
|
+
* Remove one path without recursive deletion.
|
|
20
|
+
* @param filePath - Regular file or hard-link path
|
|
21
|
+
*/
|
|
22
|
+
export declare function removeFileIfPresent(filePath: string): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Treat permission-denied PID probes as live and missing PIDs as dead.
|
|
25
|
+
* @param pid - Declared owner process id
|
|
26
|
+
* @returns Whether the process may still be alive
|
|
27
|
+
*/
|
|
28
|
+
export declare function isProcessLive(pid: number): boolean;
|
|
29
|
+
//# sourceMappingURL=learnings-lock-fs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"learnings-lock-fs.d.ts","sourceRoot":"","sources":["../../src/core/learnings-lock-fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,KAAK,EAAU,MAAM,kBAAkB,CAAC;AAEjD;;;;GAIG;AACH,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC,CASxD;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQzE;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOlD"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem and process primitives shared by the file lock and its stale-lock
|
|
3
|
+
* reclaim capability.
|
|
4
|
+
*
|
|
5
|
+
* Extracted verbatim from `learnings-lock.ts` so the reclaim capability
|
|
6
|
+
* (`learnings-lock-capability.ts`) can reuse the exact same probes the lock
|
|
7
|
+
* itself uses. A second, subtly different copy of "is this process alive" or
|
|
8
|
+
* "is an absent file an error" is precisely how a lock grows a hole.
|
|
9
|
+
* @module core/learnings-lock-fs
|
|
10
|
+
*/
|
|
11
|
+
import { lstat, unlink } from "node:fs/promises";
|
|
12
|
+
/**
|
|
13
|
+
* Read file metadata without treating an absent path as an error.
|
|
14
|
+
* @param filePath - Filesystem path
|
|
15
|
+
* @returns File metadata or undefined
|
|
16
|
+
*/
|
|
17
|
+
export async function statFile(filePath) {
|
|
18
|
+
try {
|
|
19
|
+
return await lstat(filePath);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (error.code === "ENOENT") {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Remove one path without recursive deletion.
|
|
30
|
+
* @param filePath - Regular file or hard-link path
|
|
31
|
+
*/
|
|
32
|
+
export async function removeFileIfPresent(filePath) {
|
|
33
|
+
try {
|
|
34
|
+
await unlink(filePath);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (error.code !== "ENOENT") {
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Treat permission-denied PID probes as live and missing PIDs as dead.
|
|
44
|
+
* @param pid - Declared owner process id
|
|
45
|
+
* @returns Whether the process may still be alive
|
|
46
|
+
*/
|
|
47
|
+
export function isProcessLive(pid) {
|
|
48
|
+
try {
|
|
49
|
+
process.kill(pid, 0);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
return error.code !== "ESRCH";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=learnings-lock-fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"learnings-lock-fs.js","sourceRoot":"","sources":["../../src/core/learnings-lock-fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAEjD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,QAAgB;IAEhB,IAAI,CAAC;QACH,OAAO,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,QAAgB;IACxD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAQ,KAA+B,CAAC,IAAI,KAAK,OAAO,CAAC;IAC3D,CAAC;AACH,CAAC"}
|
|
@@ -39,6 +39,16 @@ export interface StaleLockObservation {
|
|
|
39
39
|
export declare function observeStaleLock(lockPath: string): Promise<StaleLockObservation | null>;
|
|
40
40
|
/**
|
|
41
41
|
* Reclaim only the same lock inode retained in a safe quarantine link.
|
|
42
|
+
*
|
|
43
|
+
* Proving the lock is still the inode judged stale and unlinking it are two
|
|
44
|
+
* syscalls, and POSIX has no "unlink only if still this inode". Every reclaimer
|
|
45
|
+
* that passed the proof therefore used to unlink whatever sat at the path
|
|
46
|
+
* afterwards — including a lock a live writer had legitimately acquired in
|
|
47
|
+
* between, which left two writers holding one "exclusive" lock and silently
|
|
48
|
+
* dropped a learning (CodySwannGT/lisa#2488). That gap is closed by holding the
|
|
49
|
+
* generation's exclusive reclaim capability across both syscalls; see
|
|
50
|
+
* `learnings-lock-capability.ts` for why this cannot interleave rather than
|
|
51
|
+
* merely interleaving rarely.
|
|
42
52
|
* @param lockPath - Shared lock path
|
|
43
53
|
* @param observation - Snapshot that judged this lock reclaimable
|
|
44
54
|
* @returns Whether the observed lock was reclaimed
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"learnings-lock.d.ts","sourceRoot":"","sources":["../../src/core/learnings-lock.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"learnings-lock.d.ts","sourceRoot":"","sources":["../../src/core/learnings-lock.ts"],"names":[],"mappings":"AAgBA,8DAA8D;AAC9D,UAAU,SAAS;IACjB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAQD;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,CAAC,EAC5C,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,CAEZ;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EACxC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,CAaZ;AAuED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAAC;IACtC,iDAAiD;IACjD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAcD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAiBtC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,oBAAoB,GAChC,OAAO,CAAC,OAAO,CAAC,CAOlB"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/** Cross-process serialization for project learnings writes. */
|
|
2
|
-
import { link,
|
|
2
|
+
import { link, readFile, unlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import { withReclaimCapability, } from "./learnings-lock-capability.js";
|
|
4
|
+
import { isProcessLive, removeFileIfPresent, statFile, } from "./learnings-lock-fs.js";
|
|
3
5
|
const MAX_LOCK_ATTEMPTS = 200;
|
|
4
6
|
const LOCK_RETRY_DELAY_MS = 10;
|
|
5
7
|
const STALE_LOCK_MS = 30_000;
|
|
@@ -128,11 +130,44 @@ export async function observeStaleLock(lockPath) {
|
|
|
128
130
|
}
|
|
129
131
|
/**
|
|
130
132
|
* Reclaim only the same lock inode retained in a safe quarantine link.
|
|
133
|
+
*
|
|
134
|
+
* Proving the lock is still the inode judged stale and unlinking it are two
|
|
135
|
+
* syscalls, and POSIX has no "unlink only if still this inode". Every reclaimer
|
|
136
|
+
* that passed the proof therefore used to unlink whatever sat at the path
|
|
137
|
+
* afterwards — including a lock a live writer had legitimately acquired in
|
|
138
|
+
* between, which left two writers holding one "exclusive" lock and silently
|
|
139
|
+
* dropped a learning (CodySwannGT/lisa#2488). That gap is closed by holding the
|
|
140
|
+
* generation's exclusive reclaim capability across both syscalls; see
|
|
141
|
+
* `learnings-lock-capability.ts` for why this cannot interleave rather than
|
|
142
|
+
* merely interleaving rarely.
|
|
131
143
|
* @param lockPath - Shared lock path
|
|
132
144
|
* @param observation - Snapshot that judged this lock reclaimable
|
|
133
145
|
* @returns Whether the observed lock was reclaimed
|
|
134
146
|
*/
|
|
135
147
|
export async function reclaimObservedStaleLock(lockPath, observation) {
|
|
148
|
+
return withReclaimCapability(lockPath, observedGenerationIdentity(observation), false, async () => deleteObservedGeneration(lockPath, observation));
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Describe the observed generation for the capability that guards it.
|
|
152
|
+
* @param observation - Snapshot that judged the lock reclaimable
|
|
153
|
+
* @returns Identity of the generation this reclaim may delete
|
|
154
|
+
*/
|
|
155
|
+
function observedGenerationIdentity(observation) {
|
|
156
|
+
return {
|
|
157
|
+
dev: observation.dev,
|
|
158
|
+
ino: observation.ino,
|
|
159
|
+
token: observation.owner?.token,
|
|
160
|
+
pid: observation.owner?.pid,
|
|
161
|
+
createdAt: observation.owner?.createdAt,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Delete the observed lock generation while its reclaim capability is held.
|
|
166
|
+
* @param lockPath - Shared lock path
|
|
167
|
+
* @param observation - Snapshot that judged this lock reclaimable
|
|
168
|
+
* @returns Whether the observed lock was reclaimed
|
|
169
|
+
*/
|
|
170
|
+
async function deleteObservedGeneration(lockPath, observation) {
|
|
136
171
|
// Pin whatever currently sits at the lock path so its inode cannot be
|
|
137
172
|
// recycled underneath the checks below, then prove it is still the very
|
|
138
173
|
// inode and ownership this observation judged stale before deleting it.
|
|
@@ -218,36 +253,6 @@ async function sameFile(left, right) {
|
|
|
218
253
|
leftStat.dev === rightStat.dev &&
|
|
219
254
|
leftStat.ino === rightStat.ino);
|
|
220
255
|
}
|
|
221
|
-
/**
|
|
222
|
-
* Read file metadata without treating an absent path as an error.
|
|
223
|
-
* @param filePath - Filesystem path
|
|
224
|
-
* @returns File metadata or undefined
|
|
225
|
-
*/
|
|
226
|
-
async function statFile(filePath) {
|
|
227
|
-
try {
|
|
228
|
-
return await lstat(filePath);
|
|
229
|
-
}
|
|
230
|
-
catch (error) {
|
|
231
|
-
if (error.code === "ENOENT") {
|
|
232
|
-
return undefined;
|
|
233
|
-
}
|
|
234
|
-
throw error;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* Remove one path without recursive deletion.
|
|
239
|
-
* @param filePath - Regular file or hard-link path
|
|
240
|
-
*/
|
|
241
|
-
async function removeFileIfPresent(filePath) {
|
|
242
|
-
try {
|
|
243
|
-
await unlink(filePath);
|
|
244
|
-
}
|
|
245
|
-
catch (error) {
|
|
246
|
-
if (error.code !== "ENOENT") {
|
|
247
|
-
throw error;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
256
|
/**
|
|
252
257
|
* Narrow parsed lock metadata to the exact ownership shape.
|
|
253
258
|
* @param value - Parsed metadata
|
|
@@ -273,20 +278,6 @@ function isLockOwner(value) {
|
|
|
273
278
|
typeof owner.createdAt === "number" &&
|
|
274
279
|
Number.isSafeInteger(owner.createdAt));
|
|
275
280
|
}
|
|
276
|
-
/**
|
|
277
|
-
* Treat permission-denied PID probes as live and missing PIDs as dead.
|
|
278
|
-
* @param pid - Declared owner process id
|
|
279
|
-
* @returns Whether the process may still be alive
|
|
280
|
-
*/
|
|
281
|
-
function isProcessLive(pid) {
|
|
282
|
-
try {
|
|
283
|
-
process.kill(pid, 0);
|
|
284
|
-
return true;
|
|
285
|
-
}
|
|
286
|
-
catch (error) {
|
|
287
|
-
return error.code !== "ESRCH";
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
281
|
/**
|
|
291
282
|
* Await a short retry delay without blocking the event loop.
|
|
292
283
|
* @param milliseconds - Delay duration
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"learnings-lock.js","sourceRoot":"","sources":["../../src/core/learnings-lock.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,OAAO,EAAE,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"learnings-lock.js","sourceRoot":"","sources":["../../src/core/learnings-lock.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"learnings-overflow.d.ts","sourceRoot":"","sources":["../../src/core/learnings-overflow.ts"],"names":[],"mappings":"AAkDA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EACL,oBAAoB,EAIrB,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"learnings-overflow.d.ts","sourceRoot":"","sources":["../../src/core/learnings-overflow.ts"],"names":[],"mappings":"AAkDA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EACL,oBAAoB,EAIrB,MAAM,yBAAyB,CAAC;AAgBjC;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAI1E;AA6CD,6DAA6D;AAC7D,MAAM,WAAW,yBAAyB;IACxC,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wCAAwC;IACxC,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;CAC5C;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,yBAAyB,CAAC,CAIpC;AAED,kEAAkE;AAClE,MAAM,WAAW,sBAAsB;IACrC,8BAA8B;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,0CAA0C;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,SAAS,MAAM,EAAE,GACrB,OAAO,CAAC,sBAAsB,CAAC,CAwBjC;AA0BD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,KAAK,CAAC,CAyBhB"}
|