qlogicagent 2.16.5 → 2.16.7

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 (74) hide show
  1. package/dist/agent.js +20 -20
  2. package/dist/cli.js +375 -370
  3. package/dist/index.js +374 -369
  4. package/dist/orchestration.js +10 -10
  5. package/dist/protocol.js +1 -1
  6. package/dist/types/agent/tool-loop/loop-helpers.d.ts +1 -4
  7. package/dist/types/agent/tool-loop/pseudo-tool-output.d.ts +8 -0
  8. package/dist/types/agent/tool-loop/tool-failure-policy.d.ts +0 -1
  9. package/dist/types/agent/tool-loop/tool-guardrails.d.ts +24 -0
  10. package/dist/types/agent/tool-loop/tool-result-classification.d.ts +10 -0
  11. package/dist/types/cli/acp-commands.d.ts +1 -2
  12. package/dist/types/cli/base-tool-bootstrap.d.ts +1 -0
  13. package/dist/types/cli/handlers/files-handler.d.ts +5 -0
  14. package/dist/types/cli/handlers/message-feedback-handler.d.ts +29 -0
  15. package/dist/types/cli/handlers/pinned-skill-context.d.ts +2 -0
  16. package/dist/types/cli/handlers/project-handler.d.ts +1 -0
  17. package/dist/types/cli/handlers/turn-baseline-handler.d.ts +8 -0
  18. package/dist/types/cli/handlers/turn-handler.d.ts +5 -0
  19. package/dist/types/cli/handlers/working-materials-handler.d.ts +9 -0
  20. package/dist/types/cli/idle-dream-coordinator.d.ts +6 -0
  21. package/dist/types/cli/mcp-bootstrap.d.ts +1 -0
  22. package/dist/types/cli/rpc-registry.d.ts +6 -0
  23. package/dist/types/cli/skill-invocation-service.d.ts +2 -0
  24. package/dist/types/cli/stdio-rpc-handler-hosts.d.ts +1 -0
  25. package/dist/types/cli/stdio-runtime-bootstrap.d.ts +1 -0
  26. package/dist/types/cli/tool-bootstrap-core-registration.d.ts +1 -0
  27. package/dist/types/cli/tool-bootstrap.d.ts +1 -0
  28. package/dist/types/protocol/methods.d.ts +24 -0
  29. package/dist/types/protocol/wire/agent-events.d.ts +2 -2
  30. package/dist/types/protocol/wire/gateway-rpc.d.ts +160 -0
  31. package/dist/types/protocol/wire/notification-payloads.d.ts +27 -0
  32. package/dist/types/runtime/execution/untrusted-tool-result.d.ts +2 -0
  33. package/dist/types/runtime/infra/feedback-distillation-worker.d.ts +20 -0
  34. package/dist/types/runtime/infra/feedback-distillation.d.ts +30 -0
  35. package/dist/types/runtime/infra/feedback-event-store.d.ts +160 -0
  36. package/dist/types/runtime/infra/feedback-outbox.d.ts +26 -0
  37. package/dist/types/runtime/infra/feedback-redaction.d.ts +71 -0
  38. package/dist/types/runtime/infra/feedback-upload-client.d.ts +39 -0
  39. package/dist/types/runtime/infra/feedback-upload-worker.d.ts +11 -0
  40. package/dist/types/runtime/infra/skill-resolver.d.ts +8 -2
  41. package/dist/types/runtime/infra/turn-baseline-store.d.ts +102 -0
  42. package/dist/types/runtime/infra/turn-telemetry-store.d.ts +59 -0
  43. package/dist/types/runtime/infra/working-materials-store.d.ts +35 -0
  44. package/dist/types/runtime/ports/memory-provider.d.ts +6 -0
  45. package/dist/types/runtime/ports/tool-contracts.d.ts +1 -0
  46. package/dist/types/runtime/prompt/fresh-workspace-evidence.d.ts +14 -0
  47. package/dist/types/skills/mcp/mcp-manager.d.ts +31 -2
  48. package/dist/types/skills/memory/local-memory-provider.d.ts +3 -3
  49. package/dist/types/skills/memory/local-store-records.d.ts +18 -1
  50. package/dist/types/skills/memory/local-store.d.ts +8 -195
  51. package/dist/types/skills/memory/memory-consolidation.d.ts +14 -0
  52. package/dist/types/skills/memory/sqlite-memory-schema.d.ts +1 -1
  53. package/dist/types/skills/skill-system/skill-bundles.d.ts +8 -0
  54. package/dist/types/skills/skill-system/skill-frontmatter.d.ts +1 -5
  55. package/dist/types/skills/skill-system/skill-lifecycle.d.ts +13 -1
  56. package/dist/types/skills/skill-system/skill-preprocessing.d.ts +11 -0
  57. package/dist/types/skills/skill-system/skill-types.d.ts +0 -75
  58. package/dist/types/skills/skill-system/skill-validation.d.ts +1 -0
  59. package/dist/types/skills/tools/skill-tool.d.ts +3 -2
  60. package/dist/vendor/hatch-pet/LICENSE.txt +201 -201
  61. package/dist/vendor/hatch-pet/NOTICE.md +25 -25
  62. package/dist/vendor/hatch-pet/references/animation-rows.md +29 -29
  63. package/dist/vendor/hatch-pet/references/codex-pet-contract.md +35 -35
  64. package/dist/vendor/hatch-pet/references/qa-rubric.md +66 -66
  65. package/dist/vendor/hatch-pet/scripts/compose_atlas.py +169 -169
  66. package/dist/vendor/hatch-pet/scripts/derive_running_left_from_running_right.py +150 -150
  67. package/dist/vendor/hatch-pet/scripts/extract_strip_frames.py +408 -408
  68. package/dist/vendor/hatch-pet/scripts/inspect_frames.py +256 -256
  69. package/dist/vendor/hatch-pet/scripts/make_contact_sheet.py +96 -96
  70. package/dist/vendor/hatch-pet/scripts/prepare_pet_run.py +834 -834
  71. package/dist/vendor/hatch-pet/scripts/render_animation_previews.py +78 -78
  72. package/dist/vendor/hatch-pet/scripts/validate_atlas.py +157 -157
  73. package/package.json +3 -2
  74. package/dist/types/skills/skill-system/skill-source.d.ts +0 -38
