loopforge 1.12.0 → 2.0.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 +172 -95
- package/dist/backends/interface.d.ts +3 -9
- package/dist/backends/interface.d.ts.map +1 -1
- package/dist/backends/interface.js +1 -5
- package/dist/backends/interface.js.map +1 -1
- package/dist/canonical-state.d.ts +53 -0
- package/dist/canonical-state.d.ts.map +1 -0
- package/dist/canonical-state.js +161 -0
- package/dist/canonical-state.js.map +1 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +227 -0
- package/dist/cli.js.map +1 -0
- package/dist/enforcement-gate.d.ts +44 -0
- package/dist/enforcement-gate.d.ts.map +1 -0
- package/dist/enforcement-gate.js +271 -0
- package/dist/enforcement-gate.js.map +1 -0
- package/dist/engine.d.ts +17 -7
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +158 -249
- package/dist/engine.js.map +1 -1
- package/dist/evidence-provider.d.ts +113 -0
- package/dist/evidence-provider.d.ts.map +1 -0
- package/dist/evidence-provider.js +419 -0
- package/dist/evidence-provider.js.map +1 -0
- package/dist/index.d.ts +19 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -10
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +15 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +49 -0
- package/dist/init.js.map +1 -0
- package/dist/interop.d.ts +30 -0
- package/dist/interop.d.ts.map +1 -0
- package/dist/interop.js +29 -0
- package/dist/interop.js.map +1 -0
- package/dist/loop-compiler.d.ts +14 -64
- package/dist/loop-compiler.d.ts.map +1 -1
- package/dist/loop-compiler.js +307 -2001
- package/dist/loop-compiler.js.map +1 -1
- package/dist/loop-store.d.ts +82 -0
- package/dist/loop-store.d.ts.map +1 -0
- package/dist/loop-store.js +332 -0
- package/dist/loop-store.js.map +1 -0
- package/dist/mcp/server.d.ts +9 -6
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +109 -73
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/session.d.ts +84 -20
- package/dist/mcp/session.d.ts.map +1 -1
- package/dist/mcp/session.js +718 -316
- package/dist/mcp/session.js.map +1 -1
- package/dist/mcp/tools.d.ts +18 -268
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +225 -12
- package/dist/mcp/tools.js.map +1 -1
- package/dist/observability.d.ts +36 -16
- package/dist/observability.d.ts.map +1 -1
- package/dist/observability.js +82 -23
- package/dist/observability.js.map +1 -1
- package/dist/policy-metrics.d.ts +46 -0
- package/dist/policy-metrics.d.ts.map +1 -0
- package/dist/policy-metrics.js +146 -0
- package/dist/policy-metrics.js.map +1 -0
- package/dist/policy.d.ts +58 -75
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +122 -93
- package/dist/policy.js.map +1 -1
- package/dist/prompt-assembler.d.ts +30 -0
- package/dist/prompt-assembler.d.ts.map +1 -0
- package/dist/prompt-assembler.js +257 -0
- package/dist/prompt-assembler.js.map +1 -0
- package/dist/prompt-policy.d.ts +29 -0
- package/dist/prompt-policy.d.ts.map +1 -0
- package/dist/prompt-policy.js +51 -0
- package/dist/prompt-policy.js.map +1 -0
- package/dist/protocol.d.ts +117 -91
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +40 -36
- package/dist/protocol.js.map +1 -1
- package/dist/replay.d.ts.map +1 -1
- package/dist/replay.js +1 -27
- package/dist/replay.js.map +1 -1
- package/dist/round-coordinator.d.ts +90 -0
- package/dist/round-coordinator.d.ts.map +1 -0
- package/dist/round-coordinator.js +186 -0
- package/dist/round-coordinator.js.map +1 -0
- package/dist/round-driver.d.ts +53 -0
- package/dist/round-driver.d.ts.map +1 -0
- package/dist/round-driver.js +101 -0
- package/dist/round-driver.js.map +1 -0
- package/dist/round-transaction.d.ts +70 -0
- package/dist/round-transaction.d.ts.map +1 -0
- package/dist/round-transaction.js +290 -0
- package/dist/round-transaction.js.map +1 -0
- package/dist/runtime.d.ts +35 -17
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +357 -344
- package/dist/runtime.js.map +1 -1
- package/dist/storage.d.ts +38 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +201 -0
- package/dist/storage.js.map +1 -0
- package/dist/verification-gate.d.ts +39 -7
- package/dist/verification-gate.d.ts.map +1 -1
- package/dist/verification-gate.js +198 -9
- package/dist/verification-gate.js.map +1 -1
- package/loop_policy.json +26 -47
- package/package.json +13 -10
- package/skills/perception/SKILL.md +80 -249
- package/dist/backends/fs.d.ts +0 -36
- package/dist/backends/fs.d.ts.map +0 -1
- package/dist/backends/fs.js +0 -358
- package/dist/backends/fs.js.map +0 -1
- package/dist/builder.d.ts +0 -12
- package/dist/builder.d.ts.map +0 -1
- package/dist/builder.js +0 -259
- package/dist/builder.js.map +0 -1
- package/dist/mcp-server.d.ts +0 -12
- package/dist/mcp-server.d.ts.map +0 -1
- package/dist/mcp-server.js +0 -14
- package/dist/mcp-server.js.map +0 -1
- package/dist/memory-bridge.d.ts +0 -47
- package/dist/memory-bridge.d.ts.map +0 -1
- package/dist/memory-bridge.js +0 -290
- package/dist/memory-bridge.js.map +0 -1
- package/dist/tests/_helpers.d.ts +0 -25
- package/dist/tests/_helpers.d.ts.map +0 -1
- package/dist/tests/_helpers.js +0 -47
- package/dist/tests/_helpers.js.map +0 -1
- package/dist/tests/builder.test.d.ts +0 -2
- package/dist/tests/builder.test.d.ts.map +0 -1
- package/dist/tests/builder.test.js +0 -110
- package/dist/tests/builder.test.js.map +0 -1
- package/dist/tests/engine.test.d.ts +0 -2
- package/dist/tests/engine.test.d.ts.map +0 -1
- package/dist/tests/engine.test.js +0 -371
- package/dist/tests/engine.test.js.map +0 -1
- package/dist/tests/generate-schema.test.d.ts +0 -8
- package/dist/tests/generate-schema.test.d.ts.map +0 -1
- package/dist/tests/generate-schema.test.js +0 -199
- package/dist/tests/generate-schema.test.js.map +0 -1
- package/dist/tests/loop-compiler.test.d.ts +0 -2
- package/dist/tests/loop-compiler.test.d.ts.map +0 -1
- package/dist/tests/loop-compiler.test.js +0 -1051
- package/dist/tests/loop-compiler.test.js.map +0 -1
- package/dist/tests/mcp.test.d.ts +0 -7
- package/dist/tests/mcp.test.d.ts.map +0 -1
- package/dist/tests/mcp.test.js +0 -485
- package/dist/tests/mcp.test.js.map +0 -1
- package/dist/tests/memory-bridge.test.d.ts +0 -8
- package/dist/tests/memory-bridge.test.d.ts.map +0 -1
- package/dist/tests/memory-bridge.test.js +0 -383
- package/dist/tests/memory-bridge.test.js.map +0 -1
- package/dist/tests/policy.test.d.ts +0 -2
- package/dist/tests/policy.test.d.ts.map +0 -1
- package/dist/tests/policy.test.js +0 -49
- package/dist/tests/policy.test.js.map +0 -1
- package/dist/tests/protocol.test.d.ts +0 -2
- package/dist/tests/protocol.test.d.ts.map +0 -1
- package/dist/tests/protocol.test.js +0 -73
- package/dist/tests/protocol.test.js.map +0 -1
- package/dist/tests/replay.test.d.ts +0 -2
- package/dist/tests/replay.test.d.ts.map +0 -1
- package/dist/tests/replay.test.js +0 -222
- package/dist/tests/replay.test.js.map +0 -1
- package/dist/tests/runtime.test.d.ts +0 -7
- package/dist/tests/runtime.test.d.ts.map +0 -1
- package/dist/tests/runtime.test.js +0 -323
- package/dist/tests/runtime.test.js.map +0 -1
- package/dist/tests/verification-gate.test.d.ts +0 -2
- package/dist/tests/verification-gate.test.d.ts.map +0 -1
- package/dist/tests/verification-gate.test.js +0 -407
- package/dist/tests/verification-gate.test.js.map +0 -1
- package/skills/prompt-techniques/SKILL.md +0 -52
- package/skills/prompt-techniques/references/chain-of-thought.md +0 -207
- package/skills/prompt-techniques/references/few-shot.md +0 -174
- package/skills/prompt-techniques/references/least-to-most.md +0 -182
- package/skills/prompt-techniques/references/step-back.md +0 -160
- package/skills/prompt-techniques/references/tree-of-thought.md +0 -191
- package/skills/prompt-techniques/references/zero-shot.md +0 -97
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/** In-process policy effectiveness metrics with no runtime dependency. */
|
|
2
|
+
function empty(loopId) {
|
|
3
|
+
return {
|
|
4
|
+
loopId,
|
|
5
|
+
roundAttempts: 0,
|
|
6
|
+
committedRounds: 0,
|
|
7
|
+
rejectedAttempts: 0,
|
|
8
|
+
terminatedRounds: 0,
|
|
9
|
+
stoppedRounds: 0,
|
|
10
|
+
replayedTransactions: 0,
|
|
11
|
+
successfulRounds: 0,
|
|
12
|
+
contradictedRounds: 0,
|
|
13
|
+
verificationFlags: {},
|
|
14
|
+
enforcementReasons: {},
|
|
15
|
+
evidenceOutcomesByProvider: {},
|
|
16
|
+
evidenceCaptures: 0,
|
|
17
|
+
evidenceAvailable: 0,
|
|
18
|
+
evidenceUnavailable: 0,
|
|
19
|
+
evidenceFailures: 0,
|
|
20
|
+
evidenceTimeouts: 0,
|
|
21
|
+
evidenceLatencyMs: 0,
|
|
22
|
+
levels: {},
|
|
23
|
+
strategyEffectiveness: {},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function increment(target, key) {
|
|
27
|
+
target[key] = (target[key] ?? 0) + 1;
|
|
28
|
+
}
|
|
29
|
+
export class PolicyMetricsCollector {
|
|
30
|
+
loops = new Map();
|
|
31
|
+
aggregate = empty();
|
|
32
|
+
targets(loopId) {
|
|
33
|
+
if (!loopId)
|
|
34
|
+
return [this.aggregate];
|
|
35
|
+
let metric = this.loops.get(loopId);
|
|
36
|
+
if (!metric) {
|
|
37
|
+
metric = empty(loopId);
|
|
38
|
+
this.loops.set(loopId, metric);
|
|
39
|
+
}
|
|
40
|
+
return [this.aggregate, metric];
|
|
41
|
+
}
|
|
42
|
+
recordRound(loopId, result, replayed = false) {
|
|
43
|
+
for (const metric of this.targets(loopId)) {
|
|
44
|
+
if (replayed) {
|
|
45
|
+
metric.replayedTransactions++;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
metric.roundAttempts++;
|
|
49
|
+
if (result.action === "reject")
|
|
50
|
+
metric.rejectedAttempts++;
|
|
51
|
+
else
|
|
52
|
+
metric.committedRounds++;
|
|
53
|
+
if (result.action === "terminate")
|
|
54
|
+
metric.terminatedRounds++;
|
|
55
|
+
if (result.action === "stop")
|
|
56
|
+
metric.stoppedRounds++;
|
|
57
|
+
if (result.roundSuccess)
|
|
58
|
+
metric.successfulRounds++;
|
|
59
|
+
if (result.gateContradicted)
|
|
60
|
+
metric.contradictedRounds++;
|
|
61
|
+
for (const flag of result.verificationFlags) {
|
|
62
|
+
increment(metric.verificationFlags, flag.check);
|
|
63
|
+
}
|
|
64
|
+
if (result.enforcementReason) {
|
|
65
|
+
increment(metric.enforcementReasons, result.enforcementReason);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
recordEvidence(provider, outcome, latencyMs, loopId) {
|
|
70
|
+
for (const metric of this.targets(loopId)) {
|
|
71
|
+
metric.evidenceCaptures++;
|
|
72
|
+
metric.evidenceLatencyMs += Math.max(0, latencyMs);
|
|
73
|
+
if (outcome === "available")
|
|
74
|
+
metric.evidenceAvailable++;
|
|
75
|
+
if (outcome === "unavailable")
|
|
76
|
+
metric.evidenceUnavailable++;
|
|
77
|
+
if (outcome === "failure")
|
|
78
|
+
metric.evidenceFailures++;
|
|
79
|
+
if (outcome === "timeout")
|
|
80
|
+
metric.evidenceTimeouts++;
|
|
81
|
+
increment(metric.evidenceOutcomesByProvider, `${provider}:${outcome}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
recordStrategy(loopId, level) {
|
|
85
|
+
for (const metric of this.targets(loopId)) {
|
|
86
|
+
if (level)
|
|
87
|
+
increment(metric.levels, level);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
recordStrategyOutcome(loopId, level, result, replayed = false) {
|
|
91
|
+
if (replayed)
|
|
92
|
+
return;
|
|
93
|
+
const key = level ?? "unknown";
|
|
94
|
+
for (const metric of this.targets(loopId)) {
|
|
95
|
+
const current = metric.strategyEffectiveness[key] ?? {
|
|
96
|
+
attempts: 0,
|
|
97
|
+
successes: 0,
|
|
98
|
+
rejections: 0,
|
|
99
|
+
};
|
|
100
|
+
current.attempts++;
|
|
101
|
+
if (result.roundSuccess && result.action !== "reject")
|
|
102
|
+
current.successes++;
|
|
103
|
+
if (result.action === "reject")
|
|
104
|
+
current.rejections++;
|
|
105
|
+
metric.strategyEffectiveness[key] = current;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
snapshot(loopId) {
|
|
109
|
+
const source = loopId ? this.loops.get(loopId) ?? empty(loopId) : this.aggregate;
|
|
110
|
+
const attempts = source.roundAttempts;
|
|
111
|
+
const evidence = source.evidenceCaptures;
|
|
112
|
+
const strategyEffectiveness = {};
|
|
113
|
+
for (const [key, value] of Object.entries(source.strategyEffectiveness)) {
|
|
114
|
+
strategyEffectiveness[key] = {
|
|
115
|
+
...value,
|
|
116
|
+
successRate: value.attempts === 0 ? 0 : value.successes / value.attempts,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
...source,
|
|
121
|
+
verificationFlags: { ...source.verificationFlags },
|
|
122
|
+
enforcementReasons: { ...source.enforcementReasons },
|
|
123
|
+
evidenceOutcomesByProvider: { ...source.evidenceOutcomesByProvider },
|
|
124
|
+
levels: { ...source.levels },
|
|
125
|
+
strategyEffectiveness,
|
|
126
|
+
acceptanceRate: attempts === 0 ? 0 : source.committedRounds / attempts,
|
|
127
|
+
evidenceAvailabilityRate: evidence === 0 ? 0 : source.evidenceAvailable / evidence,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
reset(loopId) {
|
|
131
|
+
if (loopId) {
|
|
132
|
+
this.loops.delete(loopId);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
this.loops.clear();
|
|
136
|
+
this.aggregate = empty();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
export const policyMetrics = new PolicyMetricsCollector();
|
|
140
|
+
export function getPolicyMetrics(loopId) {
|
|
141
|
+
return policyMetrics.snapshot(loopId);
|
|
142
|
+
}
|
|
143
|
+
export function resetPolicyMetrics(loopId) {
|
|
144
|
+
policyMetrics.reset(loopId);
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=policy-metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-metrics.js","sourceRoot":"","sources":["../src/policy-metrics.ts"],"names":[],"mappings":"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"}
|
package/dist/policy.d.ts
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
* All tunable parameters live here instead of as module-level constants.
|
|
4
|
-
*/
|
|
1
|
+
/** Externalized LoopForge runtime policy. */
|
|
5
2
|
export interface ConstraintsPolicy {
|
|
6
3
|
retire_window: number;
|
|
7
|
-
max_active: number;
|
|
8
4
|
}
|
|
9
5
|
export interface SummaryPolicy {
|
|
10
6
|
window: number;
|
|
11
7
|
health_check_interval: number;
|
|
12
8
|
}
|
|
13
|
-
export interface TechniquePolicy {
|
|
14
|
-
/** Number of consecutive failures before escalating to Tier 2 techniques. */
|
|
15
|
-
tier2_escalation_failures: number;
|
|
16
|
-
}
|
|
17
9
|
export interface EnginePolicy {
|
|
18
10
|
feedback_flush_interval: number;
|
|
19
11
|
max_circuit_breaker: number;
|
|
@@ -24,101 +16,92 @@ export interface RuntimePolicy {
|
|
|
24
16
|
heartbeat_interval_ms: number;
|
|
25
17
|
stall_grace_ms: number;
|
|
26
18
|
max_consecutive_errors: number;
|
|
19
|
+
pause_double_tap_ms: number;
|
|
20
|
+
}
|
|
21
|
+
/** Levels control state density only; reasoning strategy belongs to the Agent. */
|
|
22
|
+
export interface PromptPolicy {
|
|
23
|
+
injection_mode: "adaptive" | "full" | "pointer";
|
|
24
|
+
full_refresh_interval: number;
|
|
25
|
+
l0_max_chars: number;
|
|
26
|
+
l1_max_chars: number;
|
|
27
|
+
l2_max_chars: number;
|
|
28
|
+
base_prompt_version: string;
|
|
27
29
|
}
|
|
28
30
|
export interface BackendPolicy {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
/** Root for typed per-loop documents. */
|
|
32
|
+
root_dir: string;
|
|
31
33
|
}
|
|
32
34
|
export interface EvolutionPolicy {
|
|
33
|
-
/** P0: Max new constraints the agent can discover per round. */
|
|
34
35
|
max_discovered_constraints_per_round: number;
|
|
35
|
-
/** P0: Hard upper bound on total active constraints. */
|
|
36
36
|
max_active_constraints: number;
|
|
37
|
-
/** P1: Max versions of the loop objective to retain in history. */
|
|
38
37
|
max_objective_versions: number;
|
|
39
|
-
/** P4: Minimum progress delta to not be considered stalled. */
|
|
40
38
|
progress_stall_threshold: number;
|
|
41
|
-
/** P4: Consecutive rounds below stall threshold before warning. */
|
|
42
39
|
progress_stall_rounds: number;
|
|
43
|
-
/** P4: Max allowed difference between objective and subjective progress. */
|
|
44
40
|
progress_mismatch_threshold: number;
|
|
45
41
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
export interface MemoryInjectionTier {
|
|
50
|
-
/** Upper bound of maxRounds for this tier (inclusive). */
|
|
51
|
-
max_rounds: number;
|
|
52
|
-
/** Which phases are allowed in this tier: [1], [1,3], or [1,2,3]. */
|
|
53
|
-
allowed_phases: number[];
|
|
42
|
+
export interface CheckpointPolicy {
|
|
43
|
+
max_carried_constraints: number;
|
|
44
|
+
outcome_max_chars: number;
|
|
54
45
|
}
|
|
55
|
-
|
|
56
|
-
|
|
46
|
+
/** Human-readable derived state view. JSON LoopStore documents remain truth. */
|
|
47
|
+
export interface StateFilePolicy {
|
|
57
48
|
enabled: boolean;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
phase_thresholds: {
|
|
62
|
-
phase1: {
|
|
63
|
-
trigger: "round_1";
|
|
64
|
-
};
|
|
65
|
-
phase2: {
|
|
66
|
-
trigger: "progress";
|
|
67
|
-
threshold: number;
|
|
68
|
-
};
|
|
69
|
-
phase3: {
|
|
70
|
-
trigger: "progress";
|
|
71
|
-
threshold: number;
|
|
72
|
-
};
|
|
73
|
-
};
|
|
74
|
-
/** Round-based tiered injection strategy. Each tier defines which phases
|
|
75
|
-
* are allowed based on maxRounds. The first matching tier wins.
|
|
76
|
-
* Tiers should be ordered by max_rounds ascending. */
|
|
77
|
-
round_tiers: MemoryInjectionTier[];
|
|
78
|
-
/** Jaccard similarity threshold above which a new context is considered
|
|
79
|
-
* duplicate and skipped. */
|
|
80
|
-
dedup_threshold: number;
|
|
81
|
-
/** Maximum characters of memory context to inject (truncated if longer). */
|
|
82
|
-
max_context_length: number;
|
|
83
|
-
/** Section header for the injected context block in the L2 prompt. */
|
|
84
|
-
section_title: string;
|
|
49
|
+
directory: string;
|
|
50
|
+
max_checkpoints: number;
|
|
51
|
+
max_summary_rounds: number;
|
|
85
52
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
export interface
|
|
92
|
-
|
|
53
|
+
export interface EvidencePolicy {
|
|
54
|
+
providers: string[];
|
|
55
|
+
timeout_ms: number;
|
|
56
|
+
commands: CommandEvidencePolicy[];
|
|
57
|
+
}
|
|
58
|
+
export interface CommandEvidencePolicy {
|
|
59
|
+
name: string;
|
|
93
60
|
enabled: boolean;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
61
|
+
executable: string;
|
|
62
|
+
args: string[];
|
|
63
|
+
cwd?: string;
|
|
64
|
+
phase: "after" | "both";
|
|
65
|
+
required: boolean;
|
|
66
|
+
timeout_ms: number;
|
|
67
|
+
max_output_chars: number;
|
|
68
|
+
success_exit_codes: number[];
|
|
100
69
|
}
|
|
101
|
-
export interface
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
/** Maximum character length of the outcome field in a checkpoint. */
|
|
105
|
-
outcome_max_chars: number;
|
|
70
|
+
export interface McpPolicy {
|
|
71
|
+
session_lease_ms: number;
|
|
72
|
+
session_lease_renew_interval_ms: number;
|
|
106
73
|
}
|
|
107
74
|
export interface LoopPolicy {
|
|
108
75
|
version: string;
|
|
109
76
|
constraints: ConstraintsPolicy;
|
|
110
77
|
summary: SummaryPolicy;
|
|
111
|
-
technique: TechniquePolicy;
|
|
112
78
|
engine: EnginePolicy;
|
|
113
79
|
runtime: RuntimePolicy;
|
|
80
|
+
prompt: PromptPolicy;
|
|
114
81
|
backend: BackendPolicy;
|
|
115
82
|
evolution: EvolutionPolicy;
|
|
116
|
-
memory_injection: MemoryInjectionPolicy;
|
|
117
|
-
memory_writeback: MemoryWritebackPolicy;
|
|
118
83
|
checkpoint: CheckpointPolicy;
|
|
84
|
+
state_file: StateFilePolicy;
|
|
85
|
+
evidence: EvidencePolicy;
|
|
86
|
+
mcp: McpPolicy;
|
|
119
87
|
}
|
|
120
88
|
export declare const DEFAULT_POLICY: LoopPolicy;
|
|
89
|
+
/** Write a full default `loop_policy.json` to the target directory.
|
|
90
|
+
*
|
|
91
|
+
* The written file contains every configurable key and its default value
|
|
92
|
+
* so users can discover and tune the system without reading source code.
|
|
93
|
+
* Skip creation when the file already exists unless `force` is true.
|
|
94
|
+
*
|
|
95
|
+
* @returns The resolved file path and whether it was freshly created.
|
|
96
|
+
*/
|
|
97
|
+
export declare function writeDefaultPolicy(targetDir: string, force?: boolean): {
|
|
98
|
+
path: string;
|
|
99
|
+
created: boolean;
|
|
100
|
+
};
|
|
121
101
|
export declare function loadPolicy(path?: string): LoopPolicy;
|
|
122
102
|
export declare function getPolicy(path?: string): LoopPolicy;
|
|
123
103
|
export declare function resetPolicy(): void;
|
|
104
|
+
export declare function validateLoopId(loopId: string): void;
|
|
105
|
+
export declare function resolveStateDirectory(workspaceRoot: string, configuredDirectory: string): string;
|
|
106
|
+
export declare function writeStateFile(loopId: string, content: string | undefined): void;
|
|
124
107
|
//# sourceMappingURL=policy.d.ts.map
|
package/dist/policy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}
|
package/dist/policy.js
CHANGED
|
@@ -1,53 +1,29 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import { readFileSync } from "node:fs";
|
|
6
|
-
import { resolve } from "node:path";
|
|
7
|
-
/** Resolve which injection phases are allowed for a given maxRounds.
|
|
8
|
-
* Uses the tiered strategy: finds the first tier where maxRounds ≤ tier.max_rounds,
|
|
9
|
-
* and returns its allowed_phases. If maxRounds exceeds all tiers, returns the
|
|
10
|
-
* last tier's phases. */
|
|
11
|
-
export function resolveAllowedPhases(maxRounds, tiers) {
|
|
12
|
-
if (tiers.length === 0)
|
|
13
|
-
return [1]; // safety fallback
|
|
14
|
-
for (const tier of tiers) {
|
|
15
|
-
if (maxRounds <= tier.max_rounds)
|
|
16
|
-
return tier.allowed_phases;
|
|
17
|
-
}
|
|
18
|
-
return tiers[tiers.length - 1].allowed_phases;
|
|
19
|
-
}
|
|
20
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
21
|
-
// Default policy
|
|
22
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
1
|
+
/** Externalized LoopForge runtime policy. */
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync, } from "node:fs";
|
|
4
|
+
import { isAbsolute, relative, resolve, sep } from "node:path";
|
|
23
5
|
export const DEFAULT_POLICY = {
|
|
24
|
-
version: "
|
|
25
|
-
constraints: {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
},
|
|
29
|
-
summary: {
|
|
30
|
-
window: 5,
|
|
31
|
-
health_check_interval: 1,
|
|
32
|
-
},
|
|
33
|
-
technique: {
|
|
34
|
-
tier2_escalation_failures: 3,
|
|
35
|
-
},
|
|
36
|
-
engine: {
|
|
37
|
-
feedback_flush_interval: 5,
|
|
38
|
-
max_circuit_breaker: 3,
|
|
39
|
-
},
|
|
6
|
+
version: "2",
|
|
7
|
+
constraints: { retire_window: 3 },
|
|
8
|
+
summary: { window: 5, health_check_interval: 1 },
|
|
9
|
+
engine: { feedback_flush_interval: 5, max_circuit_breaker: 3 },
|
|
40
10
|
runtime: {
|
|
41
11
|
max_rounds: 20,
|
|
42
12
|
round_timeout_ms: 600_000,
|
|
43
13
|
heartbeat_interval_ms: 30_000,
|
|
44
14
|
stall_grace_ms: 300_000,
|
|
45
15
|
max_consecutive_errors: 3,
|
|
16
|
+
pause_double_tap_ms: 3000,
|
|
46
17
|
},
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
18
|
+
prompt: {
|
|
19
|
+
injection_mode: "adaptive",
|
|
20
|
+
full_refresh_interval: 5,
|
|
21
|
+
l0_max_chars: 3000,
|
|
22
|
+
l1_max_chars: 7000,
|
|
23
|
+
l2_max_chars: 18000,
|
|
24
|
+
base_prompt_version: "2.0.0",
|
|
50
25
|
},
|
|
26
|
+
backend: { root_dir: ".loopforge" },
|
|
51
27
|
evolution: {
|
|
52
28
|
max_discovered_constraints_per_round: 5,
|
|
53
29
|
max_active_constraints: 15,
|
|
@@ -56,84 +32,137 @@ export const DEFAULT_POLICY = {
|
|
|
56
32
|
progress_stall_rounds: 2,
|
|
57
33
|
progress_mismatch_threshold: 0.3,
|
|
58
34
|
},
|
|
59
|
-
|
|
35
|
+
checkpoint: { max_carried_constraints: 10, outcome_max_chars: 200 },
|
|
36
|
+
state_file: {
|
|
60
37
|
enabled: true,
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
phase2: { trigger: "progress", threshold: 0.40 },
|
|
65
|
-
phase3: { trigger: "progress", threshold: 0.70 },
|
|
66
|
-
},
|
|
67
|
-
round_tiers: [
|
|
68
|
-
{ max_rounds: 10, allowed_phases: [1] },
|
|
69
|
-
{ max_rounds: 20, allowed_phases: [1, 3] },
|
|
70
|
-
{ max_rounds: 30, allowed_phases: [1, 2, 3] },
|
|
71
|
-
],
|
|
72
|
-
dedup_threshold: 0.6,
|
|
73
|
-
max_context_length: 2000,
|
|
74
|
-
section_title: "### Background Context (Long-Term Memory)",
|
|
38
|
+
directory: ".loopforge/state",
|
|
39
|
+
max_checkpoints: 5,
|
|
40
|
+
max_summary_rounds: 5,
|
|
75
41
|
},
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
write_on_outcomes: ["completed", "circuit_breaker", "max_rounds"],
|
|
81
|
-
},
|
|
82
|
-
checkpoint: {
|
|
83
|
-
max_carried_constraints: 10,
|
|
84
|
-
outcome_max_chars: 200,
|
|
42
|
+
evidence: { providers: ["git"], timeout_ms: 120_000, commands: [] },
|
|
43
|
+
mcp: {
|
|
44
|
+
session_lease_ms: 30_000,
|
|
45
|
+
session_lease_renew_interval_ms: 10_000,
|
|
85
46
|
},
|
|
86
47
|
};
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
48
|
+
/** Write a full default `loop_policy.json` to the target directory.
|
|
49
|
+
*
|
|
50
|
+
* The written file contains every configurable key and its default value
|
|
51
|
+
* so users can discover and tune the system without reading source code.
|
|
52
|
+
* Skip creation when the file already exists unless `force` is true.
|
|
53
|
+
*
|
|
54
|
+
* @returns The resolved file path and whether it was freshly created.
|
|
55
|
+
*/
|
|
56
|
+
export function writeDefaultPolicy(targetDir, force = false) {
|
|
57
|
+
const target = resolve(targetDir, "loop_policy.json");
|
|
58
|
+
if (existsSync(target) && !force) {
|
|
59
|
+
return { path: target, created: false };
|
|
60
|
+
}
|
|
61
|
+
writeFileSync(target, JSON.stringify(DEFAULT_POLICY, null, 2) + "\n", "utf8");
|
|
62
|
+
return { path: target, created: true };
|
|
63
|
+
}
|
|
90
64
|
function deepMerge(defaults, overrides) {
|
|
91
65
|
const result = { ...defaults };
|
|
92
66
|
for (const key of Object.keys(overrides)) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
typeof
|
|
97
|
-
!Array.isArray(
|
|
98
|
-
|
|
99
|
-
result[key] = deepMerge(result[key], overrides[key]);
|
|
67
|
+
const current = result[key];
|
|
68
|
+
const incoming = overrides[key];
|
|
69
|
+
if (key in result && current !== null && incoming !== null &&
|
|
70
|
+
typeof current === "object" && !Array.isArray(current) &&
|
|
71
|
+
typeof incoming === "object" && !Array.isArray(incoming)) {
|
|
72
|
+
result[key] = deepMerge(current, incoming);
|
|
100
73
|
}
|
|
101
|
-
else {
|
|
102
|
-
|
|
74
|
+
else if (key in result) {
|
|
75
|
+
// Unknown legacy keys are deliberately ignored at the 2.0 boundary.
|
|
76
|
+
result[key] = incoming;
|
|
103
77
|
}
|
|
104
78
|
}
|
|
105
79
|
return result;
|
|
106
80
|
}
|
|
107
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
108
|
-
// Loader
|
|
109
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
110
81
|
export function loadPolicy(path) {
|
|
111
82
|
const candidates = [path, "loop_policy.json"].filter(Boolean);
|
|
112
83
|
for (const candidate of candidates) {
|
|
113
84
|
try {
|
|
114
|
-
const
|
|
115
|
-
const raw = JSON.parse(readFileSync(resolved, "utf-8"));
|
|
85
|
+
const raw = JSON.parse(readFileSync(resolve(candidate), "utf8"));
|
|
116
86
|
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
117
87
|
return deepMerge(DEFAULT_POLICY, raw);
|
|
118
88
|
}
|
|
119
89
|
}
|
|
120
90
|
catch {
|
|
121
|
-
//
|
|
91
|
+
// Try the next candidate.
|
|
122
92
|
}
|
|
123
93
|
}
|
|
124
|
-
return
|
|
94
|
+
return structuredClone(DEFAULT_POLICY);
|
|
125
95
|
}
|
|
126
|
-
|
|
127
|
-
// Module-level singleton — loaded once per session
|
|
128
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
129
|
-
let _policy = null;
|
|
96
|
+
let policy = null;
|
|
130
97
|
export function getPolicy(path) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
return _policy;
|
|
98
|
+
policy ??= loadPolicy(path);
|
|
99
|
+
return policy;
|
|
135
100
|
}
|
|
136
101
|
export function resetPolicy() {
|
|
137
|
-
|
|
102
|
+
policy = null;
|
|
103
|
+
}
|
|
104
|
+
const LOOP_ID_RE = /^[a-zA-Z0-9][-a-zA-Z0-9_:.]{0,127}$/;
|
|
105
|
+
export function validateLoopId(loopId) {
|
|
106
|
+
if (typeof loopId !== "string" || !loopId) {
|
|
107
|
+
throw new Error("Invalid loopId: must be a non-empty string");
|
|
108
|
+
}
|
|
109
|
+
if (loopId.includes(".."))
|
|
110
|
+
throw new Error('Invalid loopId: ".." is not allowed');
|
|
111
|
+
if (loopId.includes("/") || loopId.includes("\\")) {
|
|
112
|
+
throw new Error("Invalid loopId: path separators are not allowed");
|
|
113
|
+
}
|
|
114
|
+
if (!LOOP_ID_RE.test(loopId)) {
|
|
115
|
+
throw new Error("Invalid loopId: use at most 128 alphanumeric, hyphen, underscore, colon, or dot characters");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
export function resolveStateDirectory(workspaceRoot, configuredDirectory) {
|
|
119
|
+
const lexicalRoot = resolve(workspaceRoot);
|
|
120
|
+
const lexicalTarget = resolve(lexicalRoot, configuredDirectory);
|
|
121
|
+
const lexicalRelative = relative(lexicalRoot, lexicalTarget);
|
|
122
|
+
if (lexicalRelative === ".." || lexicalRelative.startsWith(`..${sep}`) ||
|
|
123
|
+
isAbsolute(lexicalRelative)) {
|
|
124
|
+
throw new Error("State file directory must stay within the workspace");
|
|
125
|
+
}
|
|
126
|
+
const realRoot = realpathSync(lexicalRoot);
|
|
127
|
+
let ancestor = lexicalTarget;
|
|
128
|
+
while (!existsSync(ancestor)) {
|
|
129
|
+
const parent = resolve(ancestor, "..");
|
|
130
|
+
if (parent === ancestor)
|
|
131
|
+
break;
|
|
132
|
+
ancestor = parent;
|
|
133
|
+
}
|
|
134
|
+
const projected = resolve(realpathSync(ancestor), relative(ancestor, lexicalTarget));
|
|
135
|
+
const realRelative = relative(realRoot, projected);
|
|
136
|
+
if (realRelative === ".." || realRelative.startsWith(`..${sep}`) ||
|
|
137
|
+
isAbsolute(realRelative)) {
|
|
138
|
+
throw new Error("State file directory resolves outside the workspace");
|
|
139
|
+
}
|
|
140
|
+
return lexicalTarget;
|
|
141
|
+
}
|
|
142
|
+
export function writeStateFile(loopId, content) {
|
|
143
|
+
if (!content)
|
|
144
|
+
return;
|
|
145
|
+
validateLoopId(loopId);
|
|
146
|
+
const config = getPolicy().state_file;
|
|
147
|
+
if (!config.enabled)
|
|
148
|
+
return;
|
|
149
|
+
const directory = resolveStateDirectory(process.cwd(), config.directory);
|
|
150
|
+
mkdirSync(directory, { recursive: true });
|
|
151
|
+
const verifiedDirectory = resolveStateDirectory(process.cwd(), config.directory);
|
|
152
|
+
const target = resolve(verifiedDirectory, `${loopId}-state.md`);
|
|
153
|
+
if (existsSync(target) && lstatSync(target).isSymbolicLink()) {
|
|
154
|
+
throw new Error("State file target must not be a symbolic link");
|
|
155
|
+
}
|
|
156
|
+
const temporary = resolve(verifiedDirectory, `.${loopId}-state.${process.pid}.${randomUUID()}.tmp`);
|
|
157
|
+
try {
|
|
158
|
+
writeFileSync(temporary, content, "utf8");
|
|
159
|
+
renameSync(temporary, target);
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
try {
|
|
163
|
+
rmSync(temporary, { force: true });
|
|
164
|
+
}
|
|
165
|
+
catch { /* best effort */ }
|
|
166
|
+
}
|
|
138
167
|
}
|
|
139
168
|
//# sourceMappingURL=policy.js.map
|
package/dist/policy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAE7C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,UAAU,EACV,SAAS,EACT,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,MAAM,EACN,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAqG/D,MAAM,CAAC,MAAM,cAAc,GAAe;IACxC,OAAO,EAAE,GAAG;IACZ,WAAW,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE;IACjC,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,qBAAqB,EAAE,CAAC,EAAE;IAChD,MAAM,EAAE,EAAE,uBAAuB,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE;IAC9D,OAAO,EAAE;QACP,UAAU,EAAE,EAAE;QACd,gBAAgB,EAAE,OAAO;QACzB,qBAAqB,EAAE,MAAM;QAC7B,cAAc,EAAE,OAAO;QACvB,sBAAsB,EAAE,CAAC;QACzB,mBAAmB,EAAE,IAAI;KAC1B;IACD,MAAM,EAAE;QACN,cAAc,EAAE,UAAU;QAC1B,qBAAqB,EAAE,CAAC;QACxB,YAAY,EAAE,IAAI;QAClB,YAAY,EAAE,IAAI;QAClB,YAAY,EAAE,KAAK;QACnB,mBAAmB,EAAE,OAAO;KAC7B;IACD,OAAO,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE;IACnC,SAAS,EAAE;QACT,oCAAoC,EAAE,CAAC;QACvC,sBAAsB,EAAE,EAAE;QAC1B,sBAAsB,EAAE,EAAE;QAC1B,wBAAwB,EAAE,IAAI;QAC9B,qBAAqB,EAAE,CAAC;QACxB,2BAA2B,EAAE,GAAG;KACjC;IACD,UAAU,EAAE,EAAE,uBAAuB,EAAE,EAAE,EAAE,iBAAiB,EAAE,GAAG,EAAE;IACnE,UAAU,EAAE;QACV,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,kBAAkB;QAC7B,eAAe,EAAE,CAAC;QAClB,kBAAkB,EAAE,CAAC;KACtB;IACD,QAAQ,EAAE,EAAE,SAAS,EAAE,CAAC,KAAK,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE;IACnE,GAAG,EAAE;QACH,gBAAgB,EAAE,MAAM;QACxB,+BAA+B,EAAE,MAAM;KACxC;CACF,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,SAAiB,EACjB,KAAK,GAAG,KAAK;IAEb,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;IACtD,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QACjC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC1C,CAAC;IACD,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;IAC9E,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACzC,CAAC;AAED,SAAS,SAAS,CAAI,QAAW,EAAE,SAAkC;IACnE,MAAM,MAAM,GAAG,EAAE,GAAG,QAAQ,EAA6B,CAAC;IAC1D,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;QAChC,IACE,GAAG,IAAI,MAAM,IAAI,OAAO,KAAK,IAAI,IAAI,QAAQ,KAAK,IAAI;YACtD,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;YACtD,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EACxD,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CACrB,OAAkC,EAClC,QAAmC,CACpC,CAAC;QACJ,CAAC;aAAM,IAAI,GAAG,IAAI,MAAM,EAAE,CAAC;YACzB,oEAAoE;YACpE,MAAM,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC;QACzB,CAAC;IACH,CAAC;IACD,OAAO,MAAW,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAa;IACtC,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAa,CAAC;IAC1E,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;YACjE,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC1D,OAAO,SAAS,CAAC,cAAc,EAAE,GAA8B,CAAC,CAAC;YACnE,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,0BAA0B;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,eAAe,CAAC,cAAc,CAAC,CAAC;AACzC,CAAC;AAED,IAAI,MAAM,GAAsB,IAAI,CAAC;AAErC,MAAM,UAAU,SAAS,CAAC,IAAa;IACrC,MAAM,KAAK,UAAU,CAAC,IAAI,CAAC,CAAC;IAC5B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,GAAG,qCAAqC,CAAC;AAEzD,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAClF,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,4FAA4F,CAC7F,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,aAAqB,EACrB,mBAA2B;IAE3B,MAAM,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC3C,MAAM,aAAa,GAAG,OAAO,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC;IAChE,MAAM,eAAe,GAAG,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAC7D,IACE,eAAe,KAAK,IAAI,IAAI,eAAe,CAAC,UAAU,CAAC,KAAK,GAAG,EAAE,CAAC;QAClE,UAAU,CAAC,eAAe,CAAC,EAC3B,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IAED,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,QAAQ,GAAG,aAAa,CAAC;IAC7B,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACvC,IAAI,MAAM,KAAK,QAAQ;YAAE,MAAM;QAC/B,QAAQ,GAAG,MAAM,CAAC;IACpB,CAAC;IACD,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC;IACrF,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACnD,IACE,YAAY,KAAK,IAAI,IAAI,YAAY,CAAC,UAAU,CAAC,KAAK,GAAG,EAAE,CAAC;QAC5D,UAAU,CAAC,YAAY,CAAC,EACxB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,OAA2B;IACxE,IAAI,CAAC,OAAO;QAAE,OAAO;IACrB,cAAc,CAAC,MAAM,CAAC,CAAC;IACvB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC,UAAU,CAAC;IACtC,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO;IAC5B,MAAM,SAAS,GAAG,qBAAqB,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACzE,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACjF,MAAM,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,GAAG,MAAM,WAAW,CAAC,CAAC;IAChE,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC;QAC7D,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,CAAC;IACD,MAAM,SAAS,GAAG,OAAO,CACvB,iBAAiB,EACjB,IAAI,MAAM,UAAU,OAAO,CAAC,GAAG,IAAI,UAAU,EAAE,MAAM,CACtD,CAAC;IACF,IAAI,CAAC;QACH,aAAa,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1C,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAChC,CAAC;YAAS,CAAC;QACT,IAAI,CAAC;YAAC,MAAM,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IACzE,CAAC;AACH,CAAC"}
|