packet-tracer-skill 0.1.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.
Files changed (35) hide show
  1. package/LICENSE +21 -0
  2. package/LICENSES/LICENSE.Twofish-BSD-3-Clause.txt +29 -0
  3. package/README.md +687 -0
  4. package/SKILL.md +221 -0
  5. package/bin/packet-tracer-skill.js +635 -0
  6. package/examples/blueprint_minimal.json +46 -0
  7. package/package.json +42 -0
  8. package/references/packettracer-sample-catalog.json +21410 -0
  9. package/references/packettracer-sample-catalog.md +1124 -0
  10. package/references/pkt-format.md +57 -0
  11. package/references/xml-skeleton-notes.md +44 -0
  12. package/requirements-dev.txt +1 -0
  13. package/requirements.txt +6 -0
  14. package/scripts/build_sample_catalog.py +65 -0
  15. package/scripts/donor_diagnostics.py +35 -0
  16. package/scripts/generate_pkt.py +1264 -0
  17. package/scripts/install_skill.py +71 -0
  18. package/scripts/intent_parser.py +712 -0
  19. package/scripts/packet_tracer_env.py +278 -0
  20. package/scripts/pkt_builder.py +15 -0
  21. package/scripts/pkt_codec.py +181 -0
  22. package/scripts/pkt_editor.py +752 -0
  23. package/scripts/pkt_transformer.py +541 -0
  24. package/scripts/sample_catalog.py +385 -0
  25. package/scripts/sample_selector.py +156 -0
  26. package/scripts/setup.ps1 +26 -0
  27. package/scripts/twofish_diagnostics.py +91 -0
  28. package/scripts/vendor/README.md +46 -0
  29. package/scripts/vendor/twofish.py +81 -0
  30. package/scripts/workspace_repair.py +441 -0
  31. package/templates/pt900/base_empty.xml +21 -0
  32. package/templates/pt900/device_library/pc.xml +20 -0
  33. package/templates/pt900/device_library/printer.xml +432 -0
  34. package/templates/pt900/device_library/router.xml +16 -0
  35. package/templates/pt900/device_library/switch.xml +38 -0