@@ -1,78 +1,78 @@
1
- #!/usr/bin/env python3
2
- """Render lightweight animated QA previews from extracted Codex pet frames."""
3
-
4
- from __future__ import annotations
5
-
6
- import argparse
7
- import json
8
- from pathlib import Path
9
-
10
- from PIL import Image
11
-
12
- ROW_DURATIONS = {
13
- "idle": [280, 110, 110, 140, 140, 320],
14
- "running-right": [120, 120, 120, 120, 120, 120, 120, 220],
15
- "running-left": [120, 120, 120, 120, 120, 120, 120, 220],
16
- "waving": [140, 140, 140, 280],
17
- "jumping": [140, 140, 140, 140, 280],
18
- "failed": [140, 140, 140, 140, 140, 140, 140, 240],
19
- "waiting": [150, 150, 150, 150, 150, 260],
20
- "running": [120, 120, 120, 120, 120, 220],
21
- "review": [150, 150, 150, 150, 150, 280],
22
- }
23
- IMAGE_SUFFIXES = {".png", ".webp", ".jpg", ".jpeg"}
24
-
25
-
26
- def frame_files(state_dir: Path) -> list[Path]:
27
- if not state_dir.is_dir():
28
- return []
29
- return sorted(path for path in state_dir.iterdir() if path.suffix.lower() in IMAGE_SUFFIXES)
30
-
31
-
32
- def load_frames(frames_root: Path, state: str, expected_count: int) -> list[Image.Image]:
33
- files = frame_files(frames_root / state)
34
- if len(files) != expected_count:
35
- raise SystemExit(
36
- f"{state} preview needs {expected_count} frames, found {len(files)} under {frames_root / state}"
37
- )
38
- frames = []
39
- for path in files:
40
- with Image.open(path) as opened:
41
- frames.append(opened.convert("RGBA"))
42
- return frames
43
-
44
-
45
- def save_preview(frames: list[Image.Image], durations: list[int], output: Path) -> None:
46
- output.parent.mkdir(parents=True, exist_ok=True)
47
- frames[0].save(
48
- output,
49
- save_all=True,
50
- append_images=frames[1:],
51
- duration=durations,
52
- loop=0,
53
- disposal=2,
54
- optimize=False,
55
- )
56
-
57
-
58
- def main() -> None:
59
- parser = argparse.ArgumentParser(description=__doc__)
60
- parser.add_argument("--frames-root", required=True)
61
- parser.add_argument("--output-dir", required=True)
62
- args = parser.parse_args()
63
-
64
- frames_root = Path(args.frames_root).expanduser().resolve()
65
- output_dir = Path(args.output_dir).expanduser().resolve()
66
- previews = []
67
- for state, durations in ROW_DURATIONS.items():
68
- frames = load_frames(frames_root, state, len(durations))
69
- output = output_dir / f"{state}.gif"
70
- save_preview(frames, durations, output)
71
- previews.append({"state": state, "path": str(output), "frames": len(frames)})
72
-
73
- result = {"ok": True, "output_dir": str(output_dir), "previews": previews}
74
- print(json.dumps(result, indent=2))
75
-
76
-
77
- if __name__ == "__main__":
78
- main()
1
+ #!/usr/bin/env python3
2
+ """Render lightweight animated QA previews from extracted Codex pet frames."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ from pathlib import Path
9
+
10
+ from PIL import Image
11
+
12
+ ROW_DURATIONS = {
13
+ "idle": [280, 110, 110, 140, 140, 320],
14
+ "running-right": [120, 120, 120, 120, 120, 120, 120, 220],
15
+ "running-left": [120, 120, 120, 120, 120, 120, 120, 220],
16
+ "waving": [140, 140, 140, 280],
17
+ "jumping": [140, 140, 140, 140, 280],
18
+ "failed": [140, 140, 140, 140, 140, 140, 140, 240],
19
+ "waiting": [150, 150, 150, 150, 150, 260],
20
+ "running": [120, 120, 120, 120, 120, 220],
21
+ "review": [150, 150, 150, 150, 150, 280],
22
+ }
23
+ IMAGE_SUFFIXES = {".png", ".webp", ".jpg", ".jpeg"}
24
+
25
+
26
+ def frame_files(state_dir: Path) -> list[Path]:
27
+ if not state_dir.is_dir():
28
+ return []
29
+ return sorted(path for path in state_dir.iterdir() if path.suffix.lower() in IMAGE_SUFFIXES)
30
+
31
+
32
+ def load_frames(frames_root: Path, state: str, expected_count: int) -> list[Image.Image]:
33
+ files = frame_files(frames_root / state)
34
+ if len(files) != expected_count:
35
+ raise SystemExit(
36
+ f"{state} preview needs {expected_count} frames, found {len(files)} under {frames_root / state}"
37
+ )
38
+ frames = []
39
+ for path in files:
40
+ with Image.open(path) as opened:
41
+ frames.append(opened.convert("RGBA"))
42
+ return frames
43
+
44
+
45
+ def save_preview(frames: list[Image.Image], durations: list[int], output: Path) -> None:
46
+ output.parent.mkdir(parents=True, exist_ok=True)
47
+ frames[0].save(
48
+ output,
49
+ save_all=True,
50
+ append_images=frames[1:],
51
+ duration=durations,
52
+ loop=0,
53
+ disposal=2,
54
+ optimize=False,
55
+ )
56
+
57
+
58
+ def main() -> None:
59
+ parser = argparse.ArgumentParser(description=__doc__)
60
+ parser.add_argument("--frames-root", required=True)
61
+ parser.add_argument("--output-dir", required=True)
62
+ args = parser.parse_args()
63
+
64
+ frames_root = Path(args.frames_root).expanduser().resolve()
65
+ output_dir = Path(args.output_dir).expanduser().resolve()
66
+ previews = []
67
+ for state, durations in ROW_DURATIONS.items():
68
+ frames = load_frames(frames_root, state, len(durations))
69
+ output = output_dir / f"{state}.gif"
70
+ save_preview(frames, durations, output)
71
+ previews.append({"state": state, "path": str(output), "frames": len(frames)})
72
+
73
+ result = {"ok": True, "output_dir": str(output_dir), "previews": previews}
74
+ print(json.dumps(result, indent=2))
75
+
76
+
77
+ if __name__ == "__main__":
78
+ main()
@@ -1,157 +1,157 @@
1
- #!/usr/bin/env python3
2
- """Validate a Codex pet spritesheet atlas."""
3
-
4
- from __future__ import annotations
5
-
6
- import argparse
7
- import json
8
- from collections import defaultdict
9
- from pathlib import Path
10
-
11
- from PIL import Image
12
-
13
- COLUMNS = 8
14
- ROWS = 9
15
- CELL_WIDTH = 192
16
- CELL_HEIGHT = 208
17
- ATLAS_WIDTH = COLUMNS * CELL_WIDTH
18
- ATLAS_HEIGHT = ROWS * CELL_HEIGHT
19
- ROW_BY_INDEX = {
20
- 0: ("idle", 6),
21
- 1: ("running-right", 8),
22
- 2: ("running-left", 8),
23
- 3: ("waving", 4),
24
- 4: ("jumping", 5),
25
- 5: ("failed", 8),
26
- 6: ("waiting", 6),
27
- 7: ("running", 6),
28
- 8: ("review", 6),
29
- }
30
-
31
-
32
- def alpha_nonzero_count(image: Image.Image) -> int:
33
- alpha = image.getchannel("A")
34
- return sum(alpha.histogram()[1:])
35
-
36
-
37
- def transparent_rgb_residue_count(image: Image.Image) -> int:
38
- rgba = image.convert("RGBA")
39
- data = rgba.tobytes()
40
- count = 0
41
- for index in range(0, len(data), 4):
42
- red, green, blue, alpha = data[index : index + 4]
43
- if alpha == 0 and (red or green or blue):
44
- count += 1
45
- return count
46
-
47
-
48
- def main() -> None:
49
- parser = argparse.ArgumentParser(description=__doc__)
50
- parser.add_argument("atlas")
51
- parser.add_argument("--json-out")
52
- parser.add_argument("--min-used-pixels", type=int, default=50)
53
- parser.add_argument("--near-opaque-threshold", type=float, default=0.95)
54
- parser.add_argument("--allow-opaque", action="store_true")
55
- parser.add_argument("--allow-near-opaque-used-cells", action="store_true")
56
- args = parser.parse_args()
57
-
58
- atlas_path = Path(args.atlas).expanduser().resolve()
59
- errors: list[str] = []
60
- warnings: list[str] = []
61
- near_opaque_used_cells: dict[str, list[int]] = defaultdict(list)
62
- cells: list[dict[str, object]] = []
63
-
64
- try:
65
- with Image.open(atlas_path) as opened:
66
- source_mode = opened.mode
67
- source_format = opened.format
68
- image = opened.convert("RGBA")
69
- except Exception as exc: # noqa: BLE001
70
- result = {"ok": False, "errors": [f"could not open atlas: {exc}"], "warnings": []}
71
- print(json.dumps(result, indent=2))
72
- raise SystemExit(1)
73
-
74
- if image.size != (ATLAS_WIDTH, ATLAS_HEIGHT):
75
- errors.append(f"expected {ATLAS_WIDTH}x{ATLAS_HEIGHT}, got {image.width}x{image.height}")
76
-
77
- if source_format not in {"PNG", "WEBP"}:
78
- errors.append(f"expected PNG or WebP, got {source_format}")
79
-
80
- if "A" not in source_mode and not args.allow_opaque:
81
- errors.append("atlas does not have an alpha channel")
82
-
83
- for row_index in range(ROWS):
84
- state, frame_count = ROW_BY_INDEX[row_index]
85
- for column_index in range(COLUMNS):
86
- left = column_index * CELL_WIDTH
87
- top = row_index * CELL_HEIGHT
88
- cell = image.crop((left, top, left + CELL_WIDTH, top + CELL_HEIGHT))
89
- nontransparent = alpha_nonzero_count(cell)
90
- used = column_index < frame_count
91
- cell_info = {
92
- "state": state,
93
- "row": row_index,
94
- "column": column_index,
95
- "used": used,
96
- "nontransparent_pixels": nontransparent,
97
- }
98
- cells.append(cell_info)
99
- if used and nontransparent < args.min_used_pixels:
100
- errors.append(
101
- f"{state} row {row_index} column {column_index} is empty or too sparse ({nontransparent} pixels)"
102
- )
103
- if used and nontransparent > CELL_WIDTH * CELL_HEIGHT * args.near_opaque_threshold:
104
- near_opaque_used_cells[f"{state} row {row_index}"].append(column_index)
105
- if not used and nontransparent != 0:
106
- errors.append(
107
- f"{state} row {row_index} unused column {column_index} is not transparent ({nontransparent} pixels)"
108
- )
109
-
110
- for row_label, columns in near_opaque_used_cells.items():
111
- message = (
112
- f"{row_label} has {len(columns)} nearly opaque used cells; "
113
- "this usually means the sprite has a non-transparent background"
114
- )
115
- if args.allow_near_opaque_used_cells:
116
- warnings.append(message)
117
- else:
118
- errors.append(message)
119
-
120
- alpha_count = alpha_nonzero_count(image)
121
- if alpha_count == ATLAS_WIDTH * ATLAS_HEIGHT:
122
- message = "atlas is fully opaque; custom pets require a transparent sprite background"
123
- if args.allow_opaque:
124
- warnings.append(message)
125
- else:
126
- errors.append(message)
127
-
128
- transparent_rgb_residue = transparent_rgb_residue_count(image)
129
- if transparent_rgb_residue:
130
- errors.append(
131
- f"atlas has {transparent_rgb_residue} fully transparent pixels with non-zero RGB residue"
132
- )
133
-
134
- result = {
135
- "ok": not errors,
136
- "file": str(atlas_path),
137
- "format": source_format,
138
- "mode": source_mode,
139
- "width": image.width,
140
- "height": image.height,
141
- "transparent_rgb_residue_pixels": transparent_rgb_residue,
142
- "errors": errors,
143
- "warnings": warnings,
144
- "cells": cells,
145
- }
146
-
147
- if args.json_out:
148
- Path(args.json_out).expanduser().resolve().write_text(
149
- json.dumps(result, indent=2) + "\n", encoding="utf-8"
150
- )
151
-
152
- print(json.dumps({k: v for k, v in result.items() if k != "cells"}, indent=2))
153
- raise SystemExit(0 if result["ok"] else 1)
154
-
155
-
156
- if __name__ == "__main__":
157
- main()
1
+ #!/usr/bin/env python3
2
+ """Validate a Codex pet spritesheet atlas."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ from collections import defaultdict
9
+ from pathlib import Path
10
+
11
+ from PIL import Image
12
+
13
+ COLUMNS = 8
14
+ ROWS = 9
15
+ CELL_WIDTH = 192
16
+ CELL_HEIGHT = 208
17
+ ATLAS_WIDTH = COLUMNS * CELL_WIDTH
18
+ ATLAS_HEIGHT = ROWS * CELL_HEIGHT
19
+ ROW_BY_INDEX = {
20
+ 0: ("idle", 6),
21
+ 1: ("running-right", 8),
22
+ 2: ("running-left", 8),
23
+ 3: ("waving", 4),
24
+ 4: ("jumping", 5),
25
+ 5: ("failed", 8),
26
+ 6: ("waiting", 6),
27
+ 7: ("running", 6),
28
+ 8: ("review", 6),
29
+ }
30
+
31
+
32
+ def alpha_nonzero_count(image: Image.Image) -> int:
33
+ alpha = image.getchannel("A")
34
+ return sum(alpha.histogram()[1:])
35
+
36
+
37
+ def transparent_rgb_residue_count(image: Image.Image) -> int:
38
+ rgba = image.convert("RGBA")
39
+ data = rgba.tobytes()
40
+ count = 0
41
+ for index in range(0, len(data), 4):
42
+ red, green, blue, alpha = data[index : index + 4]
43
+ if alpha == 0 and (red or green or blue):
44
+ count += 1
45
+ return count
46
+
47
+
48
+ def main() -> None:
49
+ parser = argparse.ArgumentParser(description=__doc__)
50
+ parser.add_argument("atlas")
51
+ parser.add_argument("--json-out")
52
+ parser.add_argument("--min-used-pixels", type=int, default=50)
53
+ parser.add_argument("--near-opaque-threshold", type=float, default=0.95)
54
+ parser.add_argument("--allow-opaque", action="store_true")
55
+ parser.add_argument("--allow-near-opaque-used-cells", action="store_true")
56
+ args = parser.parse_args()
57
+
58
+ atlas_path = Path(args.atlas).expanduser().resolve()
59
+ errors: list[str] = []
60
+ warnings: list[str] = []
61
+ near_opaque_used_cells: dict[str, list[int]] = defaultdict(list)
62
+ cells: list[dict[str, object]] = []
63
+
64
+ try:
65
+ with Image.open(atlas_path) as opened:
66
+ source_mode = opened.mode
67
+ source_format = opened.format
68
+ image = opened.convert("RGBA")
69
+ except Exception as exc: # noqa: BLE001
70
+ result = {"ok": False, "errors": [f"could not open atlas: {exc}"], "warnings": []}
71
+ print(json.dumps(result, indent=2))
72
+ raise SystemExit(1)
73
+
74
+ if image.size != (ATLAS_WIDTH, ATLAS_HEIGHT):
75
+ errors.append(f"expected {ATLAS_WIDTH}x{ATLAS_HEIGHT}, got {image.width}x{image.height}")
76
+
77
+ if source_format not in {"PNG", "WEBP"}:
78
+ errors.append(f"expected PNG or WebP, got {source_format}")
79
+
80
+ if "A" not in source_mode and not args.allow_opaque:
81
+ errors.append("atlas does not have an alpha channel")
82
+
83
+ for row_index in range(ROWS):
84
+ state, frame_count = ROW_BY_INDEX[row_index]
85
+ for column_index in range(COLUMNS):
86
+ left = column_index * CELL_WIDTH
87
+ top = row_index * CELL_HEIGHT
88
+ cell = image.crop((left, top, left + CELL_WIDTH, top + CELL_HEIGHT))
89
+ nontransparent = alpha_nonzero_count(cell)
90
+ used = column_index < frame_count
91
+ cell_info = {
92
+ "state": state,
93
+ "row": row_index,
94
+ "column": column_index,
95
+ "used": used,
96
+ "nontransparent_pixels": nontransparent,
97
+ }
98
+ cells.append(cell_info)
99
+ if used and nontransparent < args.min_used_pixels:
100
+ errors.append(
101
+ f"{state} row {row_index} column {column_index} is empty or too sparse ({nontransparent} pixels)"
102
+ )
103
+ if used and nontransparent > CELL_WIDTH * CELL_HEIGHT * args.near_opaque_threshold:
104
+ near_opaque_used_cells[f"{state} row {row_index}"].append(column_index)
105
+ if not used and nontransparent != 0:
106
+ errors.append(
107
+ f"{state} row {row_index} unused column {column_index} is not transparent ({nontransparent} pixels)"
108
+ )
109
+
110
+ for row_label, columns in near_opaque_used_cells.items():
111
+ message = (
112
+ f"{row_label} has {len(columns)} nearly opaque used cells; "
113
+ "this usually means the sprite has a non-transparent background"
114
+ )
115
+ if args.allow_near_opaque_used_cells:
116
+ warnings.append(message)
117
+ else:
118
+ errors.append(message)
119
+
120
+ alpha_count = alpha_nonzero_count(image)
121
+ if alpha_count == ATLAS_WIDTH * ATLAS_HEIGHT:
122
+ message = "atlas is fully opaque; custom pets require a transparent sprite background"
123
+ if args.allow_opaque:
124
+ warnings.append(message)
125
+ else:
126
+ errors.append(message)
127
+
128
+ transparent_rgb_residue = transparent_rgb_residue_count(image)
129
+ if transparent_rgb_residue:
130
+ errors.append(
131
+ f"atlas has {transparent_rgb_residue} fully transparent pixels with non-zero RGB residue"
132
+ )
133
+
134
+ result = {
135
+ "ok": not errors,
136
+ "file": str(atlas_path),
137
+ "format": source_format,
138
+ "mode": source_mode,
139
+ "width": image.width,
140
+ "height": image.height,
141
+ "transparent_rgb_residue_pixels": transparent_rgb_residue,
142
+ "errors": errors,
143
+ "warnings": warnings,
144
+ "cells": cells,
145
+ }
146
+
147
+ if args.json_out:
148
+ Path(args.json_out).expanduser().resolve().write_text(
149
+ json.dumps(result, indent=2) + "\n", encoding="utf-8"
150
+ )
151
+
152
+ print(json.dumps({k: v for k, v in result.items() if k != "cells"}, indent=2))
153
+ raise SystemExit(0 if result["ok"] else 1)
154
+
155
+
156
+ if __name__ == "__main__":
157
+ main()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qlogicagent",
3
- "version": "2.16.5",
3
+ "version": "2.16.7",
4
4
  "description": "XiaozhiClaw Agent CLI — subprocess architecture (JSON-RPC over stdio)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -71,6 +71,7 @@
