@fairfox/polly 0.7.1 → 0.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/background/index.d.ts +1 -1
- package/dist/src/background/index.js +10 -3
- package/dist/src/background/index.js.map +9 -9
- package/dist/src/background/message-router.js +10 -3
- package/dist/src/background/message-router.js.map +8 -8
- package/dist/src/index.d.ts +9 -9
- package/dist/src/index.js +74 -67
- package/dist/src/index.js.map +12 -12
- package/dist/src/shared/adapters/chrome/context-menus.chrome.d.ts +1 -1
- package/dist/src/shared/adapters/chrome/tabs.chrome.d.ts +2 -2
- package/dist/src/shared/adapters/context-menus.adapter.d.ts +1 -1
- package/dist/src/shared/adapters/index.d.ts +4 -4
- package/dist/src/shared/adapters/index.js +9 -2
- package/dist/src/shared/adapters/index.js.map +6 -6
- package/dist/src/shared/adapters/tabs.adapter.d.ts +2 -2
- package/dist/src/shared/lib/context-helpers.js +10 -3
- package/dist/src/shared/lib/context-helpers.js.map +8 -8
- package/dist/src/shared/lib/message-bus.js +10 -3
- package/dist/src/shared/lib/message-bus.js.map +7 -7
- package/dist/src/shared/lib/state.js +10 -3
- package/dist/src/shared/lib/state.js.map +8 -8
- package/dist/src/shared/state/app-state.js +10 -3
- package/dist/src/shared/state/app-state.js.map +8 -8
- package/dist/tools/init/src/cli.js +17 -2
- package/dist/tools/init/src/cli.js.map +4 -4
- package/dist/tools/init/templates/pwa/package.json.template +3 -3
- package/dist/tools/teach/src/cli.js +2712 -2442
- package/dist/tools/teach/src/cli.js.map +11 -11
- package/dist/tools/teach/src/index.js +1379 -1379
- package/dist/tools/teach/src/index.js.map +10 -10
- package/dist/tools/test/src/adapters/index.d.ts +8 -8
- package/dist/tools/test/src/adapters/index.js +3 -2
- package/dist/tools/test/src/adapters/index.js.map +6 -6
- package/dist/tools/test/src/index.d.ts +3 -3
- package/dist/tools/test/src/index.js +3 -2
- package/dist/tools/test/src/index.js.map +6 -6
- package/dist/tools/verify/src/cli.js +190 -68
- package/dist/tools/verify/src/cli.js.map +8 -8
- package/dist/tools/visualize/src/cli.js +18 -3
- package/dist/tools/visualize/src/cli.js.map +4 -4
- package/package.json +27 -16
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
3
5
|
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
9
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
10
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
11
|
+
for (let key of __getOwnPropNames(mod))
|
|
12
|
+
if (!__hasOwnProp.call(to, key))
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: () => mod[key],
|
|
15
|
+
enumerable: true
|
|
16
|
+
});
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
4
19
|
var __export = (target, all) => {
|
|
5
20
|
for (var name in all)
|
|
6
21
|
__defProp(target, name, {
|
|
@@ -687,6 +702,17 @@ class TLAGenerator {
|
|
|
687
702
|
return isFirst;
|
|
688
703
|
}
|
|
689
704
|
addStateType(config, _analysis) {
|
|
705
|
+
this.defineValueTypes();
|
|
706
|
+
this.line("\\* Application state type definition");
|
|
707
|
+
this.line("State == [");
|
|
708
|
+
this.indent++;
|
|
709
|
+
const stateFields = this.collectStateFields(config, _analysis);
|
|
710
|
+
this.writeStateFields(stateFields);
|
|
711
|
+
this.indent--;
|
|
712
|
+
this.line("]");
|
|
713
|
+
this.line("");
|
|
714
|
+
}
|
|
715
|
+
defineValueTypes() {
|
|
690
716
|
this.line("\\* Generic value type for sequences and maps");
|
|
691
717
|
this.line("\\* Bounded to allow model checking");
|
|
692
718
|
this.line('Value == {"v1", "v2", "v3"}');
|
|
@@ -695,9 +721,8 @@ class TLAGenerator {
|
|
|
695
721
|
this.line("\\* Bounded to allow model checking");
|
|
696
722
|
this.line('Keys == {"k1", "k2", "k3"}');
|
|
697
723
|
this.line("");
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
this.indent++;
|
|
724
|
+
}
|
|
725
|
+
collectStateFields(config, _analysis) {
|
|
701
726
|
const stateFields = [];
|
|
702
727
|
for (const [fieldPath, fieldConfig] of Object.entries(config.state)) {
|
|
703
728
|
if (typeof fieldConfig !== "object" || fieldConfig === null)
|
|
@@ -707,24 +732,26 @@ class TLAGenerator {
|
|
|
707
732
|
stateFields.push(`${fieldName}: ${tlaType}`);
|
|
708
733
|
}
|
|
709
734
|
for (const fieldAnalysis of _analysis.fields) {
|
|
710
|
-
if (!fieldAnalysis.path || typeof fieldAnalysis.path !== "string")
|
|
735
|
+
if (!fieldAnalysis.path || typeof fieldAnalysis.path !== "string")
|
|
711
736
|
continue;
|
|
712
|
-
}
|
|
713
737
|
const fieldName = this.sanitizeFieldName(fieldAnalysis.path);
|
|
714
|
-
if (stateFields.some((f) => f.startsWith(`${fieldName}:`)))
|
|
738
|
+
if (stateFields.some((f) => f.startsWith(`${fieldName}:`)))
|
|
715
739
|
continue;
|
|
716
|
-
}
|
|
717
740
|
const tlaType = this.inferTLATypeFromAnalysis(fieldAnalysis);
|
|
718
741
|
stateFields.push(`${fieldName}: ${tlaType}`);
|
|
719
742
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
743
|
+
return stateFields;
|
|
744
|
+
}
|
|
745
|
+
writeStateFields(fields) {
|
|
746
|
+
if (fields.length === 0) {
|
|
747
|
+
this.line("dummy: BOOLEAN \\* Placeholder for empty state");
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
for (let i = 0;i < fields.length; i++) {
|
|
751
|
+
const field = fields[i];
|
|
752
|
+
const suffix = i < fields.length - 1 ? "," : "";
|
|
723
753
|
this.line(`${field}${suffix}`);
|
|
724
754
|
}
|
|
725
|
-
this.indent--;
|
|
726
|
-
this.line("]");
|
|
727
|
-
this.line("");
|
|
728
755
|
}
|
|
729
756
|
addMessageTypes(_config, analysis) {
|
|
730
757
|
if (analysis.messageTypes.length === 0) {
|
|
@@ -765,6 +792,20 @@ class TLAGenerator {
|
|
|
765
792
|
this.line("\\* Initial application state");
|
|
766
793
|
this.line("InitialState == [");
|
|
767
794
|
this.indent++;
|
|
795
|
+
const fields = this.collectInitialStateFields(config, _analysis);
|
|
796
|
+
this.writeInitialStateFields(fields);
|
|
797
|
+
this.indent--;
|
|
798
|
+
this.line("]");
|
|
799
|
+
this.line("");
|
|
800
|
+
this.line("\\* Initial state (extends MessageRouter)");
|
|
801
|
+
this.line("UserInit ==");
|
|
802
|
+
this.indent++;
|
|
803
|
+
this.line("/\\ Init \\* MessageRouter's init");
|
|
804
|
+
this.line("/\\ contextStates = [c \\in Contexts |-> InitialState]");
|
|
805
|
+
this.indent--;
|
|
806
|
+
this.line("");
|
|
807
|
+
}
|
|
808
|
+
collectInitialStateFields(config, _analysis) {
|
|
768
809
|
const fields = [];
|
|
769
810
|
for (const [fieldPath, fieldConfig] of Object.entries(config.state)) {
|
|
770
811
|
if (typeof fieldConfig !== "object" || fieldConfig === null)
|
|
@@ -774,31 +815,26 @@ class TLAGenerator {
|
|
|
774
815
|
fields.push(`${fieldName} |-> ${initialValue}`);
|
|
775
816
|
}
|
|
776
817
|
for (const fieldAnalysis of _analysis.fields) {
|
|
777
|
-
if (!fieldAnalysis.path || typeof fieldAnalysis.path !== "string")
|
|
818
|
+
if (!fieldAnalysis.path || typeof fieldAnalysis.path !== "string")
|
|
778
819
|
continue;
|
|
779
|
-
}
|
|
780
820
|
const fieldName = this.sanitizeFieldName(fieldAnalysis.path);
|
|
781
|
-
if (fields.some((f) => f.startsWith(`${fieldName} |->`)))
|
|
821
|
+
if (fields.some((f) => f.startsWith(`${fieldName} |->`)))
|
|
782
822
|
continue;
|
|
783
|
-
}
|
|
784
823
|
const initialValue = this.getInitialValueFromAnalysis(fieldAnalysis);
|
|
785
824
|
fields.push(`${fieldName} |-> ${initialValue}`);
|
|
786
825
|
}
|
|
826
|
+
return fields;
|
|
827
|
+
}
|
|
828
|
+
writeInitialStateFields(fields) {
|
|
829
|
+
if (fields.length === 0) {
|
|
830
|
+
this.line("dummy |-> FALSE \\* Placeholder for empty state");
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
787
833
|
for (let i = 0;i < fields.length; i++) {
|
|
788
834
|
const field = fields[i];
|
|
789
835
|
const suffix = i < fields.length - 1 ? "," : "";
|
|
790
836
|
this.line(`${field}${suffix}`);
|
|
791
837
|
}
|
|
792
|
-
this.indent--;
|
|
793
|
-
this.line("]");
|
|
794
|
-
this.line("");
|
|
795
|
-
this.line("\\* Initial state (extends MessageRouter)");
|
|
796
|
-
this.line("UserInit ==");
|
|
797
|
-
this.indent++;
|
|
798
|
-
this.line("/\\ Init \\* MessageRouter's init");
|
|
799
|
-
this.line("/\\ contextStates = [c \\in Contexts |-> InitialState]");
|
|
800
|
-
this.indent--;
|
|
801
|
-
this.line("");
|
|
802
838
|
}
|
|
803
839
|
addActions(config, analysis) {
|
|
804
840
|
this.line("\\* =============================================================================");
|
|
@@ -1024,10 +1060,10 @@ class TLAGenerator {
|
|
|
1024
1060
|
const _indexMap = new Map;
|
|
1025
1061
|
result = result.replace(/(\w+(?:\.\w+)*)\[(\d+)\]|\]\[(\d+)\]/g, (_match, identPart, index1, index2) => {
|
|
1026
1062
|
if (identPart) {
|
|
1027
|
-
const newIndex2 = Number.parseInt(index1) + 1;
|
|
1063
|
+
const newIndex2 = Number.parseInt(index1, 10) + 1;
|
|
1028
1064
|
return `${identPart}[${newIndex2}]`;
|
|
1029
1065
|
}
|
|
1030
|
-
const newIndex = Number.parseInt(index2) + 1;
|
|
1066
|
+
const newIndex = Number.parseInt(index2, 10) + 1;
|
|
1031
1067
|
return `][${newIndex}]`;
|
|
1032
1068
|
});
|
|
1033
1069
|
result = result.replace(/(\w+(?:\.\w+)*)\.some\(\(?(\w+)\)?\s*=>\s*([^)]+)\)/g, (_match, arrayRef, param, condition) => {
|
|
@@ -1056,9 +1092,9 @@ class TLAGenerator {
|
|
|
1056
1092
|
return `\\E i \\in 1..Len(${strRef}) : SubSeq(${strRef}, i, i+${substring.length}-1) = "${substring}"`;
|
|
1057
1093
|
});
|
|
1058
1094
|
result = result.replace(/(\w+(?:\.\w+)*)\.slice\((-?\d+)(?:,\s*(-?\d+))?\)\.length/g, (_match, strRef, start, end) => {
|
|
1059
|
-
const startNum = Number.parseInt(start);
|
|
1095
|
+
const startNum = Number.parseInt(start, 10);
|
|
1060
1096
|
if (end !== undefined) {
|
|
1061
|
-
const endNum = Number.parseInt(end);
|
|
1097
|
+
const endNum = Number.parseInt(end, 10);
|
|
1062
1098
|
if (startNum < 0 && endNum < 0) {
|
|
1063
1099
|
return `Len(SubSeq(${strRef}, Len(${strRef}) - ${Math.abs(startNum)} + 1, Len(${strRef}) - ${Math.abs(endNum)}))`;
|
|
1064
1100
|
}
|
|
@@ -1076,9 +1112,9 @@ class TLAGenerator {
|
|
|
1076
1112
|
return `Len(SubSeq(${strRef}, ${startNum + 1}, Len(${strRef})))`;
|
|
1077
1113
|
});
|
|
1078
1114
|
result = result.replace(/(\w+(?:\.\w+)*)\.substring\((\d+)(?:,\s*(\d+))?\)\.length/g, (_match, strRef, start, end) => {
|
|
1079
|
-
const startNum = Number.parseInt(start);
|
|
1115
|
+
const startNum = Number.parseInt(start, 10);
|
|
1080
1116
|
if (end !== undefined) {
|
|
1081
|
-
const endNum = Number.parseInt(end);
|
|
1117
|
+
const endNum = Number.parseInt(end, 10);
|
|
1082
1118
|
if (startNum > endNum) {
|
|
1083
1119
|
return `Len(SubSeq(${strRef}, ${endNum + 1}, ${startNum}))`;
|
|
1084
1120
|
}
|
|
@@ -1087,15 +1123,15 @@ class TLAGenerator {
|
|
|
1087
1123
|
return `Len(SubSeq(${strRef}, ${startNum + 1}, Len(${strRef})))`;
|
|
1088
1124
|
});
|
|
1089
1125
|
result = result.replace(/(\w+(?:\.\w+)*)\.slice\((-?\d+)\)(?!,)/g, (_match, strRef, start) => {
|
|
1090
|
-
const startNum = Number.parseInt(start);
|
|
1126
|
+
const startNum = Number.parseInt(start, 10);
|
|
1091
1127
|
if (startNum < 0) {
|
|
1092
1128
|
return `SubSeq(${strRef}, Len(${strRef}) - ${Math.abs(startNum)} + 1, Len(${strRef}))`;
|
|
1093
1129
|
}
|
|
1094
1130
|
return `SubSeq(${strRef}, ${startNum + 1}, Len(${strRef}))`;
|
|
1095
1131
|
});
|
|
1096
1132
|
result = result.replace(/(\w+(?:\.\w+)*)\.slice\((-?\d+),\s*(-?\d+)\)/g, (_match, strRef, start, end) => {
|
|
1097
|
-
const startNum = Number.parseInt(start);
|
|
1098
|
-
const endNum = Number.parseInt(end);
|
|
1133
|
+
const startNum = Number.parseInt(start, 10);
|
|
1134
|
+
const endNum = Number.parseInt(end, 10);
|
|
1099
1135
|
if (startNum < 0 && endNum < 0) {
|
|
1100
1136
|
return `SubSeq(${strRef}, Len(${strRef}) - ${Math.abs(startNum)} + 1, Len(${strRef}) - ${Math.abs(endNum)})`;
|
|
1101
1137
|
}
|
|
@@ -1108,12 +1144,12 @@ class TLAGenerator {
|
|
|
1108
1144
|
return `SubSeq(${strRef}, ${startNum + 1}, ${endNum})`;
|
|
1109
1145
|
});
|
|
1110
1146
|
result = result.replace(/(\w+(?:\.\w+)*)\.substring\((\d+)\)(?!,)/g, (_match, strRef, start) => {
|
|
1111
|
-
const startNum = Number.parseInt(start);
|
|
1147
|
+
const startNum = Number.parseInt(start, 10);
|
|
1112
1148
|
return `SubSeq(${strRef}, ${startNum + 1}, Len(${strRef}))`;
|
|
1113
1149
|
});
|
|
1114
1150
|
result = result.replace(/(\w+(?:\.\w+)*)\.substring\((\d+),\s*(\d+)\)/g, (_match, strRef, start, end) => {
|
|
1115
|
-
const startNum = Number.parseInt(start);
|
|
1116
|
-
const endNum = Number.parseInt(end);
|
|
1151
|
+
const startNum = Number.parseInt(start, 10);
|
|
1152
|
+
const endNum = Number.parseInt(end, 10);
|
|
1117
1153
|
if (startNum > endNum) {
|
|
1118
1154
|
return `SubSeq(${strRef}, ${endNum + 1}, ${startNum})`;
|
|
1119
1155
|
}
|
|
@@ -1189,7 +1225,7 @@ class TLAGenerator {
|
|
|
1189
1225
|
result = result.replace(/(\w+(?:\.\w+)*)\?\.(\w+)(?!\?\.)/g, (_match, obj, prop) => `IF ${obj} # NULL THEN ${obj}.${prop} ELSE NULL`);
|
|
1190
1226
|
result = result.replace(/\(([^)]+)\)\?\.(\w+)/g, (_match, expr2, prop) => `IF (${expr2}) # NULL THEN (${expr2}).${prop} ELSE NULL`);
|
|
1191
1227
|
result = result.replace(/(\w+(?:\.\w+)*)\?\.\[(\d+)\]/g, (_match, obj, index) => {
|
|
1192
|
-
const tlaIndex = Number.parseInt(index) + 1;
|
|
1228
|
+
const tlaIndex = Number.parseInt(index, 10) + 1;
|
|
1193
1229
|
return `IF ${obj} # NULL THEN ${obj}[${tlaIndex}] ELSE NULL`;
|
|
1194
1230
|
});
|
|
1195
1231
|
result = result.replace(/(\w+(?:\.\w+)*)\?\.\[['"](\w+)['"]\]/g, (_match, obj, prop) => `IF ${obj} # NULL THEN ${obj}.${prop} ELSE NULL`);
|
|
@@ -1670,8 +1706,8 @@ class DockerRunner {
|
|
|
1670
1706
|
return {
|
|
1671
1707
|
success: true,
|
|
1672
1708
|
stats: {
|
|
1673
|
-
statesGenerated: statesMatch?.[1] ? Number.parseInt(statesMatch[1]) : 0,
|
|
1674
|
-
distinctStates: distinctMatch?.[1] ? Number.parseInt(distinctMatch[1]) : 0
|
|
1709
|
+
statesGenerated: statesMatch?.[1] ? Number.parseInt(statesMatch[1], 10) : 0,
|
|
1710
|
+
distinctStates: distinctMatch?.[1] ? Number.parseInt(distinctMatch[1], 10) : 0
|
|
1675
1711
|
},
|
|
1676
1712
|
output
|
|
1677
1713
|
};
|
|
@@ -1718,10 +1754,11 @@ class DockerRunner {
|
|
|
1718
1754
|
proc.stderr.on("data", (data) => {
|
|
1719
1755
|
stderr += data.toString();
|
|
1720
1756
|
});
|
|
1721
|
-
const
|
|
1757
|
+
const timeoutValue = options?.timeout ?? 0;
|
|
1758
|
+
const timeout = timeoutValue > 0 ? setTimeout(() => {
|
|
1722
1759
|
proc.kill();
|
|
1723
|
-
reject(new Error(`Command timed out after ${
|
|
1724
|
-
},
|
|
1760
|
+
reject(new Error(`Command timed out after ${Math.floor(timeoutValue / 1000)}s. TLC was still making progress. Consider increasing the timeout or using preset: 'thorough' for no timeout.`));
|
|
1761
|
+
}, timeoutValue) : null;
|
|
1725
1762
|
proc.on("close", (exitCode) => {
|
|
1726
1763
|
if (timeout)
|
|
1727
1764
|
clearTimeout(timeout);
|
|
@@ -2114,6 +2151,22 @@ class ConfigGenerator {
|
|
|
2114
2151
|
this.line("// • 'off' - Skip verification");
|
|
2115
2152
|
this.line("//");
|
|
2116
2153
|
this.line("onRelease: 'error',");
|
|
2154
|
+
this.line("");
|
|
2155
|
+
this.line("// Verification options (optional)");
|
|
2156
|
+
this.line("// ─────────────────────");
|
|
2157
|
+
this.line("//");
|
|
2158
|
+
this.line("// Presets provide quick configuration:");
|
|
2159
|
+
this.line("// • 'quick': 1 minute timeout, 1 worker");
|
|
2160
|
+
this.line("// • 'balanced': 5 minutes timeout, 2 workers (default)");
|
|
2161
|
+
this.line("// • 'thorough': No timeout, 4 workers");
|
|
2162
|
+
this.line("//");
|
|
2163
|
+
this.line("// Or customize with verification options:");
|
|
2164
|
+
this.line("// verification: {");
|
|
2165
|
+
this.line("// timeout: 300, // Timeout in seconds (0 = no timeout)");
|
|
2166
|
+
this.line("// workers: 2, // Number of TLC workers");
|
|
2167
|
+
this.line("// }");
|
|
2168
|
+
this.line("//");
|
|
2169
|
+
this.line("// preset: 'balanced',");
|
|
2117
2170
|
}
|
|
2118
2171
|
formatTypeName(type) {
|
|
2119
2172
|
let typeName;
|
|
@@ -2226,6 +2279,9 @@ class ConfigValidator {
|
|
|
2226
2279
|
const lineNumber = source.substring(0, position).split(`
|
|
2227
2280
|
`).length;
|
|
2228
2281
|
const line = lines[lineNumber - 1];
|
|
2282
|
+
if (line?.trim().startsWith("//")) {
|
|
2283
|
+
continue;
|
|
2284
|
+
}
|
|
2229
2285
|
const fieldMatch = line?.match(/"([^"]+)":\s*{/);
|
|
2230
2286
|
const fieldName = fieldMatch ? fieldMatch[1] : "unknown";
|
|
2231
2287
|
locations.push({
|
|
@@ -2235,21 +2291,23 @@ class ConfigValidator {
|
|
|
2235
2291
|
context: fieldName ?? "unknown"
|
|
2236
2292
|
});
|
|
2237
2293
|
}
|
|
2238
|
-
|
|
2239
|
-
type: "incomplete",
|
|
2240
|
-
severity: "error",
|
|
2241
|
-
message: `Found ${matches.length} incomplete configuration marker(s)`,
|
|
2242
|
-
suggestion: "Replace all /* CONFIGURE */ markers with actual values"
|
|
2243
|
-
});
|
|
2244
|
-
for (const loc of locations) {
|
|
2294
|
+
if (locations.length > 0) {
|
|
2245
2295
|
this.issues.push({
|
|
2246
2296
|
type: "incomplete",
|
|
2247
2297
|
severity: "error",
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
message: `Incomplete configuration at line ${loc.line}`,
|
|
2251
|
-
suggestion: `Fill in value for "${loc.context}"`
|
|
2298
|
+
message: `Found ${locations.length} incomplete configuration marker(s)`,
|
|
2299
|
+
suggestion: "Replace all /* CONFIGURE */ markers with actual values"
|
|
2252
2300
|
});
|
|
2301
|
+
for (const loc of locations) {
|
|
2302
|
+
this.issues.push({
|
|
2303
|
+
type: "incomplete",
|
|
2304
|
+
severity: "error",
|
|
2305
|
+
field: loc.context,
|
|
2306
|
+
location: { line: loc.line, column: loc.column },
|
|
2307
|
+
message: `Incomplete configuration at line ${loc.line}`,
|
|
2308
|
+
suggestion: `Fill in value for "${loc.context}"`
|
|
2309
|
+
});
|
|
2310
|
+
}
|
|
2253
2311
|
}
|
|
2254
2312
|
}
|
|
2255
2313
|
}
|
|
@@ -2257,12 +2315,23 @@ class ConfigValidator {
|
|
|
2257
2315
|
const reviewRegex = /\/\*\s*REVIEW\s*\*\//g;
|
|
2258
2316
|
const matches = [...source.matchAll(reviewRegex)];
|
|
2259
2317
|
if (matches.length > 0) {
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2318
|
+
const lines = source.split(`
|
|
2319
|
+
`);
|
|
2320
|
+
const validMatches = [...matches].filter((match) => {
|
|
2321
|
+
const position = match.index ?? 0;
|
|
2322
|
+
const lineNumber = source.substring(0, position).split(`
|
|
2323
|
+
`).length;
|
|
2324
|
+
const line = lines[lineNumber - 1];
|
|
2325
|
+
return !line?.trim().startsWith("//");
|
|
2265
2326
|
});
|
|
2327
|
+
if (validMatches.length > 0) {
|
|
2328
|
+
this.issues.push({
|
|
2329
|
+
type: "incomplete",
|
|
2330
|
+
severity: "warning",
|
|
2331
|
+
message: `Found ${validMatches.length} value(s) that should be reviewed`,
|
|
2332
|
+
suggestion: "Review auto-generated values marked with /* REVIEW */"
|
|
2333
|
+
});
|
|
2334
|
+
}
|
|
2266
2335
|
}
|
|
2267
2336
|
}
|
|
2268
2337
|
loadConfig(configPath) {
|
|
@@ -3051,7 +3120,7 @@ class HandlerExtractor {
|
|
|
3051
3120
|
const index = indexExpr ? indexExpr.getText() : "0";
|
|
3052
3121
|
const value = this.extractValue(right);
|
|
3053
3122
|
if (value !== undefined) {
|
|
3054
|
-
const tlaIndex = this.isNumericLiteral(index) ? (Number.parseInt(index) + 1).toString() : `${index} + 1`;
|
|
3123
|
+
const tlaIndex = this.isNumericLiteral(index) ? (Number.parseInt(index, 10) + 1).toString() : `${index} + 1`;
|
|
3055
3124
|
assignments.push({
|
|
3056
3125
|
field: `${field}[${tlaIndex}]`,
|
|
3057
3126
|
value
|
|
@@ -4327,10 +4396,55 @@ async function verifyCommand() {
|
|
|
4327
4396
|
console.log();
|
|
4328
4397
|
try {
|
|
4329
4398
|
await runFullVerification(configPath);
|
|
4330
|
-
} catch (
|
|
4399
|
+
} catch (error) {
|
|
4400
|
+
console.error(color(`
|
|
4401
|
+
❌ Verification error:`, COLORS.red));
|
|
4402
|
+
if (error instanceof Error) {
|
|
4403
|
+
console.error(color(error.message, COLORS.red));
|
|
4404
|
+
if (process.env.POLLY_DEBUG) {
|
|
4405
|
+
console.error(color(`
|
|
4406
|
+
Stack trace:`, COLORS.gray));
|
|
4407
|
+
console.error(error.stack);
|
|
4408
|
+
}
|
|
4409
|
+
} else {
|
|
4410
|
+
console.error(String(error));
|
|
4411
|
+
}
|
|
4412
|
+
console.error();
|
|
4331
4413
|
process.exit(1);
|
|
4332
4414
|
}
|
|
4333
4415
|
}
|
|
4416
|
+
function getTimeout(config) {
|
|
4417
|
+
if (config.verification?.timeout !== undefined) {
|
|
4418
|
+
return config.verification.timeout;
|
|
4419
|
+
}
|
|
4420
|
+
const preset = config.preset || "balanced";
|
|
4421
|
+
switch (preset) {
|
|
4422
|
+
case "quick":
|
|
4423
|
+
return 60;
|
|
4424
|
+
case "balanced":
|
|
4425
|
+
return 300;
|
|
4426
|
+
case "thorough":
|
|
4427
|
+
return 0;
|
|
4428
|
+
default:
|
|
4429
|
+
return 300;
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
function getWorkers(config) {
|
|
4433
|
+
if (config.verification?.workers !== undefined) {
|
|
4434
|
+
return config.verification.workers;
|
|
4435
|
+
}
|
|
4436
|
+
const preset = config.preset || "balanced";
|
|
4437
|
+
switch (preset) {
|
|
4438
|
+
case "quick":
|
|
4439
|
+
return 1;
|
|
4440
|
+
case "balanced":
|
|
4441
|
+
return 2;
|
|
4442
|
+
case "thorough":
|
|
4443
|
+
return 4;
|
|
4444
|
+
default:
|
|
4445
|
+
return 2;
|
|
4446
|
+
}
|
|
4447
|
+
}
|
|
4334
4448
|
async function runFullVerification(configPath) {
|
|
4335
4449
|
const config = await loadVerificationConfig(configPath);
|
|
4336
4450
|
const analysis = await runCodebaseAnalysis();
|
|
@@ -4340,19 +4454,27 @@ async function runFullVerification(configPath) {
|
|
|
4340
4454
|
console.log(color(` ${specPath}`, COLORS.gray));
|
|
4341
4455
|
console.log();
|
|
4342
4456
|
const docker = await setupDocker();
|
|
4457
|
+
const timeoutSeconds = getTimeout(config);
|
|
4458
|
+
const workers = getWorkers(config);
|
|
4343
4459
|
console.log(color("⚙️ Running TLC model checker...", COLORS.blue));
|
|
4344
|
-
|
|
4460
|
+
if (timeoutSeconds === 0) {
|
|
4461
|
+
console.log(color(" No timeout set - will run until completion", COLORS.gray));
|
|
4462
|
+
} else {
|
|
4463
|
+
const timeoutMinutes = Math.floor(timeoutSeconds / 60);
|
|
4464
|
+
const timeoutLabel = timeoutMinutes > 0 ? `${timeoutMinutes} minute${timeoutMinutes > 1 ? "s" : ""}` : `${timeoutSeconds} seconds`;
|
|
4465
|
+
console.log(color(` Timeout: ${timeoutLabel}`, COLORS.gray));
|
|
4466
|
+
}
|
|
4345
4467
|
console.log();
|
|
4346
4468
|
const result = await docker.runTLC(specPath, {
|
|
4347
|
-
workers
|
|
4348
|
-
timeout:
|
|
4469
|
+
workers,
|
|
4470
|
+
timeout: timeoutSeconds > 0 ? timeoutSeconds * 1000 : undefined
|
|
4349
4471
|
});
|
|
4350
4472
|
displayVerificationResults(result, specDir);
|
|
4351
4473
|
}
|
|
4352
4474
|
async function loadVerificationConfig(configPath) {
|
|
4353
4475
|
const resolvedPath = path4.resolve(configPath);
|
|
4354
4476
|
const configModule = await import(`file://${resolvedPath}?t=${Date.now()}`);
|
|
4355
|
-
return configModule.default;
|
|
4477
|
+
return configModule.verificationConfig || configModule.default;
|
|
4356
4478
|
}
|
|
4357
4479
|
async function runCodebaseAnalysis() {
|
|
4358
4480
|
console.log(color("\uD83D\uDCCA Analyzing codebase...", COLORS.blue));
|
|
@@ -4526,4 +4648,4 @@ main().catch((error) => {
|
|
|
4526
4648
|
process.exit(1);
|
|
4527
4649
|
});
|
|
4528
4650
|
|
|
4529
|
-
//# debugId=
|
|
4651
|
+
//# debugId=487C3279544257BF64756E2164756E21
|