@@ -0,0 +1,57 @@
1
+ # Packet Tracer 9.0 Format Notes
2
+
3
+ This skill targets the modern Packet Tracer `.pkt` format described in the
4
+ research notes supplied alongside the skill update request.
5
+
6
+ ## High-Level Pipeline
7
+
8
+ 1. Packet Tracer XML bytes
9
+ 2. qCompress wrapper
10
+ 3. Stage-2 XOR obfuscation
11
+ 4. Twofish/EAX encryption with a 16-byte authentication tag
12
+ 5. Stage-1 reverse/XOR obfuscation
13
+
14
+ ## qCompress Wrapper
15
+
16
+ The qCompress-compatible wrapper used here is:
17
+
18
+ - 4-byte big-endian uncompressed length
19
+ - zlib-compressed payload
20
+
21
+ ## Modern Codec Constants
22
+
23
+ - Twofish key: `0x89` repeated 16 times
24
+ - EAX nonce seed: `0x10` repeated 16 times
25
+ - Tag length: `16`
26
+
27
+ ## Stage-2 XOR
28
+
29
+ Stage-2 XOR is symmetric:
30
+
31
+ ```text
32
+ out[i] = in[i] XOR ((L - i) & 0xFF)
33
+ ```
34
+
35
+ where `L` is the input length.
36
+
37
+ ## Stage-1 Obfuscation
38
+
39
+ For output:
40
+
41
+ ```text
42
+ out[L - 1 - i] = in[i] XOR ((L - i * L) & 0xFF)
43
+ ```
44
+
45
+ For decode:
46
+
47
+ ```text
48
+ clear[i] = obf[L - 1 - i] XOR ((L - i * L) & 0xFF)
49
+ ```
50
+
51
+ ## Compatibility Notes
52
+
53
+ - The XML root should be `PACKETTRACER5`
54
+ - The targeted version field is `9.0.0.0810`
55
+ - Cross-version compatibility is not assumed
56
+ - The template library in this skill is a controlled starter set, not a complete
57
+ reverse-engineered clone of all Packet Tracer internals
@@ -0,0 +1,44 @@
1
+ # XML Skeleton Notes
2
+
3
+ The builder uses a `PACKETTRACER5` root and organizes generated content under a
4
+ `NETWORK` node with `DEVICES`, `LINKS`, and `SHAPETESTS`.
5
+
6
+ ## Base Document Shape
7
+
8
+ ```xml
9
+ <PACKETTRACER5>
10
+ <VERSION>9.0.0.0810</VERSION>
11
+ <PIXMAPBANK />
12
+ <MOVIEBANK />
13
+ <NETWORK>
14
+ <DEVICES />
15
+ <LINKS />
16
+ <SHAPETESTS />
17
+ </NETWORK>
18
+ <OPTIONS />
19
+ <PHYSICALWORKSPACE />
20
+ </PACKETTRACER5>
21
+ ```
22
+
23
+ ## Template Strategy
24
+
25
+ This skill does not attempt to synthesize the entire Cisco-internal XML schema from
26
+ scratch. Instead, it uses:
27
+
28
+ - a stable base XML document
29
+ - per-device XML templates
30
+ - targeted placeholder replacement for names, models, positions, ports, and configs
31
+
32
+ ## Current Supported Device Templates
33
+
34
+ - `router.xml`
35
+ - `switch.xml`
36
+ - `pc.xml`
37
+
38
+ Each template includes:
39
+
40
+ - a generated device id
41
+ - human-readable device name
42
+ - type and model fields
43
+ - layout coordinates
44
+ - a config section appropriate for the device family
@@ -0,0 +1 @@
1
+ pytest>=8,<9
@@ -0,0 +1,6 @@
1
+ # Runtime Python dependencies
2
+ #
3
+ # The main runtime is intentionally standard-library-first.
4
+ # Packet Tracer encode/decode for modern 9.x files additionally needs a local
5
+ # Twofish bridge binary configured via PKT_TWOFISH_LIBRARY or placed under
6
+ # scripts/vendor/.
@@ -0,0 +1,65 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ import xml.etree.ElementTree as ET
5
+
6
+ from packet_tracer_env import require_packet_tracer_saves_root
7
+ from pkt_codec import decode_pkt_modern
8
+ from sample_catalog import write_catalog_outputs
9
+
10
+
11
+ def summarize_pkt(path: Path) -> dict:
12
+ saves_root = require_packet_tracer_saves_root()
13
+ xml = decode_pkt_modern(path.read_bytes())
14
+ root = ET.fromstring(xml)
15
+ devices = []
16
+ for device in root.findall(".//DEVICES/DEVICE"):
17
+ type_node = device.find("./ENGINE/TYPE")
18
+ devices.append(
19
+ {
20
+ "name": device.findtext("./ENGINE/NAME", default=""),
21
+ "type": device.findtext("./ENGINE/TYPE", default=""),
22
+ "model": type_node.get("model", "") if type_node is not None else "",
23
+ }
24
+ )
25
+ links = []
26
+ for link in root.findall(".//LINKS/LINK"):
27
+ cable = link.find("./CABLE")
28
+ ports = cable.findall("PORT") if cable is not None else []
29
+ links.append(
30
+ {
31
+ "type": link.findtext("./TYPE", default=""),
32
+ "cable_type": cable.findtext("./TYPE", default="") if cable is not None else "",
33
+ "ports": [port.text or "" for port in ports[:2]],
34
+ }
35
+ )
36
+ return {
37
+ "relative_path": str(path.relative_to(saves_root)),
38
+ "version": root.findtext("./VERSION", default=""),
39
+ "device_count": len(devices),
40
+ "link_count": len(links),
41
+ "devices": devices,
42
+ "links": links,
43
+ }
44
+
45
+
46
+ def build_catalog() -> list[dict]:
47
+ saves_root = require_packet_tracer_saves_root()
48
+ items = []
49
+ for path in sorted(saves_root.rglob("*.pkt")):
50
+ try:
51
+ items.append(summarize_pkt(path))
52
+ except Exception as exc:
53
+ items.append({"relative_path": str(path.relative_to(saves_root)), "error": f"{type(exc).__name__}: {exc}"})
54
+ return items
55
+
56
+
57
+ def main() -> None:
58
+ require_packet_tracer_saves_root()
59
+ items = build_catalog()
60
+ write_catalog_outputs(items)
61
+ print(f"Wrote {len(items)} sample entries")
62
+
63
+
64
+ if __name__ == "__main__":
65
+ main()
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env python3
2
+ """Runtime diagnostics for Packet Tracer donor compatibility."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import json
7
+ from packet_tracer_env import inspect_packet_tracer_compatibility_donor
8
+
9
+
10
+ def main() -> int:
11
+ details = inspect_packet_tracer_compatibility_donor()
12
+ result = {
13
+ "target_version": details.target_version,
14
+ "resolved_donor_path": str(details.resolved_path) if details.resolved_path else "",
15
+ "donor_path": str(details.resolved_path) if details.resolved_path else "",
16
+ "donor_version": details.donor_version or "",
17
+ "donor_source": details.donor_source or "",
18
+ "status": details.status,
19
+ "message": (
20
+ f"{details.resolved_path} (version {details.donor_version})"
21
+ if details.status == "ok" and details.resolved_path and details.donor_version
22
+ else details.blocking_reason or details.status
23
+ ),
24
+ "blocking_reason": details.blocking_reason,
25
+ "candidate_paths": [
26
+ {"source": source, "path": str(path)}
27
+ for source, path in details.candidate_paths[:10]
28
+ ],
29
+ }
30
+ print(json.dumps(result))
31
+ return 0
32
+
33
+
34
+ if __name__ == "__main__":
35
+ raise SystemExit(main())