71
71
  "test": "vitest run",
72
72
  "check": "tsc --noEmit && pnpm test && pnpm run check:architecture-boundaries && pnpm run check:provider-core-boundary && pnpm run check:provider-core-release-sync && pnpm run check:pet-core-boundary && pnpm run check:workspace-hygiene && pnpm run check:package-artifact",
73
73
  "test:watch": "vitest",
74
+ "benchmark:hermes-superiority": "tsx benchmarks/hermes-superiority/runner.ts",
74
75
  "lint": "oxlint .",
75
76
  "check:architecture-boundaries": "node scripts/check-architecture-boundaries.mjs",
76
77
  "check:provider-core-boundary": "node scripts/check-provider-core-boundary.mjs",
@@ -89,7 +90,7 @@
89
90
  "dependencies": {
90
91
  "@agentclientprotocol/sdk": "^0.25.0",
91
92
  "@napi-rs/canvas": "0.1.100",
92
- "@xiaozhiclaw/pet-core": "0.1.2",
93
+ "@xiaozhiclaw/pet-core": "0.1.3",
93
94
  "@xiaozhiclaw/provider-core": "^0.1.20",
94
95
  "better-sqlite3": "^12.10.0",
95
96
  "dotenv": "^17.3.1",
@@ -1,38 +0,0 @@
1
- /**
2
- * Lightweight per-skill stats stored in `~/.qlogicagent/skill-stats.json`.
3
- * Covers learned, promoted, and registry-installed skills.
4
- */
5
- export interface SkillUsageStats {
6
- /** Total number of times this skill has been invoked/applied. */
7
- invokeCount: number;
8
- /** Number of turns where the skill was active and contributed. */
9
- activeCount: number;
10
- /** Number of times the skill received positive feedback. */
11
- positiveCount: number;
12
- /** Number of times the skill received negative feedback. */
13
- negativeCount: number;
14
- /** ISO 8601 timestamp of last use. */
15
- lastUsedAt?: string;
16
- /** Derived success rate = (invokeCount - negativeCount) / invokeCount */
17
- successRate?: number;
18
- }
19
- export interface SkillStatsFile {
20
- [skillName: string]: SkillUsageStats;
21
- }
22
- /**
23
- * Record a skill invocation. Fire-and-forget — never throws.
24
- * @param agentHome - path to `~/.qlogicagent/`
25
- * @param skillName - the skill that was invoked
26
- * @param success - whether the invocation completed without error
27
- */
28
- export declare function trackSkillInvocation(agentHome: string, skillName: string, success: boolean): void;
29
- /**
30
- * Read stats for a skill. Returns undefined if no stats recorded.
31
- */
32
- export declare function getSkillStats(agentHome: string, skillName: string): SkillUsageStats | undefined;
33
- /**
34
- * Get all skill stats. Useful for UI display.
35
- */
36
- export declare function getAllSkillStats(agentHome: string): SkillStatsFile;
37
- /** Reset cache (for testing). */
38
- export declare function resetStatsCache(): void;