packet-tracer-skill 0.1.0 → 0.2.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/CHANGELOG.md +33 -0
- package/CITATION.cff +15 -0
- package/CODE_OF_CONDUCT.md +26 -0
- package/CONTRIBUTING.md +120 -0
- package/README.md +164 -543
- package/SECURITY.md +36 -0
- package/SKILL.md +46 -5
- package/bin/packet-tracer-skill.js +503 -7
- package/docs/curated-donor-registry.md +51 -0
- package/docs/discovery-keywords.md +55 -0
- package/docs/github-discussions-setup.md +34 -0
- package/docs/github-metadata.md +33 -0
- package/docs/hero-demo-plan.md +42 -0
- package/docs/publish-preview-roadmap.md +31 -0
- package/docs/release-checklist.md +60 -0
- package/docs/release-notes-0.2.0.md +25 -0
- package/docs/runtime-truth.md +49 -0
- package/docs/screenshots/.gitkeep +1 -0
- package/docs/screenshots/packet-tracer-topology-cropped.png +0 -0
- package/examples/README.md +72 -0
- package/examples/complex_campus_master_edit_v4.inventory.json +94 -0
- package/examples/gallery.md +39 -0
- package/examples/home_iot_cli_edit_v1.inventory.json +58 -0
- package/examples/index.json +127 -0
- package/examples/screenshots/complex_campus_master_edit_v4.png +0 -0
- package/examples/screenshots/home_iot_cli_edit_v1.png +0 -0
- package/examples/screenshots/service_heavy_cli_edit_v1.png +0 -0
- package/examples/screenshots/service_heavy_cli_edit_v1_dhcp.png +0 -0
- package/examples/screenshots/service_heavy_cli_edit_v1_dns.png +0 -0
- package/examples/screenshots/service_heavy_cli_edit_v1_ftp.png +0 -0
- package/examples/service_heavy_cli_edit_v1.inventory.json +51 -0
- package/package.json +41 -4
- package/references/curated-donor-registry.json +71 -0
- package/references/scenario-fixture-corpus.json +53 -0
- package/scripts/__pycache__/build_examples_index.cpython-314.pyc +0 -0
- package/scripts/__pycache__/build_sample_catalog.cpython-314.pyc +0 -0
- package/scripts/__pycache__/coverage_matrix.cpython-314.pyc +0 -0
- package/scripts/__pycache__/donor_diagnostics.cpython-314.pyc +0 -0
- package/scripts/__pycache__/generate_pkt.cpython-314.pyc +0 -0
- package/scripts/__pycache__/install_skill.cpython-314.pyc +0 -0
- package/scripts/__pycache__/intent_parser.cpython-314.pyc +0 -0
- package/scripts/__pycache__/packet_tracer_env.cpython-314.pyc +0 -0
- package/scripts/__pycache__/pkt_builder.cpython-314.pyc +0 -0
- package/scripts/__pycache__/pkt_codec.cpython-314.pyc +0 -0
- package/scripts/__pycache__/pkt_editor.cpython-314.pyc +0 -0
- package/scripts/__pycache__/pkt_transformer.cpython-314.pyc +0 -0
- package/scripts/__pycache__/remote_search.cpython-314.pyc +0 -0
- package/scripts/__pycache__/runtime_doctor.cpython-314.pyc +0 -0
- package/scripts/__pycache__/sample_catalog.cpython-314.pyc +0 -0
- package/scripts/__pycache__/sample_selector.cpython-314.pyc +0 -0
- package/scripts/__pycache__/twofish_diagnostics.cpython-314.pyc +0 -0
- package/scripts/__pycache__/twofish_runtime.cpython-314.pyc +0 -0
- package/scripts/__pycache__/workspace_repair.cpython-314.pyc +0 -0
- package/scripts/build_examples_index.py +314 -0
- package/scripts/coverage_matrix.py +783 -0
- package/scripts/donor_diagnostics.py +6 -3
- package/scripts/generate_pkt.py +2605 -98
- package/scripts/intent_parser.py +173 -18
- package/scripts/packet_tracer_env.py +127 -14
- package/scripts/pkt_editor.py +312 -12
- package/scripts/pkt_transformer.py +195 -9
- package/scripts/remote_search.py +169 -0
- package/scripts/runtime_doctor.py +286 -0
- package/scripts/sample_catalog.py +643 -38
- package/scripts/sample_selector.py +251 -5
- package/scripts/setup.ps1 +2 -1
- package/scripts/twofish_diagnostics.py +20 -23
- package/scripts/twofish_runtime.py +101 -0
- package/scripts/vendor/README.md +13 -1
- package/scripts/vendor/__pycache__/twofish.cpython-314.pyc +0 -0
- package/scripts/vendor/twofish.py +11 -9
- package/scripts/workspace_repair.py +69 -2
|
@@ -143,6 +143,7 @@ function verifyInstall(target) {
|
|
|
143
143
|
path.join("scripts", "donor_diagnostics.py"),
|
|
144
144
|
path.join("scripts", "install_skill.py"),
|
|
145
145
|
path.join("scripts", "packet_tracer_env.py"),
|
|
146
|
+
path.join("scripts", "runtime_doctor.py"),
|
|
146
147
|
path.join("scripts", "twofish_diagnostics.py"),
|
|
147
148
|
];
|
|
148
149
|
const missing = required.filter((rel) => !fs.existsSync(path.join(target, rel)));
|
|
@@ -154,11 +155,30 @@ function verifyInstall(target) {
|
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
function commandExists(command) {
|
|
158
|
+
if (path.isAbsolute(command) || command.includes(path.sep)) {
|
|
159
|
+
return fs.existsSync(command);
|
|
160
|
+
}
|
|
157
161
|
const probe = process.platform === "win32" ? "where" : "which";
|
|
158
162
|
const result = spawnSync(probe, [command], { stdio: "ignore" });
|
|
159
163
|
return result.status === 0;
|
|
160
164
|
}
|
|
161
165
|
|
|
166
|
+
function preferredPythonCommand() {
|
|
167
|
+
const candidates = [
|
|
168
|
+
process.env.PACKET_TRACER_SKILL_PYTHON,
|
|
169
|
+
process.env.PYTHON,
|
|
170
|
+
process.platform === "win32" ? path.join("C:\\", "Python314", "python.exe") : "",
|
|
171
|
+
"python",
|
|
172
|
+
"py",
|
|
173
|
+
].filter(Boolean);
|
|
174
|
+
for (const candidate of candidates) {
|
|
175
|
+
if (commandExists(candidate)) {
|
|
176
|
+
return candidate;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
|
|
162
182
|
function envPathStatus(value) {
|
|
163
183
|
if (!value) {
|
|
164
184
|
return { ok: false, message: "not set" };
|
|
@@ -170,7 +190,7 @@ function envPathStatus(value) {
|
|
|
170
190
|
}
|
|
171
191
|
|
|
172
192
|
function packetTracerVersionDiagnostics() {
|
|
173
|
-
const pythonCommand =
|
|
193
|
+
const pythonCommand = preferredPythonCommand();
|
|
174
194
|
if (!pythonCommand) {
|
|
175
195
|
return {
|
|
176
196
|
targetVersion: process.env.PACKET_TRACER_TARGET_VERSION || "9.0.0.0810",
|
|
@@ -267,12 +287,14 @@ function packetTracerVersionDiagnostics() {
|
|
|
267
287
|
}
|
|
268
288
|
|
|
269
289
|
function twofishDiagnostics() {
|
|
270
|
-
const pythonCommand =
|
|
290
|
+
const pythonCommand = preferredPythonCommand();
|
|
271
291
|
if (!pythonCommand) {
|
|
272
292
|
return {
|
|
273
293
|
pythonVersion: "",
|
|
274
294
|
pythonSupportStatus: "missing",
|
|
275
295
|
pythonSupportMessage: "python was not found in PATH",
|
|
296
|
+
expectedTwofishPatterns: [],
|
|
297
|
+
twofishSearchRoots: [],
|
|
276
298
|
resolvedTwofishPath: "",
|
|
277
299
|
twofishSource: "",
|
|
278
300
|
twofishLoadStatus: "python_missing",
|
|
@@ -291,6 +313,8 @@ function twofishDiagnostics() {
|
|
|
291
313
|
pythonVersion: "",
|
|
292
314
|
pythonSupportStatus: "unknown",
|
|
293
315
|
pythonSupportMessage: `inspection blocked in this host wrapper: ${result.error.message}`,
|
|
316
|
+
expectedTwofishPatterns: [],
|
|
317
|
+
twofishSearchRoots: [],
|
|
294
318
|
resolvedTwofishPath: envPath,
|
|
295
319
|
twofishSource: envPath ? "env" : "",
|
|
296
320
|
twofishLoadStatus: envExists ? "inspection_blocked" : "missing",
|
|
@@ -310,6 +334,8 @@ function twofishDiagnostics() {
|
|
|
310
334
|
pythonVersion: "",
|
|
311
335
|
pythonSupportStatus: "unknown",
|
|
312
336
|
pythonSupportMessage: detail,
|
|
337
|
+
expectedTwofishPatterns: [],
|
|
338
|
+
twofishSearchRoots: [],
|
|
313
339
|
resolvedTwofishPath: process.env.PKT_TWOFISH_LIBRARY || "",
|
|
314
340
|
twofishSource: process.env.PKT_TWOFISH_LIBRARY ? "env" : "",
|
|
315
341
|
twofishLoadStatus: "load_error",
|
|
@@ -324,6 +350,8 @@ function twofishDiagnostics() {
|
|
|
324
350
|
pythonVersion: parsed.python_version || "",
|
|
325
351
|
pythonSupportStatus: parsed.python_support_status || "unknown",
|
|
326
352
|
pythonSupportMessage: parsed.python_support_message || "unknown",
|
|
353
|
+
expectedTwofishPatterns: parsed.expected_twofish_patterns || [],
|
|
354
|
+
twofishSearchRoots: parsed.twofish_search_roots || [],
|
|
327
355
|
resolvedTwofishPath: parsed.resolved_twofish_path || "",
|
|
328
356
|
twofishSource: parsed.twofish_source || "",
|
|
329
357
|
twofishLoadStatus: parsed.twofish_load_status || "unknown",
|
|
@@ -335,6 +363,8 @@ function twofishDiagnostics() {
|
|
|
335
363
|
pythonVersion: "",
|
|
336
364
|
pythonSupportStatus: "unknown",
|
|
337
365
|
pythonSupportMessage: error.message,
|
|
366
|
+
expectedTwofishPatterns: [],
|
|
367
|
+
twofishSearchRoots: [],
|
|
338
368
|
resolvedTwofishPath: process.env.PKT_TWOFISH_LIBRARY || "",
|
|
339
369
|
twofishSource: process.env.PKT_TWOFISH_LIBRARY ? "env" : "",
|
|
340
370
|
twofishLoadStatus: "load_error",
|
|
@@ -344,6 +374,124 @@ function twofishDiagnostics() {
|
|
|
344
374
|
}
|
|
345
375
|
}
|
|
346
376
|
|
|
377
|
+
function runtimeDoctorDiagnostics() {
|
|
378
|
+
const pythonCommand = preferredPythonCommand();
|
|
379
|
+
if (!pythonCommand) {
|
|
380
|
+
return {
|
|
381
|
+
available: false,
|
|
382
|
+
error: "python_missing",
|
|
383
|
+
hostOs: process.platform,
|
|
384
|
+
installerSupport: { status: "supported", message: "supported" },
|
|
385
|
+
realPktRuntimeSupport: {
|
|
386
|
+
status: "windows_first",
|
|
387
|
+
message: "python was not found in PATH",
|
|
388
|
+
},
|
|
389
|
+
envExamples: [],
|
|
390
|
+
detectedLayoutType: "missing",
|
|
391
|
+
recommendedPacketTracerRoot: "",
|
|
392
|
+
recommendedPacketTracerSavesRoot: "",
|
|
393
|
+
capabilityImpact: {},
|
|
394
|
+
runtimeBlockers: [],
|
|
395
|
+
readyOperations: [],
|
|
396
|
+
blockedOperations: [],
|
|
397
|
+
doctorSummary: "Runtime is blocked: python was not found in PATH.",
|
|
398
|
+
runtimeGrade: "blocked",
|
|
399
|
+
bridgeResolution: process.env.PKT_TWOFISH_LIBRARY ? "external_env" : "missing",
|
|
400
|
+
bridgePathSource: process.env.PKT_TWOFISH_LIBRARY ? "env" : "",
|
|
401
|
+
bridgeRecommendation: process.env.PKT_TWOFISH_LIBRARY
|
|
402
|
+
? "Use or install a repo-local vendor bridge for fully self-contained runtime readiness."
|
|
403
|
+
: "Provide PKT_TWOFISH_LIBRARY or PKT_TWOFISH_SEARCH_ROOTS to resolve a local bridge.",
|
|
404
|
+
runtimeContractNotes: process.env.PKT_TWOFISH_LIBRARY
|
|
405
|
+
? "External bridge resolves decode/edit, but repo-local runtime packaging is still incomplete."
|
|
406
|
+
: "Bridge resolution is missing, so strict runtime remains blocked.",
|
|
407
|
+
pythonVersion: "",
|
|
408
|
+
pythonSupportStatus: "missing",
|
|
409
|
+
pythonSupportMessage: "python was not found in PATH",
|
|
410
|
+
expectedTwofishPatterns: [],
|
|
411
|
+
twofishSearchRoots: [],
|
|
412
|
+
packetTracerRoot: process.env.PACKET_TRACER_ROOT || "",
|
|
413
|
+
packetTracerSavesRoot: "",
|
|
414
|
+
packetTracerExe: "",
|
|
415
|
+
resolvedTwofishPath: process.env.PKT_TWOFISH_LIBRARY || "",
|
|
416
|
+
twofishSource: process.env.PKT_TWOFISH_LIBRARY ? "env" : "",
|
|
417
|
+
twofishLoadStatus: "python_missing",
|
|
418
|
+
twofishMessage: "python was not found in PATH",
|
|
419
|
+
twofishSha256: "",
|
|
420
|
+
targetVersion: process.env.PACKET_TRACER_TARGET_VERSION || "9.0.0.0810",
|
|
421
|
+
resolvedDonorPath: process.env.PACKET_TRACER_COMPAT_DONOR || "",
|
|
422
|
+
donorVersion: "",
|
|
423
|
+
donorSource: process.env.PACKET_TRACER_COMPAT_DONOR ? "env" : "",
|
|
424
|
+
donorStatus: process.env.PACKET_TRACER_COMPAT_DONOR ? "unknown" : "missing",
|
|
425
|
+
donorMessage: process.env.PACKET_TRACER_COMPAT_DONOR ? "python missing" : "not set",
|
|
426
|
+
donorBlockingReason: "python was not found in PATH",
|
|
427
|
+
donorCandidates: [],
|
|
428
|
+
blockingReason: "python was not found in PATH",
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const diagnosticsScript = path.join(REPO_ROOT, "scripts", "runtime_doctor.py");
|
|
433
|
+
const args = pythonCommand === "py" ? ["-3", diagnosticsScript] : [diagnosticsScript];
|
|
434
|
+
const result = runCaptured(pythonCommand, args);
|
|
435
|
+
if (result.error || result.status !== 0) {
|
|
436
|
+
return {
|
|
437
|
+
available: false,
|
|
438
|
+
error: result.error ? result.error.message : `exit code ${result.status}`,
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
try {
|
|
443
|
+
const parsed = JSON.parse((result.stdout || "").trim() || "{}");
|
|
444
|
+
return {
|
|
445
|
+
available: true,
|
|
446
|
+
hostOs: parsed.host_os || process.platform,
|
|
447
|
+
installerSupport: parsed.installer_support || { status: "unknown", message: "unknown" },
|
|
448
|
+
realPktRuntimeSupport: parsed.real_pkt_runtime_support || { status: "unknown", message: "unknown" },
|
|
449
|
+
envExamples: parsed.env_examples || [],
|
|
450
|
+
detectedLayoutType: parsed.detected_layout_type || "unknown",
|
|
451
|
+
recommendedPacketTracerRoot: parsed.recommended_packet_tracer_root || "",
|
|
452
|
+
recommendedPacketTracerSavesRoot: parsed.recommended_packet_tracer_saves_root || "",
|
|
453
|
+
recommendedNextSteps: parsed.recommended_next_steps || [],
|
|
454
|
+
capabilityImpact: parsed.capability_impact || {},
|
|
455
|
+
runtimeBlockers: parsed.runtime_blockers || [],
|
|
456
|
+
readyOperations: parsed.ready_operations || [],
|
|
457
|
+
blockedOperations: parsed.blocked_operations || [],
|
|
458
|
+
doctorSummary: parsed.doctor_summary || "",
|
|
459
|
+
runtimeGrade: parsed.runtime_grade || "blocked",
|
|
460
|
+
bridgeResolution: parsed.bridge_resolution || "missing",
|
|
461
|
+
bridgePathSource: parsed.bridge_path_source || "",
|
|
462
|
+
bridgeRecommendation: parsed.bridge_recommendation || "",
|
|
463
|
+
runtimeContractNotes: parsed.runtime_contract_notes || "",
|
|
464
|
+
packetTracerRoot: parsed.packet_tracer_root || process.env.PACKET_TRACER_ROOT || "",
|
|
465
|
+
packetTracerSavesRoot: parsed.packet_tracer_saves_root || "",
|
|
466
|
+
packetTracerExe: parsed.packet_tracer_exe || "",
|
|
467
|
+
pythonVersion: parsed.python_version || "",
|
|
468
|
+
pythonSupportStatus: parsed.python_support_status || "unknown",
|
|
469
|
+
pythonSupportMessage: parsed.python_support_message || "unknown",
|
|
470
|
+
expectedTwofishPatterns: parsed.expected_twofish_patterns || [],
|
|
471
|
+
twofishSearchRoots: parsed.twofish_search_roots || [],
|
|
472
|
+
resolvedTwofishPath: parsed.resolved_twofish_path || "",
|
|
473
|
+
twofishSource: parsed.twofish_source || "",
|
|
474
|
+
twofishLoadStatus: parsed.twofish_load_status || "unknown",
|
|
475
|
+
twofishMessage: parsed.twofish_message || "unknown",
|
|
476
|
+
twofishSha256: parsed.twofish_sha256 || "",
|
|
477
|
+
targetVersion: parsed.target_version || process.env.PACKET_TRACER_TARGET_VERSION || "9.0.0.0810",
|
|
478
|
+
resolvedDonorPath: parsed.resolved_donor_path || process.env.PACKET_TRACER_COMPAT_DONOR || "",
|
|
479
|
+
donorVersion: parsed.donor_version || "",
|
|
480
|
+
donorSource: parsed.donor_source || "",
|
|
481
|
+
donorStatus: parsed.donor_status || "unknown",
|
|
482
|
+
donorMessage: parsed.donor_message || "unknown",
|
|
483
|
+
donorBlockingReason: parsed.donor_blocking_reason || "",
|
|
484
|
+
donorCandidates: parsed.donor_candidates || [],
|
|
485
|
+
blockingReason: parsed.blocking_reason || "",
|
|
486
|
+
};
|
|
487
|
+
} catch (error) {
|
|
488
|
+
return {
|
|
489
|
+
available: false,
|
|
490
|
+
error: error.message,
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
347
495
|
function requirementLines(requirementsPath) {
|
|
348
496
|
if (!fs.existsSync(requirementsPath)) {
|
|
349
497
|
return [];
|
|
@@ -385,7 +533,7 @@ function firstAvailableCommand(candidates) {
|
|
|
385
533
|
}
|
|
386
534
|
|
|
387
535
|
function bootstrapEnvironment(target, includeDev) {
|
|
388
|
-
const pythonCommand =
|
|
536
|
+
const pythonCommand = preferredPythonCommand();
|
|
389
537
|
if (!pythonCommand) {
|
|
390
538
|
return {
|
|
391
539
|
ok: false,
|
|
@@ -453,13 +601,104 @@ function doctorChecks() {
|
|
|
453
601
|
["node", nodeOk, nodeOk ? "found" : "missing"],
|
|
454
602
|
["python", pythonOk, pythonOk ? "found" : "missing"],
|
|
455
603
|
];
|
|
456
|
-
|
|
457
|
-
const
|
|
458
|
-
|
|
459
|
-
|
|
604
|
+
const runtimeDoctor = runtimeDoctorDiagnostics();
|
|
605
|
+
const donorDiagnostics = runtimeDoctor.available
|
|
606
|
+
? {
|
|
607
|
+
targetVersion: runtimeDoctor.targetVersion,
|
|
608
|
+
donorPath: runtimeDoctor.resolvedDonorPath,
|
|
609
|
+
donorVersion: runtimeDoctor.donorVersion,
|
|
610
|
+
donorSource: runtimeDoctor.donorSource,
|
|
611
|
+
status: runtimeDoctor.donorStatus,
|
|
612
|
+
message: runtimeDoctor.donorMessage,
|
|
613
|
+
blockingReason: runtimeDoctor.donorBlockingReason,
|
|
614
|
+
candidatePaths: runtimeDoctor.donorCandidates,
|
|
615
|
+
}
|
|
616
|
+
: packetTracerVersionDiagnostics();
|
|
617
|
+
const twofish = runtimeDoctor.available
|
|
618
|
+
? {
|
|
619
|
+
pythonVersion: runtimeDoctor.pythonVersion,
|
|
620
|
+
pythonSupportStatus: runtimeDoctor.pythonSupportStatus,
|
|
621
|
+
pythonSupportMessage: runtimeDoctor.pythonSupportMessage,
|
|
622
|
+
expectedTwofishPatterns: runtimeDoctor.expectedTwofishPatterns,
|
|
623
|
+
twofishSearchRoots: runtimeDoctor.twofishSearchRoots,
|
|
624
|
+
resolvedTwofishPath: runtimeDoctor.resolvedTwofishPath,
|
|
625
|
+
twofishSource: runtimeDoctor.twofishSource,
|
|
626
|
+
twofishLoadStatus: runtimeDoctor.twofishLoadStatus,
|
|
627
|
+
twofishMessage: runtimeDoctor.twofishMessage,
|
|
628
|
+
twofishSha256: runtimeDoctor.twofishSha256,
|
|
629
|
+
}
|
|
630
|
+
: twofishDiagnostics();
|
|
631
|
+
const hostOs = runtimeDoctor.available ? runtimeDoctor.hostOs : process.platform;
|
|
632
|
+
const detectedLayoutType = runtimeDoctor.available ? runtimeDoctor.detectedLayoutType : "fallback_unknown";
|
|
633
|
+
const recommendedPacketTracerRoot = runtimeDoctor.available
|
|
634
|
+
? runtimeDoctor.recommendedPacketTracerRoot
|
|
635
|
+
: fallbackRecommendedPacketTracerRoot(process.platform);
|
|
636
|
+
const recommendedPacketTracerSavesRoot = runtimeDoctor.available
|
|
637
|
+
? runtimeDoctor.recommendedPacketTracerSavesRoot
|
|
638
|
+
: fallbackRecommendedPacketTracerSavesRoot(process.platform);
|
|
639
|
+
const installerSupported = runtimeDoctor.available
|
|
640
|
+
? runtimeDoctor.installerSupport.status === "supported"
|
|
641
|
+
: ["win32", "darwin", "linux"].includes(process.platform);
|
|
642
|
+
const runtimeSupported = runtimeDoctor.available
|
|
643
|
+
? runtimeDoctor.realPktRuntimeSupport.status === "validated"
|
|
644
|
+
: process.platform === "win32";
|
|
645
|
+
const runtimeMessage = runtimeDoctor.available
|
|
646
|
+
? runtimeDoctor.realPktRuntimeSupport.message
|
|
647
|
+
: runtimeSupported
|
|
648
|
+
? "validated Windows Packet Tracer 9.0 runtime path"
|
|
649
|
+
: twofish.resolvedTwofishPath
|
|
650
|
+
? "custom native runtime may work, but bundled validation is still Windows-first"
|
|
651
|
+
: "needs custom Packet Tracer paths and a non-Windows native Twofish bridge";
|
|
652
|
+
const packetTracerRoot = runtimeDoctor.available
|
|
653
|
+
? runtimeDoctor.packetTracerRoot
|
|
654
|
+
: process.env.PACKET_TRACER_ROOT || "";
|
|
655
|
+
const root = runtimeDoctor.available
|
|
656
|
+
? {
|
|
657
|
+
ok: packetTracerRoot !== "",
|
|
658
|
+
message: packetTracerRoot || "not set",
|
|
659
|
+
}
|
|
660
|
+
: envPathStatus(process.env.PACKET_TRACER_ROOT);
|
|
460
661
|
|
|
461
662
|
const strictTargetVersion = "9.0.0.0810";
|
|
663
|
+
checks.push(["HOST_OS", true, hostOs]);
|
|
664
|
+
checks.push([
|
|
665
|
+
"INSTALLER_SUPPORT",
|
|
666
|
+
installerSupported,
|
|
667
|
+
runtimeDoctor.available ? runtimeDoctor.installerSupport.message : installerSupported ? "supported" : "unknown host platform",
|
|
668
|
+
]);
|
|
669
|
+
checks.push([
|
|
670
|
+
"DETECTED_LAYOUT_TYPE",
|
|
671
|
+
true,
|
|
672
|
+
detectedLayoutType || "unknown",
|
|
673
|
+
]);
|
|
674
|
+
checks.push([
|
|
675
|
+
"RECOMMENDED_PACKET_TRACER_ROOT",
|
|
676
|
+
recommendedPacketTracerRoot !== "",
|
|
677
|
+
recommendedPacketTracerRoot || "not available",
|
|
678
|
+
]);
|
|
679
|
+
checks.push([
|
|
680
|
+
"RECOMMENDED_PACKET_TRACER_SAVES_ROOT",
|
|
681
|
+
recommendedPacketTracerSavesRoot !== "",
|
|
682
|
+
recommendedPacketTracerSavesRoot || "not available",
|
|
683
|
+
]);
|
|
684
|
+
checks.push([
|
|
685
|
+
"REAL_PKT_RUNTIME_SUPPORT",
|
|
686
|
+
runtimeSupported,
|
|
687
|
+
runtimeMessage,
|
|
688
|
+
]);
|
|
462
689
|
checks.push(["PACKET_TRACER_ROOT", root.ok, root.message]);
|
|
690
|
+
if (runtimeDoctor.available) {
|
|
691
|
+
checks.push([
|
|
692
|
+
"PACKET_TRACER_SAVES_ROOT",
|
|
693
|
+
runtimeDoctor.packetTracerSavesRoot !== "",
|
|
694
|
+
runtimeDoctor.packetTracerSavesRoot || "not resolved",
|
|
695
|
+
]);
|
|
696
|
+
checks.push([
|
|
697
|
+
"PACKET_TRACER_EXE",
|
|
698
|
+
runtimeDoctor.packetTracerExe !== "",
|
|
699
|
+
runtimeDoctor.packetTracerExe || "not resolved",
|
|
700
|
+
]);
|
|
701
|
+
}
|
|
463
702
|
checks.push([
|
|
464
703
|
"PYTHON_VERSION",
|
|
465
704
|
twofish.pythonVersion !== "",
|
|
@@ -528,6 +767,124 @@ function doctorChecks() {
|
|
|
528
767
|
twofish.twofishSha256 !== "",
|
|
529
768
|
twofish.twofishSha256 || "not available",
|
|
530
769
|
]);
|
|
770
|
+
checks.push([
|
|
771
|
+
"TWOFISH_EXPECTED_PATTERNS",
|
|
772
|
+
(twofish.expectedTwofishPatterns || []).length > 0,
|
|
773
|
+
(twofish.expectedTwofishPatterns || []).join(" | ") || "not available",
|
|
774
|
+
]);
|
|
775
|
+
checks.push([
|
|
776
|
+
"TWOFISH_SEARCH_ROOTS",
|
|
777
|
+
(twofish.twofishSearchRoots || []).length > 0,
|
|
778
|
+
(twofish.twofishSearchRoots || []).join(" | ") || "not available",
|
|
779
|
+
]);
|
|
780
|
+
const runtimeBlockers = runtimeDoctor.available
|
|
781
|
+
? runtimeDoctor.runtimeBlockers || []
|
|
782
|
+
: [
|
|
783
|
+
donorDiagnostics.status === "ok" ? "" : "missing_or_incompatible_donor",
|
|
784
|
+
twofish.twofishLoadStatus === "ok" ? "" : "missing_twofish_bridge",
|
|
785
|
+
packetTracerRoot ? "" : "missing_packet_tracer_root",
|
|
786
|
+
process.platform === "win32" ? "" : "windows_first_runtime",
|
|
787
|
+
].filter(Boolean);
|
|
788
|
+
const readyOperations = runtimeDoctor.available
|
|
789
|
+
? runtimeDoctor.readyOperations || []
|
|
790
|
+
: [
|
|
791
|
+
donorDiagnostics.status === "ok" && twofish.twofishLoadStatus === "ok" ? "decode" : "",
|
|
792
|
+
donorDiagnostics.status === "ok" && twofish.twofishLoadStatus === "ok" ? "edit" : "",
|
|
793
|
+
donorDiagnostics.status === "ok" &&
|
|
794
|
+
twofish.twofishLoadStatus === "ok" &&
|
|
795
|
+
packetTracerRoot
|
|
796
|
+
? "generate"
|
|
797
|
+
: "",
|
|
798
|
+
].filter(Boolean);
|
|
799
|
+
const capabilityImpact = runtimeDoctor.available
|
|
800
|
+
? runtimeDoctor.capabilityImpact || {}
|
|
801
|
+
: {
|
|
802
|
+
inventory: donorDiagnostics.status === "ok" ? "ready" : "blocked",
|
|
803
|
+
decode: donorDiagnostics.status === "ok" && twofish.twofishLoadStatus === "ok" ? "ready" : "blocked",
|
|
804
|
+
edit: donorDiagnostics.status === "ok" && twofish.twofishLoadStatus === "ok" ? "ready" : "blocked",
|
|
805
|
+
generate:
|
|
806
|
+
donorDiagnostics.status === "ok" && twofish.twofishLoadStatus === "ok" && packetTracerRoot
|
|
807
|
+
? "ready"
|
|
808
|
+
: "blocked",
|
|
809
|
+
validate_open: packetTracerRoot ? "ready" : "blocked",
|
|
810
|
+
};
|
|
811
|
+
const blockedOperations = runtimeDoctor.available
|
|
812
|
+
? runtimeDoctor.blockedOperations || []
|
|
813
|
+
: Object.entries(capabilityImpact)
|
|
814
|
+
.filter(([, status]) => status !== "ready")
|
|
815
|
+
.map(([name]) => name);
|
|
816
|
+
const runtimeGrade = runtimeDoctor.available
|
|
817
|
+
? runtimeDoctor.runtimeGrade || "blocked"
|
|
818
|
+
: runtimeBlockers.length === 0
|
|
819
|
+
? "ready"
|
|
820
|
+
: readyOperations.length > 0
|
|
821
|
+
? "partially_ready"
|
|
822
|
+
: "blocked";
|
|
823
|
+
const doctorSummary = runtimeDoctor.available
|
|
824
|
+
? runtimeDoctor.doctorSummary || ""
|
|
825
|
+
: runtimeGrade === "ready"
|
|
826
|
+
? "Runtime looks ready for decode, edit, generate, and validate-open."
|
|
827
|
+
: runtimeGrade === "partially_ready"
|
|
828
|
+
? "Runtime is partially ready: some operations work, but strict .pkt generation is still blocked."
|
|
829
|
+
: "Runtime is blocked: required donor, bridge, or Packet Tracer runtime pieces are missing.";
|
|
830
|
+
const bridgeResolution = runtimeDoctor.available ? runtimeDoctor.bridgeResolution || "missing" : (process.env.PKT_TWOFISH_LIBRARY ? "external_env" : "missing");
|
|
831
|
+
const bridgeRecommendation = runtimeDoctor.available ? runtimeDoctor.bridgeRecommendation || "" : (process.env.PKT_TWOFISH_LIBRARY
|
|
832
|
+
? "Use or install a repo-local vendor bridge for fully self-contained runtime readiness."
|
|
833
|
+
: "Provide PKT_TWOFISH_LIBRARY or PKT_TWOFISH_SEARCH_ROOTS to resolve a local bridge.");
|
|
834
|
+
const runtimeContractNotes = runtimeDoctor.available ? runtimeDoctor.runtimeContractNotes || "" : (process.env.PKT_TWOFISH_LIBRARY
|
|
835
|
+
? "External bridge resolves decode/edit, but repo-local runtime packaging is still incomplete."
|
|
836
|
+
: "Bridge resolution is missing, so strict runtime remains blocked.");
|
|
837
|
+
const runtimeBlockerSummary = runtimeBlockers.join(" | ");
|
|
838
|
+
const readyOperationSummary = readyOperations.join(" | ");
|
|
839
|
+
const blockedOperationSummary = blockedOperations.join(" | ");
|
|
840
|
+
const capabilityImpactSummary = Object.entries(capabilityImpact)
|
|
841
|
+
.map(([name, status]) => `${name}=${status}`)
|
|
842
|
+
.join(" | ");
|
|
843
|
+
checks.push([
|
|
844
|
+
"RUNTIME_BLOCKERS",
|
|
845
|
+
runtimeBlockers.length === 0,
|
|
846
|
+
runtimeBlockerSummary || "none",
|
|
847
|
+
]);
|
|
848
|
+
checks.push([
|
|
849
|
+
"READY_OPERATIONS",
|
|
850
|
+
readyOperations.length > 0,
|
|
851
|
+
readyOperationSummary || "none",
|
|
852
|
+
]);
|
|
853
|
+
checks.push([
|
|
854
|
+
"BLOCKED_OPERATIONS",
|
|
855
|
+
blockedOperations.length === 0,
|
|
856
|
+
blockedOperationSummary || "none",
|
|
857
|
+
]);
|
|
858
|
+
checks.push([
|
|
859
|
+
"RUNTIME_GRADE",
|
|
860
|
+
runtimeGrade === "ready",
|
|
861
|
+
runtimeGrade,
|
|
862
|
+
]);
|
|
863
|
+
checks.push([
|
|
864
|
+
"DOCTOR_SUMMARY",
|
|
865
|
+
doctorSummary !== "",
|
|
866
|
+
doctorSummary || "not available",
|
|
867
|
+
]);
|
|
868
|
+
checks.push([
|
|
869
|
+
"BRIDGE_RESOLUTION",
|
|
870
|
+
bridgeResolution !== "missing",
|
|
871
|
+
bridgeResolution,
|
|
872
|
+
]);
|
|
873
|
+
checks.push([
|
|
874
|
+
"BRIDGE_RECOMMENDATION",
|
|
875
|
+
bridgeRecommendation !== "",
|
|
876
|
+
bridgeRecommendation || "not available",
|
|
877
|
+
]);
|
|
878
|
+
checks.push([
|
|
879
|
+
"RUNTIME_CONTRACT_NOTES",
|
|
880
|
+
runtimeContractNotes !== "",
|
|
881
|
+
runtimeContractNotes || "not available",
|
|
882
|
+
]);
|
|
883
|
+
checks.push([
|
|
884
|
+
"CAPABILITY_IMPACT",
|
|
885
|
+
capabilityImpactSummary !== "",
|
|
886
|
+
capabilityImpactSummary || "not available",
|
|
887
|
+
]);
|
|
531
888
|
|
|
532
889
|
return checks;
|
|
533
890
|
}
|
|
@@ -538,6 +895,127 @@ function printDoctorChecks(checks) {
|
|
|
538
895
|
}
|
|
539
896
|
}
|
|
540
897
|
|
|
898
|
+
function checkMap(checks) {
|
|
899
|
+
return new Map(checks.map(([name, ok, detail]) => [name, { ok, detail }]));
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
function doctorGuidance(checks) {
|
|
903
|
+
const map = checkMap(checks);
|
|
904
|
+
const guidance = [];
|
|
905
|
+
const pythonSupport = map.get("PYTHON_SUPPORT_STATUS");
|
|
906
|
+
const root = map.get("PACKET_TRACER_ROOT");
|
|
907
|
+
const donor = map.get("PACKET_TRACER_COMPAT_DONOR");
|
|
908
|
+
const donorCandidates = map.get("DONOR_CANDIDATES");
|
|
909
|
+
const savesRoot = map.get("RECOMMENDED_PACKET_TRACER_SAVES_ROOT");
|
|
910
|
+
const twofish = map.get("TWOFISH_LOAD_STATUS");
|
|
911
|
+
const patterns = map.get("TWOFISH_EXPECTED_PATTERNS");
|
|
912
|
+
const searchRoots = map.get("TWOFISH_SEARCH_ROOTS");
|
|
913
|
+
const runtimeSupport = map.get("REAL_PKT_RUNTIME_SUPPORT");
|
|
914
|
+
|
|
915
|
+
if (runtimeSupport && !runtimeSupport.ok) {
|
|
916
|
+
guidance.push(`Real runtime is still Windows-first: ${runtimeSupport.detail}`);
|
|
917
|
+
}
|
|
918
|
+
if (pythonSupport && !pythonSupport.ok) {
|
|
919
|
+
guidance.push("Use Python 3.14.x for Packet Tracer 9.0 encode/decode.");
|
|
920
|
+
}
|
|
921
|
+
if (root && !root.ok) {
|
|
922
|
+
const suffix =
|
|
923
|
+
map.get("RECOMMENDED_PACKET_TRACER_ROOT")?.detail &&
|
|
924
|
+
map.get("RECOMMENDED_PACKET_TRACER_ROOT")?.detail !== "not available"
|
|
925
|
+
? ` Suggested root: ${map.get("RECOMMENDED_PACKET_TRACER_ROOT").detail}.`
|
|
926
|
+
: "";
|
|
927
|
+
guidance.push(`Set PACKET_TRACER_ROOT to your local Cisco Packet Tracer 9.0 install directory.${suffix}`);
|
|
928
|
+
}
|
|
929
|
+
if (donor && !donor.ok) {
|
|
930
|
+
const savesHint =
|
|
931
|
+
savesRoot && savesRoot.detail && savesRoot.detail !== "not available"
|
|
932
|
+
? ` Packet Tracer saves are typically under ${savesRoot.detail}.`
|
|
933
|
+
: "";
|
|
934
|
+
if (donorCandidates && donorCandidates.ok) {
|
|
935
|
+
guidance.push(`Pick one discovered donor or export PACKET_TRACER_COMPAT_DONOR explicitly: ${donorCandidates.detail}.${savesHint}`);
|
|
936
|
+
} else {
|
|
937
|
+
guidance.push(`Provide a working 9.0 donor lab with PACKET_TRACER_COMPAT_DONOR or place one in Downloads/Documents/Desktop/Packet Tracer saves.${savesHint}`);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
if (twofish && !twofish.ok) {
|
|
941
|
+
const parts = ["Provide a local Twofish bridge"];
|
|
942
|
+
if (patterns && patterns.detail && patterns.detail !== "not available") {
|
|
943
|
+
parts.push(`matching one of: ${patterns.detail}`);
|
|
944
|
+
}
|
|
945
|
+
if (searchRoots && searchRoots.detail && searchRoots.detail !== "not available") {
|
|
946
|
+
parts.push(`in one of these roots: ${searchRoots.detail}`);
|
|
947
|
+
}
|
|
948
|
+
parts.push("or set PKT_TWOFISH_LIBRARY / PKT_TWOFISH_SEARCH_ROOTS.");
|
|
949
|
+
guidance.push(parts.join(" "));
|
|
950
|
+
}
|
|
951
|
+
return guidance;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
function fallbackEnvExamples(platformName) {
|
|
955
|
+
if (platformName === "win32") {
|
|
956
|
+
return [
|
|
957
|
+
"$env:PACKET_TRACER_ROOT='C:\\Program Files\\Cisco Packet Tracer 9.0.0'",
|
|
958
|
+
"$env:PACKET_TRACER_COMPAT_DONOR='C:\\path\\to\\your-working-9.0-donor.pkt'",
|
|
959
|
+
'$env:PKT_TWOFISH_LIBRARY="$env:USERPROFILE\\.codex\\skills\\pkt\\scripts\\vendor\\_twofish.cp314-win_amd64.pyd"',
|
|
960
|
+
];
|
|
961
|
+
}
|
|
962
|
+
if (platformName === "darwin") {
|
|
963
|
+
return [
|
|
964
|
+
"export PACKET_TRACER_ROOT='/Applications/Cisco Packet Tracer.app/Contents/Resources'",
|
|
965
|
+
"export PACKET_TRACER_COMPAT_DONOR=\"$HOME/path/to/your-working-9.0-donor.pkt\"",
|
|
966
|
+
"export PKT_TWOFISH_SEARCH_ROOTS=\"$HOME/.codex/skills/pkt/scripts/vendor:$HOME/pkt-bridges\"",
|
|
967
|
+
];
|
|
968
|
+
}
|
|
969
|
+
if (platformName === "linux") {
|
|
970
|
+
return [
|
|
971
|
+
"export PACKET_TRACER_ROOT='/opt/pt'",
|
|
972
|
+
"export PACKET_TRACER_COMPAT_DONOR=\"$HOME/path/to/your-working-9.0-donor.pkt\"",
|
|
973
|
+
"export PKT_TWOFISH_SEARCH_ROOTS=\"$HOME/.codex/skills/pkt/scripts/vendor:$HOME/pkt-bridges\"",
|
|
974
|
+
];
|
|
975
|
+
}
|
|
976
|
+
return [];
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
function fallbackRecommendedPacketTracerRoot(platformName) {
|
|
980
|
+
if (platformName === "win32") {
|
|
981
|
+
return "C:\\Program Files\\Cisco Packet Tracer 9.0.0";
|
|
982
|
+
}
|
|
983
|
+
if (platformName === "darwin") {
|
|
984
|
+
return "/Applications/Cisco Packet Tracer.app/Contents/Resources";
|
|
985
|
+
}
|
|
986
|
+
if (platformName === "linux") {
|
|
987
|
+
return "/opt/pt";
|
|
988
|
+
}
|
|
989
|
+
return "";
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
function fallbackRecommendedPacketTracerSavesRoot(platformName) {
|
|
993
|
+
if (platformName === "win32") {
|
|
994
|
+
return "C:\\Program Files\\Cisco Packet Tracer 9.0.0\\saves";
|
|
995
|
+
}
|
|
996
|
+
if (platformName === "darwin") {
|
|
997
|
+
return "/Applications/Cisco Packet Tracer.app/Contents/Resources/saves";
|
|
998
|
+
}
|
|
999
|
+
if (platformName === "linux") {
|
|
1000
|
+
return "/opt/pt/saves";
|
|
1001
|
+
}
|
|
1002
|
+
return "";
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
function printEnvExamples(runtimeDoctor) {
|
|
1006
|
+
const examples =
|
|
1007
|
+
runtimeDoctor && runtimeDoctor.available && (runtimeDoctor.envExamples || []).length
|
|
1008
|
+
? runtimeDoctor.envExamples
|
|
1009
|
+
: fallbackEnvExamples(process.platform);
|
|
1010
|
+
if (!examples.length) {
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
console.log("\nSuggested environment setup:");
|
|
1014
|
+
for (const line of examples) {
|
|
1015
|
+
console.log(`- ${line}`);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
|
|
541
1019
|
function main() {
|
|
542
1020
|
try {
|
|
543
1021
|
const args = parseArgs(process.argv.slice(2));
|
|
@@ -547,8 +1025,17 @@ function main() {
|
|
|
547
1025
|
}
|
|
548
1026
|
|
|
549
1027
|
if (args.doctor) {
|
|
1028
|
+
const runtimeDoctor = runtimeDoctorDiagnostics();
|
|
550
1029
|
const checks = doctorChecks();
|
|
551
1030
|
printDoctorChecks(checks);
|
|
1031
|
+
const guidance = doctorGuidance(checks);
|
|
1032
|
+
if (guidance.length > 0) {
|
|
1033
|
+
console.log("\nRecommended next steps:");
|
|
1034
|
+
for (const line of guidance) {
|
|
1035
|
+
console.log(`- ${line}`);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
printEnvExamples(runtimeDoctor);
|
|
552
1039
|
const failed = checks.some(([, ok]) => !ok);
|
|
553
1040
|
if (failed) {
|
|
554
1041
|
console.error("\nRuntime is not fully ready. Install copies are fine, but Packet Tracer generation still needs the missing items above.");
|
|
@@ -610,8 +1097,17 @@ function main() {
|
|
|
610
1097
|
}
|
|
611
1098
|
|
|
612
1099
|
const checks = doctorChecks();
|
|
1100
|
+
const runtimeDoctor = runtimeDoctorDiagnostics();
|
|
613
1101
|
console.log("\nRemaining manual runtime checks:");
|
|
614
1102
|
printDoctorChecks(checks);
|
|
1103
|
+
const guidance = doctorGuidance(checks);
|
|
1104
|
+
if (guidance.length > 0) {
|
|
1105
|
+
console.log("\nRecommended next steps:");
|
|
1106
|
+
for (const line of guidance) {
|
|
1107
|
+
console.log(`- ${line}`);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
printEnvExamples(runtimeDoctor);
|
|
615
1111
|
const missing = checks.filter(([, ok]) => !ok).map(([name]) => name);
|
|
616
1112
|
const donorCandidates = checks.find(([name]) => name === "DONOR_CANDIDATES");
|
|
617
1113
|
if (donorCandidates && donorCandidates[2] && donorCandidates[2] !== "none discovered") {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Curated Donor Registry
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
The curated donor registry is the explicit truth source for donor promotion metadata that should not be guessed from filenames alone.
|
|
6
|
+
|
|
7
|
+
Registry file:
|
|
8
|
+
|
|
9
|
+
- `references/curated-donor-registry.json`
|
|
10
|
+
|
|
11
|
+
## Entry Contract
|
|
12
|
+
|
|
13
|
+
Each entry should define:
|
|
14
|
+
|
|
15
|
+
- `relative_path`
|
|
16
|
+
- `promotion_status`
|
|
17
|
+
- `packet_tracer_version`
|
|
18
|
+
- `workspace_validation`
|
|
19
|
+
- `apply_safety_level`
|
|
20
|
+
- `archetype_tags`
|
|
21
|
+
- `validated_edit_capabilities`
|
|
22
|
+
- `acceptance_fixtures`
|
|
23
|
+
- `acceptance_notes`
|
|
24
|
+
- `provenance`
|
|
25
|
+
|
|
26
|
+
## Current Seeded Entries
|
|
27
|
+
|
|
28
|
+
The current seeded entries are based on known working example artifacts:
|
|
29
|
+
|
|
30
|
+
- `complex_campus_master_edit_v4.pkt`
|
|
31
|
+
- `home_iot_cli_edit_v1.pkt`
|
|
32
|
+
- `service_heavy_cli_edit_v1.pkt`
|
|
33
|
+
|
|
34
|
+
These entries become active when a donor root contains matching relative paths or filenames.
|
|
35
|
+
|
|
36
|
+
## Promotion Rules
|
|
37
|
+
|
|
38
|
+
- `reference_only` never becomes the final selected donor
|
|
39
|
+
- `acceptance_verified_curated` requires explicit `acceptance_fixtures`
|
|
40
|
+
- registry-backed metadata overrides inferred metadata where the registry is more explicit
|
|
41
|
+
- validation can still demote a registry entry if the actual donor is blocked or incompatible
|
|
42
|
+
|
|
43
|
+
## Evidence Sources
|
|
44
|
+
|
|
45
|
+
Selected donor summaries distinguish:
|
|
46
|
+
|
|
47
|
+
- registry-backed evidence
|
|
48
|
+
- inferred evidence
|
|
49
|
+
- mixed `registry+inferred` evidence
|
|
50
|
+
|
|
51
|
+
This is important for auditability and release messaging.
|