@fairfox/polly 0.8.0 → 0.9.1
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/tools/teach/src/cli.js +5 -1
- package/dist/tools/teach/src/cli.js.map +3 -3
- package/dist/tools/verify/specs/verification.config.ts +4 -0
- package/dist/tools/verify/src/cli.js +298 -15
- package/dist/tools/verify/src/cli.js.map +7 -7
- package/dist/tools/verify/src/config.d.ts +25 -1
- package/dist/tools/verify/src/config.js.map +2 -2
- package/package.json +1 -1
|
@@ -39,6 +39,10 @@ export const verificationConfig = defineVerification({
|
|
|
39
39
|
//
|
|
40
40
|
// Start with 0 or 1 for faster verification.
|
|
41
41
|
maxTabs: 1,
|
|
42
|
+
|
|
43
|
+
// TEST: Message filtering (Issue #14)
|
|
44
|
+
// Only verify these specific message types
|
|
45
|
+
include: ["test_message_1", "test_message_2", "test_message_3"],
|
|
42
46
|
},
|
|
43
47
|
|
|
44
48
|
// Verification behavior
|
|
@@ -775,6 +775,13 @@ class TLAGenerator {
|
|
|
775
775
|
if (analysis.messageTypes.length === 0) {
|
|
776
776
|
return;
|
|
777
777
|
}
|
|
778
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
779
|
+
console.log("[DEBUG] [TLAGenerator] Full config keys:", Object.keys(config));
|
|
780
|
+
console.log("[DEBUG] [TLAGenerator] config.messages:", JSON.stringify(config.messages, null, 2));
|
|
781
|
+
console.log("[DEBUG] [TLAGenerator] config.messages.include:", config.messages.include);
|
|
782
|
+
console.log("[DEBUG] [TLAGenerator] config.messages.exclude:", config.messages.exclude);
|
|
783
|
+
console.log("[DEBUG] [TLAGenerator] analysis.messageTypes:", analysis.messageTypes);
|
|
784
|
+
}
|
|
778
785
|
let validMessageTypes = [];
|
|
779
786
|
const invalidMessageTypes = [];
|
|
780
787
|
for (const msgType of analysis.messageTypes) {
|
|
@@ -790,18 +797,46 @@ class TLAGenerator {
|
|
|
790
797
|
console.log(`[WARN] - "${invalid}" (not a valid TLA+ identifier)`);
|
|
791
798
|
}
|
|
792
799
|
}
|
|
800
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
801
|
+
console.log(`[DEBUG] [TLAGenerator] Valid message types before filtering (${validMessageTypes.length}):`, validMessageTypes);
|
|
802
|
+
}
|
|
793
803
|
const originalCount = validMessageTypes.length;
|
|
794
804
|
const filteredOut = [];
|
|
805
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
806
|
+
console.log("[DEBUG] [TLAGenerator] Checking filter conditions:");
|
|
807
|
+
console.log("[DEBUG] - config.messages.include exists:", !!config.messages.include);
|
|
808
|
+
console.log("[DEBUG] - config.messages.include.length:", config.messages.include?.length ?? "N/A");
|
|
809
|
+
console.log("[DEBUG] - First condition result:", !!(config.messages.include && config.messages.include.length > 0));
|
|
810
|
+
}
|
|
795
811
|
if (config.messages.include && config.messages.include.length > 0) {
|
|
812
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
813
|
+
console.log("[DEBUG] [TLAGenerator] Entering include mode filtering");
|
|
814
|
+
}
|
|
796
815
|
const included = new Set(config.messages.include);
|
|
797
816
|
const beforeFilter = validMessageTypes;
|
|
798
817
|
validMessageTypes = validMessageTypes.filter((msg) => included.has(msg));
|
|
799
818
|
filteredOut.push(...beforeFilter.filter((msg) => !included.has(msg)));
|
|
819
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
820
|
+
console.log("[DEBUG] [TLAGenerator] After include filtering:");
|
|
821
|
+
console.log("[DEBUG] - validMessageTypes:", validMessageTypes);
|
|
822
|
+
console.log("[DEBUG] - filteredOut:", filteredOut);
|
|
823
|
+
}
|
|
800
824
|
} else if (config.messages.exclude && config.messages.exclude.length > 0) {
|
|
825
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
826
|
+
console.log("[DEBUG] [TLAGenerator] Entering exclude mode filtering");
|
|
827
|
+
}
|
|
801
828
|
const excluded = new Set(config.messages.exclude);
|
|
802
829
|
const beforeFilter = validMessageTypes;
|
|
803
830
|
validMessageTypes = validMessageTypes.filter((msg) => !excluded.has(msg));
|
|
804
831
|
filteredOut.push(...beforeFilter.filter((msg) => excluded.has(msg)));
|
|
832
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
833
|
+
console.log("[DEBUG] [TLAGenerator] After exclude filtering:");
|
|
834
|
+
console.log("[DEBUG] - validMessageTypes:", validMessageTypes);
|
|
835
|
+
console.log("[DEBUG] - filteredOut:", filteredOut);
|
|
836
|
+
}
|
|
837
|
+
} else if (process.env["POLLY_DEBUG"]) {
|
|
838
|
+
console.log("[DEBUG] [TLAGenerator] No include/exclude filtering applied");
|
|
839
|
+
console.log("[DEBUG] - Reason: Neither include nor exclude conditions met");
|
|
805
840
|
}
|
|
806
841
|
if (filteredOut.length > 0) {
|
|
807
842
|
const filterMode = config.messages.include ? "include" : "exclude";
|
|
@@ -809,6 +844,8 @@ class TLAGenerator {
|
|
|
809
844
|
if (process.env["POLLY_DEBUG"]) {
|
|
810
845
|
console.log(`[INFO] Filtered out: ${filteredOut.join(", ")}`);
|
|
811
846
|
}
|
|
847
|
+
} else if (config.messages.include || config.messages.exclude) {
|
|
848
|
+
console.log("[WARN] [TLAGenerator] Message filters configured but no types were filtered");
|
|
812
849
|
}
|
|
813
850
|
if (validMessageTypes.length === 0) {
|
|
814
851
|
return;
|
|
@@ -1759,22 +1796,32 @@ import * as path3 from "node:path";
|
|
|
1759
1796
|
class DockerRunner {
|
|
1760
1797
|
async isDockerAvailable() {
|
|
1761
1798
|
try {
|
|
1762
|
-
const result = await this.runCommand("docker", ["
|
|
1799
|
+
const result = await this.runCommand("docker", ["info"], {
|
|
1800
|
+
timeout: 5000
|
|
1801
|
+
});
|
|
1763
1802
|
return result.exitCode === 0;
|
|
1764
|
-
} catch {
|
|
1803
|
+
} catch (error) {
|
|
1804
|
+
if (error instanceof Error && error.message.includes("timed out")) {
|
|
1805
|
+
throw error;
|
|
1806
|
+
}
|
|
1765
1807
|
return false;
|
|
1766
1808
|
}
|
|
1767
1809
|
}
|
|
1768
1810
|
async hasImage() {
|
|
1769
1811
|
try {
|
|
1770
|
-
const result = await this.runCommand("docker", ["images", "-q", "talex5/tla"]
|
|
1812
|
+
const result = await this.runCommand("docker", ["images", "-q", "talex5/tla"], {
|
|
1813
|
+
timeout: 1e4
|
|
1814
|
+
});
|
|
1771
1815
|
return result.stdout.trim().length > 0;
|
|
1772
|
-
} catch {
|
|
1816
|
+
} catch (error) {
|
|
1817
|
+
if (error instanceof Error && error.message.includes("timed out")) {
|
|
1818
|
+
throw error;
|
|
1819
|
+
}
|
|
1773
1820
|
return false;
|
|
1774
1821
|
}
|
|
1775
1822
|
}
|
|
1776
1823
|
async pullImage(onProgress) {
|
|
1777
|
-
await this.runCommandStreaming("docker", ["pull", "talex5/tla:latest"], onProgress);
|
|
1824
|
+
await this.runCommandStreaming("docker", ["pull", "talex5/tla:latest"], onProgress, 300000);
|
|
1778
1825
|
}
|
|
1779
1826
|
async runTLC(specPath, options) {
|
|
1780
1827
|
if (!fs3.existsSync(specPath)) {
|
|
@@ -1896,9 +1943,13 @@ class DockerRunner {
|
|
|
1896
1943
|
});
|
|
1897
1944
|
});
|
|
1898
1945
|
}
|
|
1899
|
-
runCommandStreaming(command, args, onOutput) {
|
|
1946
|
+
runCommandStreaming(command, args, onOutput, timeout) {
|
|
1900
1947
|
return new Promise((resolve2, reject) => {
|
|
1901
1948
|
const proc = spawn(command, args);
|
|
1949
|
+
const timeoutHandle = timeout && timeout > 0 ? setTimeout(() => {
|
|
1950
|
+
proc.kill();
|
|
1951
|
+
reject(new Error(`Command timed out after ${Math.floor(timeout / 1000)}s. Docker may be unresponsive.`));
|
|
1952
|
+
}, timeout) : null;
|
|
1902
1953
|
proc.stdout.on("data", (data) => {
|
|
1903
1954
|
if (onOutput) {
|
|
1904
1955
|
const lines = data.toString().split(`
|
|
@@ -1922,13 +1973,19 @@ class DockerRunner {
|
|
|
1922
1973
|
}
|
|
1923
1974
|
});
|
|
1924
1975
|
proc.on("close", (exitCode) => {
|
|
1976
|
+
if (timeoutHandle)
|
|
1977
|
+
clearTimeout(timeoutHandle);
|
|
1925
1978
|
if (exitCode === 0) {
|
|
1926
1979
|
resolve2();
|
|
1927
1980
|
} else {
|
|
1928
1981
|
reject(new Error(`Command failed with exit code ${exitCode}`));
|
|
1929
1982
|
}
|
|
1930
1983
|
});
|
|
1931
|
-
proc.on("error",
|
|
1984
|
+
proc.on("error", (error) => {
|
|
1985
|
+
if (timeoutHandle)
|
|
1986
|
+
clearTimeout(timeoutHandle);
|
|
1987
|
+
reject(error);
|
|
1988
|
+
});
|
|
1932
1989
|
});
|
|
1933
1990
|
}
|
|
1934
1991
|
}
|
|
@@ -2251,6 +2308,28 @@ class ConfigGenerator {
|
|
|
2251
2308
|
this.line("maxContexts: 3,");
|
|
2252
2309
|
break;
|
|
2253
2310
|
}
|
|
2311
|
+
this.line("");
|
|
2312
|
+
this.line("// ─────────────────────────────────────────────────────────");
|
|
2313
|
+
this.line("// Tier 1 Optimizations (no precision loss) - OPTIONAL");
|
|
2314
|
+
this.line("// ─────────────────────────────────────────────────────────");
|
|
2315
|
+
this.line("// Uncomment and configure to reduce state space:");
|
|
2316
|
+
this.line("//");
|
|
2317
|
+
this.line("// 1. Filter messages (use include OR exclude, not both):");
|
|
2318
|
+
this.line("// include: ['authenticate', 'query', 'command', 'result'],");
|
|
2319
|
+
this.line("// exclude: ['load', 'unload', 'resize', 'scroll', 'click'],");
|
|
2320
|
+
this.line("//");
|
|
2321
|
+
this.line("// 2. Symmetry reduction (group equivalent message types):");
|
|
2322
|
+
this.line("// symmetry: [");
|
|
2323
|
+
this.line("// ['query_user', 'query_post'], // All query types");
|
|
2324
|
+
this.line("// ['create', 'update', 'delete'], // CRUD operations");
|
|
2325
|
+
this.line("// ],");
|
|
2326
|
+
this.line("//");
|
|
2327
|
+
this.line("// 3. Per-message bounds (different maxInFlight per type):");
|
|
2328
|
+
this.line("// perMessageBounds: {");
|
|
2329
|
+
this.line("// 'authenticate': 1, // Sequential only");
|
|
2330
|
+
this.line("// 'query': 5, // Allow concurrency");
|
|
2331
|
+
this.line("// 'command': 2,");
|
|
2332
|
+
this.line("// },");
|
|
2254
2333
|
this.indent--;
|
|
2255
2334
|
this.line("},");
|
|
2256
2335
|
this.line("");
|
|
@@ -2288,6 +2367,31 @@ class ConfigGenerator {
|
|
|
2288
2367
|
this.line("// }");
|
|
2289
2368
|
this.line("//");
|
|
2290
2369
|
this.line("// preset: 'balanced',");
|
|
2370
|
+
this.line("");
|
|
2371
|
+
this.line("// ─────────────────────────────────────────────────────────");
|
|
2372
|
+
this.line("// Tier 2 Optimizations (controlled approximations) - ADVANCED");
|
|
2373
|
+
this.line("// ─────────────────────────────────────────────────────────");
|
|
2374
|
+
this.line("// Use with caution - these reduce precision for performance.");
|
|
2375
|
+
this.line("// Only use if verification is too slow even with Tier 1 optimizations.");
|
|
2376
|
+
this.line("//");
|
|
2377
|
+
this.line("// tier2: {");
|
|
2378
|
+
this.line("// // Temporal constraints: specify known ordering requirements");
|
|
2379
|
+
this.line("// temporalConstraints: [");
|
|
2380
|
+
this.line("// {");
|
|
2381
|
+
this.line("// before: 'LOGIN',");
|
|
2382
|
+
this.line("// after: 'LOGOUT',");
|
|
2383
|
+
this.line("// description: 'User must login before logout'");
|
|
2384
|
+
this.line("// },");
|
|
2385
|
+
this.line("// ],");
|
|
2386
|
+
this.line("//");
|
|
2387
|
+
this.line("// // Bounded exploration: limit state depth");
|
|
2388
|
+
this.line("// boundedExploration: {");
|
|
2389
|
+
this.line("// maxDepth: 20, // Stop exploring after 20 actions");
|
|
2390
|
+
this.line("// // criticalPaths: [ // Ensure these sequences are fully explored");
|
|
2391
|
+
this.line("// // ['LOGIN', 'QUERY', 'LOGOUT'],");
|
|
2392
|
+
this.line("// // ],");
|
|
2393
|
+
this.line("// },");
|
|
2394
|
+
this.line("// },");
|
|
2291
2395
|
}
|
|
2292
2396
|
formatTypeName(type) {
|
|
2293
2397
|
let typeName;
|
|
@@ -2464,6 +2568,13 @@ class ConfigValidator {
|
|
|
2464
2568
|
this.findNullPlaceholders(config.state, "state");
|
|
2465
2569
|
this.findNullPlaceholders(config.messages, "messages");
|
|
2466
2570
|
this.validateBounds(config);
|
|
2571
|
+
this.validateTier1Optimizations(config.messages);
|
|
2572
|
+
if (config.verification) {
|
|
2573
|
+
this.validateVerificationOptions(config.verification);
|
|
2574
|
+
}
|
|
2575
|
+
if (config.tier2) {
|
|
2576
|
+
this.validateTier2Optimizations(config.tier2);
|
|
2577
|
+
}
|
|
2467
2578
|
}
|
|
2468
2579
|
findNullPlaceholders(obj, path2) {
|
|
2469
2580
|
if (obj === null || obj === undefined) {
|
|
@@ -2624,6 +2735,142 @@ class ConfigValidator {
|
|
|
2624
2735
|
});
|
|
2625
2736
|
}
|
|
2626
2737
|
}
|
|
2738
|
+
validateTier1Optimizations(messages) {
|
|
2739
|
+
if (messages.include && messages.exclude) {
|
|
2740
|
+
this.issues.push({
|
|
2741
|
+
type: "invalid_value",
|
|
2742
|
+
severity: "error",
|
|
2743
|
+
field: "messages",
|
|
2744
|
+
message: "Cannot use both 'include' and 'exclude' filters",
|
|
2745
|
+
suggestion: "Use either 'include' OR 'exclude', not both"
|
|
2746
|
+
});
|
|
2747
|
+
}
|
|
2748
|
+
if (messages.symmetry) {
|
|
2749
|
+
for (let i = 0;i < messages.symmetry.length; i++) {
|
|
2750
|
+
const group = messages.symmetry[i];
|
|
2751
|
+
if (group.length < 2) {
|
|
2752
|
+
this.issues.push({
|
|
2753
|
+
type: "invalid_value",
|
|
2754
|
+
severity: "warning",
|
|
2755
|
+
field: `messages.symmetry[${i}]`,
|
|
2756
|
+
message: "Symmetry group must have at least 2 message types",
|
|
2757
|
+
suggestion: "Remove single-element symmetry groups"
|
|
2758
|
+
});
|
|
2759
|
+
}
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
if (messages.perMessageBounds) {
|
|
2763
|
+
for (const [msgType, bound] of Object.entries(messages.perMessageBounds)) {
|
|
2764
|
+
if (bound < 1) {
|
|
2765
|
+
this.issues.push({
|
|
2766
|
+
type: "invalid_value",
|
|
2767
|
+
severity: "error",
|
|
2768
|
+
field: `messages.perMessageBounds.${msgType}`,
|
|
2769
|
+
message: `Per-message bound must be at least 1`,
|
|
2770
|
+
suggestion: "Use a positive number"
|
|
2771
|
+
});
|
|
2772
|
+
}
|
|
2773
|
+
if (bound > 20) {
|
|
2774
|
+
this.issues.push({
|
|
2775
|
+
type: "unrealistic_bound",
|
|
2776
|
+
severity: "warning",
|
|
2777
|
+
field: `messages.perMessageBounds.${msgType}`,
|
|
2778
|
+
message: `Per-message bound ${bound} is outside recommended range (1-20)`,
|
|
2779
|
+
suggestion: "Consider adjusting bound to a more realistic value"
|
|
2780
|
+
});
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
validateVerificationOptions(verification) {
|
|
2786
|
+
if (verification.timeout !== undefined) {
|
|
2787
|
+
if (verification.timeout < 0) {
|
|
2788
|
+
this.issues.push({
|
|
2789
|
+
type: "invalid_value",
|
|
2790
|
+
severity: "error",
|
|
2791
|
+
field: "verification.timeout",
|
|
2792
|
+
message: "Timeout cannot be negative",
|
|
2793
|
+
suggestion: "Use 0 for no timeout, or positive number for timeout in seconds"
|
|
2794
|
+
});
|
|
2795
|
+
}
|
|
2796
|
+
if (verification.timeout > 3600) {
|
|
2797
|
+
this.issues.push({
|
|
2798
|
+
type: "unrealistic_bound",
|
|
2799
|
+
severity: "warning",
|
|
2800
|
+
field: "verification.timeout",
|
|
2801
|
+
message: "Timeout over 1 hour (3600s) is very long",
|
|
2802
|
+
suggestion: "Consider reducing timeout or using 0 for no limit"
|
|
2803
|
+
});
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2806
|
+
if (verification.workers !== undefined) {
|
|
2807
|
+
if (verification.workers < 1) {
|
|
2808
|
+
this.issues.push({
|
|
2809
|
+
type: "invalid_value",
|
|
2810
|
+
severity: "error",
|
|
2811
|
+
field: "verification.workers",
|
|
2812
|
+
message: "Workers must be at least 1",
|
|
2813
|
+
suggestion: "Use 1 or more workers"
|
|
2814
|
+
});
|
|
2815
|
+
}
|
|
2816
|
+
if (verification.workers > 16) {
|
|
2817
|
+
this.issues.push({
|
|
2818
|
+
type: "unrealistic_bound",
|
|
2819
|
+
severity: "warning",
|
|
2820
|
+
field: "verification.workers",
|
|
2821
|
+
message: "More than 16 workers may not improve performance",
|
|
2822
|
+
suggestion: "Typical range is 1-8 workers"
|
|
2823
|
+
});
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
validateTier2Optimizations(tier2) {
|
|
2828
|
+
if (tier2.temporalConstraints) {
|
|
2829
|
+
for (let i = 0;i < tier2.temporalConstraints.length; i++) {
|
|
2830
|
+
const constraint = tier2.temporalConstraints[i];
|
|
2831
|
+
if (!constraint.before || !constraint.after) {
|
|
2832
|
+
this.issues.push({
|
|
2833
|
+
type: "invalid_value",
|
|
2834
|
+
severity: "error",
|
|
2835
|
+
field: `tier2.temporalConstraints[${i}]`,
|
|
2836
|
+
message: "Temporal constraint must have 'before' and 'after' fields",
|
|
2837
|
+
suggestion: "Specify both message types for ordering constraint"
|
|
2838
|
+
});
|
|
2839
|
+
}
|
|
2840
|
+
if (constraint.before === constraint.after) {
|
|
2841
|
+
this.issues.push({
|
|
2842
|
+
type: "invalid_value",
|
|
2843
|
+
severity: "error",
|
|
2844
|
+
field: `tier2.temporalConstraints[${i}]`,
|
|
2845
|
+
message: "Temporal constraint cannot have same message type for 'before' and 'after'",
|
|
2846
|
+
suggestion: "Use different message types"
|
|
2847
|
+
});
|
|
2848
|
+
}
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
if (tier2.boundedExploration) {
|
|
2852
|
+
if (tier2.boundedExploration.maxDepth !== undefined) {
|
|
2853
|
+
if (tier2.boundedExploration.maxDepth < 1) {
|
|
2854
|
+
this.issues.push({
|
|
2855
|
+
type: "invalid_value",
|
|
2856
|
+
severity: "error",
|
|
2857
|
+
field: "tier2.boundedExploration.maxDepth",
|
|
2858
|
+
message: "maxDepth must be at least 1",
|
|
2859
|
+
suggestion: "Use positive integer for depth limit"
|
|
2860
|
+
});
|
|
2861
|
+
}
|
|
2862
|
+
if (tier2.boundedExploration.maxDepth > 100) {
|
|
2863
|
+
this.issues.push({
|
|
2864
|
+
type: "unrealistic_bound",
|
|
2865
|
+
severity: "warning",
|
|
2866
|
+
field: "tier2.boundedExploration.maxDepth",
|
|
2867
|
+
message: "maxDepth > 100 may not be useful",
|
|
2868
|
+
suggestion: "Typical range is 10-50"
|
|
2869
|
+
});
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2627
2874
|
}
|
|
2628
2875
|
function validateConfig(configPath) {
|
|
2629
2876
|
const validator = new ConfigValidator;
|
|
@@ -4656,14 +4903,50 @@ async function setupDocker() {
|
|
|
4656
4903
|
const { DockerRunner: DockerRunner2 } = await Promise.resolve().then(() => (init_docker(), exports_docker));
|
|
4657
4904
|
console.log(color("\uD83D\uDC33 Checking Docker...", COLORS.blue));
|
|
4658
4905
|
const docker = new DockerRunner2;
|
|
4659
|
-
|
|
4660
|
-
|
|
4906
|
+
try {
|
|
4907
|
+
if (!await docker.isDockerAvailable()) {
|
|
4908
|
+
console.log();
|
|
4909
|
+
console.log(color("❌ Docker is not available", COLORS.red));
|
|
4910
|
+
console.log();
|
|
4911
|
+
console.log("Please ensure Docker is installed and running:");
|
|
4912
|
+
console.log(color(" • Install Docker Desktop: https://www.docker.com/products/docker-desktop", COLORS.gray));
|
|
4913
|
+
console.log(color(" • Make sure Docker Desktop is running", COLORS.gray));
|
|
4914
|
+
console.log();
|
|
4915
|
+
throw new Error("Docker is not available");
|
|
4916
|
+
}
|
|
4917
|
+
} catch (error) {
|
|
4918
|
+
console.log();
|
|
4919
|
+
if (error instanceof Error && error.message.includes("timed out")) {
|
|
4920
|
+
console.log(color("❌ Docker is unresponsive", COLORS.red));
|
|
4921
|
+
console.log();
|
|
4922
|
+
console.log("Docker appears to be installed but is not responding.");
|
|
4923
|
+
console.log("Try restarting Docker:");
|
|
4924
|
+
console.log(color(" • Quit Docker Desktop completely", COLORS.gray));
|
|
4925
|
+
console.log(color(" • Restart Docker Desktop", COLORS.gray));
|
|
4926
|
+
console.log(color(" • Wait for Docker to fully start (check the menu bar icon)", COLORS.gray));
|
|
4927
|
+
console.log();
|
|
4928
|
+
} else if (error instanceof Error && error.message !== "Docker is not available") {
|
|
4929
|
+
console.log(color(`❌ Error checking Docker: ${error.message}`, COLORS.red));
|
|
4930
|
+
console.log();
|
|
4931
|
+
}
|
|
4932
|
+
throw error;
|
|
4661
4933
|
}
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4934
|
+
try {
|
|
4935
|
+
if (!await docker.hasImage()) {
|
|
4936
|
+
console.log(color(" Pulling TLA+ image (this may take a moment)...", COLORS.gray));
|
|
4937
|
+
await docker.pullImage((line) => {
|
|
4938
|
+
console.log(color(` ${line}`, COLORS.gray));
|
|
4939
|
+
});
|
|
4940
|
+
}
|
|
4941
|
+
} catch (error) {
|
|
4942
|
+
console.log();
|
|
4943
|
+
if (error instanceof Error && error.message.includes("timed out")) {
|
|
4944
|
+
console.log(color("❌ Docker is unresponsive while checking for TLA+ image", COLORS.red));
|
|
4945
|
+
console.log();
|
|
4946
|
+
console.log("Docker is not responding. Try restarting Docker Desktop.");
|
|
4947
|
+
console.log();
|
|
4948
|
+
}
|
|
4949
|
+
throw error;
|
|
4667
4950
|
}
|
|
4668
4951
|
console.log(color("✓ Docker ready", COLORS.green));
|
|
4669
4952
|
console.log();
|
|
@@ -4769,4 +5052,4 @@ main().catch((error) => {
|
|
|
4769
5052
|
process.exit(1);
|
|
4770
5053
|
});
|
|
4771
5054
|
|
|
4772
|
-
//# debugId=
|
|
5055
|
+
//# debugId=E4DF49968E3D4FDC64756E2164756E21
|