qlogicagent 2.18.6 → 2.18.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 (147) hide show
  1. package/README.md +382 -382
  2. package/dist/agent.js +30 -30
  3. package/dist/cli.js +1 -1
  4. package/dist/default-project-knowledge/INSTRUCTIONS.md +7 -7
  5. package/dist/default-project-knowledge/rules/project-workflow.md +6 -6
  6. package/dist/host-contract.js +1 -0
  7. package/dist/index.js +539 -530
  8. package/dist/orchestration.js +4 -4
  9. package/dist/permissions.js +1 -1
  10. package/dist/plugin-marketplace-compute.js +1 -0
  11. package/dist/protocol.js +1 -1
  12. package/dist/runtime/infra/mcp-bridge-server.js +275 -275
  13. package/dist/skills/builtin/desktop-screenshot/SKILL.md +62 -62
  14. package/dist/skills/builtin/office-doc-reading/SKILL.md +19 -19
  15. package/dist/skills/mcp/astraclaw-native-mcp-server.js +4 -4
  16. package/dist/tunables.js +1 -0
  17. package/dist/types/agent/runtime-vars.d.ts +1 -2
  18. package/dist/types/agent/tool-loop.d.ts +6 -0
  19. package/dist/types/agent/tool-loop.test-harness.d.ts +20 -0
  20. package/dist/types/agent/types.d.ts +2 -0
  21. package/dist/types/cli/acp-extended-handlers.d.ts +7 -0
  22. package/dist/types/cli/acp-extended-host-adapter.d.ts +2 -0
  23. package/dist/types/cli/acp-session-host.d.ts +15 -2
  24. package/dist/types/cli/base-tool-bootstrap.d.ts +1 -0
  25. package/dist/types/cli/community-skill-installer.d.ts +2 -0
  26. package/dist/types/cli/core-tool-coordinator.d.ts +4 -0
  27. package/dist/types/cli/core-tools/config-tool-bootstrap.d.ts +3 -1
  28. package/dist/types/cli/core-tools/config-tool-service.d.ts +7 -5
  29. package/dist/types/cli/default-project-bootstrap.d.ts +1 -0
  30. package/dist/types/cli/handlers/agents-handler.d.ts +4 -1
  31. package/dist/types/cli/handlers/community-handler.d.ts +2 -0
  32. package/dist/types/cli/handlers/config-handler.d.ts +2 -15
  33. package/dist/types/cli/handlers/pet-handler.d.ts +3 -2
  34. package/dist/types/cli/handlers/session-handler.d.ts +1 -1
  35. package/dist/types/cli/handlers/skills-handler.d.ts +12 -10
  36. package/dist/types/cli/handlers/solo-handler.d.ts +3 -0
  37. package/dist/types/cli/handlers/turn-handler.d.ts +46 -32
  38. package/dist/types/cli/handlers/workflow-handler.d.ts +6 -0
  39. package/dist/types/cli/mcp-bootstrap.d.ts +0 -2
  40. package/dist/types/cli/media-inline.d.ts +14 -0
  41. package/dist/types/cli/media-understanding.d.ts +65 -8
  42. package/dist/types/cli/memory-coordinator.d.ts +8 -0
  43. package/dist/types/cli/multi-agent-handler-host.d.ts +2 -0
  44. package/dist/types/cli/permission-bootstrap.d.ts +2 -0
  45. package/dist/types/cli/pet-runtime.d.ts +0 -1
  46. package/dist/types/cli/plugin-bootstrap.d.ts +2 -1
  47. package/dist/types/cli/product-coordinator.d.ts +4 -1
  48. package/dist/types/cli/rpc-registry.d.ts +1 -3
  49. package/dist/types/cli/runtime-watcher-bootstrap.d.ts +0 -2
  50. package/dist/types/cli/session-context.d.ts +4 -2
  51. package/dist/types/cli/skill-invocation-service.d.ts +2 -0
  52. package/dist/types/cli/skill-tools-bootstrap.d.ts +2 -0
  53. package/dist/types/cli/skills-query-service.d.ts +2 -1
  54. package/dist/types/cli/stdio-acp-protocol-coordinator.d.ts +9 -0
  55. package/dist/types/cli/stdio-acp-request-host.d.ts +11 -2
  56. package/dist/types/cli/stdio-rpc-handler-hosts.d.ts +1 -1
  57. package/dist/types/cli/stdio-runtime-bootstrap.d.ts +6 -0
  58. package/dist/types/cli/stdio-runtime-services.d.ts +6 -1
  59. package/dist/types/cli/stdio-server.d.ts +33 -4
  60. package/dist/types/cli/task-distillation-coordinator.d.ts +9 -4
  61. package/dist/types/cli/tool-bootstrap-core-registration.d.ts +3 -0
  62. package/dist/types/cli/tool-bootstrap-media-registration.d.ts +10 -0
  63. package/dist/types/cli/tool-bootstrap-web-registration.d.ts +1 -0
  64. package/dist/types/cli/tool-bootstrap.d.ts +9 -0
  65. package/dist/types/cli/turn-core.d.ts +2 -0
  66. package/dist/types/cli/turn-preview-browser-setup.d.ts +15 -0
  67. package/dist/types/cli/turn-project-router.d.ts +1 -1
  68. package/dist/types/cli/workflow-host-adapter.d.ts +2 -0
  69. package/dist/types/host-contract/index.d.ts +1475 -0
  70. package/dist/types/host-contract/project-id.d.ts +5 -0
  71. package/dist/types/host-contract/provider-profile.d.ts +46 -0
  72. package/dist/types/orchestration/agent-instance.d.ts +6 -0
  73. package/dist/types/orchestration/delegation-coordinator.d.ts +40 -0
  74. package/dist/types/orchestration/goal-mode-adapters.d.ts +3 -0
  75. package/dist/types/orchestration/product-planner.d.ts +3 -0
  76. package/dist/types/orchestration/solo-evaluator.d.ts +18 -3
  77. package/dist/types/orchestration/solo-persistence.d.ts +2 -0
  78. package/dist/types/orchestration/testing/delegate-test-bridge.d.ts +4 -0
  79. package/dist/types/permissions.d.ts +2 -0
  80. package/dist/types/protocol/methods.d.ts +0 -199
  81. package/dist/types/protocol/wire/acp-protocol.d.ts +16 -1
  82. package/dist/types/protocol/wire/agent-methods.d.ts +1 -173
  83. package/dist/types/protocol/wire/chat-types.d.ts +6 -0
  84. package/dist/types/runtime/config/tunable-defaults.d.ts +13 -3
  85. package/dist/types/runtime/execution/dream-agent.d.ts +9 -8
  86. package/dist/types/runtime/infra/agent-paths.d.ts +3 -3
  87. package/dist/types/runtime/infra/astraclaw-capabilities.d.ts +1 -1
  88. package/dist/types/runtime/infra/clixml-sanitize.d.ts +16 -0
  89. package/dist/types/runtime/infra/external-agent-approvals.d.ts +18 -0
  90. package/dist/types/runtime/infra/feedback-distillation.d.ts +3 -1
  91. package/dist/types/runtime/infra/feedback-host-authority.d.ts +4 -0
  92. package/dist/types/runtime/infra/llmrouter-catalog.d.ts +2 -13
  93. package/dist/types/runtime/infra/model-registry.d.ts +3 -1
  94. package/dist/types/runtime/infra/project-authority-facade.d.ts +11 -0
  95. package/dist/types/runtime/infra/project-host-authority.d.ts +10 -0
  96. package/dist/types/runtime/ports/memory-provider.d.ts +11 -7
  97. package/dist/types/runtime/ports/tool-contracts.d.ts +2 -0
  98. package/dist/types/runtime/prompt/fresh-workspace-evidence.d.ts +2 -2
  99. package/dist/types/runtime/session/session-persistence.d.ts +29 -10
  100. package/dist/types/runtime/session/session-recovery.d.ts +4 -0
  101. package/dist/types/runtime/session/session-summary.d.ts +3 -1
  102. package/dist/types/runtime/session/session-transcript-store.d.ts +7 -0
  103. package/dist/types/skills/memory/host-memory-provider.d.ts +148 -0
  104. package/dist/types/skills/memory/local-memory-provider.d.ts +19 -10
  105. package/dist/types/skills/memory/task-distillation.d.ts +6 -0
  106. package/dist/types/skills/plugins/plugin-marketplace.d.ts +23 -57
  107. package/dist/types/skills/tools/media-understand-tool.d.ts +28 -0
  108. package/dist/types/skills/tools/preview-browser-tool.d.ts +136 -0
  109. package/dist/types/skills/tools/shell/task-output.d.ts +10 -1
  110. package/dist/types/skills/tools/skill-tool.d.ts +1 -1
  111. package/dist/types/skills/web-search/brave-source.d.ts +2 -1
  112. package/dist/types/skills/web-search/crawl4ai-extractor.d.ts +3 -2
  113. package/dist/types/skills/web-search/exa-source.d.ts +2 -1
  114. package/dist/types/skills/web-search/search-svc-source.d.ts +4 -3
  115. package/dist/types/skills/web-search/searxng-source.d.ts +3 -1
  116. package/dist/types/skills/web-search/serper-source.d.ts +2 -1
  117. package/dist/types/skills/web-search/source-factory.d.ts +2 -1
  118. package/dist/types/skills/web-search/web-tunable-resolver.d.ts +16 -0
  119. package/dist/types/test-support/global-home-setup.d.ts +2 -0
  120. package/dist/types/transport/acp-server.d.ts +29 -0
  121. package/dist/types/transport/delegate-client.d.ts +82 -0
  122. package/dist/types/transport/host-capability-client.d.ts +21 -0
  123. package/dist/types/transport/host-feedback-client.d.ts +25 -0
  124. package/dist/types/transport/host-profile-client.d.ts +19 -0
  125. package/dist/types/transport/host-project-client.d.ts +16 -0
  126. package/dist/types/transport/host-request-client.d.ts +38 -0
  127. package/dist/types/transport/host-session-client.d.ts +29 -0
  128. package/dist/types/tunables.d.ts +2 -0
  129. package/dist/vendor/hatch-pet/LICENSE.txt +201 -201
  130. package/dist/vendor/hatch-pet/NOTICE.md +25 -25
  131. package/dist/vendor/hatch-pet/references/animation-rows.md +29 -29
  132. package/dist/vendor/hatch-pet/references/codex-pet-contract.md +35 -35
  133. package/dist/vendor/hatch-pet/references/qa-rubric.md +66 -66
  134. package/dist/vendor/hatch-pet/scripts/compose_atlas.py +169 -169
  135. package/dist/vendor/hatch-pet/scripts/derive_running_left_from_running_right.py +150 -150
  136. package/dist/vendor/hatch-pet/scripts/extract_strip_frames.py +408 -408
  137. package/dist/vendor/hatch-pet/scripts/inspect_frames.py +256 -256
  138. package/dist/vendor/hatch-pet/scripts/make_contact_sheet.py +96 -96
  139. package/dist/vendor/hatch-pet/scripts/prepare_pet_run.py +834 -834
  140. package/dist/vendor/hatch-pet/scripts/render_animation_previews.py +78 -78
  141. package/dist/vendor/hatch-pet/scripts/validate_atlas.py +157 -157
  142. package/package.json +25 -2
  143. package/dist/types/cli/handlers/settings-handler.d.ts +0 -19
  144. package/dist/types/cli/permission-rule-persistence.d.ts +0 -16
  145. package/dist/types/cli/tunable-store.d.ts +0 -26
  146. package/dist/types/skills/permissions/settings-watcher.d.ts +0 -26
  147. /package/dist/types/{skills/memory → host-contract}/fts-segment.d.ts +0 -0
@@ -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.18.6",
3
+ "version": "2.18.7",
4
4
  "description": "XiaozhiClaw Agent CLI — subprocess architecture (JSON-RPC over stdio)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -32,9 +32,21 @@
32
32
  "types": "./dist/types/permissions.d.ts",
33
33
  "default": "./dist/permissions.js"
34
34
  },
35
+ "./tunables": {
36
+ "types": "./dist/types/tunables.d.ts",
37
+ "default": "./dist/tunables.js"
38
+ },
35
39
  "./pet-contracts": {
36
40
  "types": "./dist/types/pet-contracts.d.ts",
37
41
  "default": "./dist/pet-contracts.js"
42
+ },
43
+ "./host-contract": {
44
+ "types": "./dist/types/host-contract/index.d.ts",
45
+ "default": "./dist/host-contract.js"
46
+ },
47
+ "./plugin-marketplace-compute": {
48
+ "types": "./dist/types/skills/plugins/plugin-marketplace.d.ts",
49
+ "default": "./dist/plugin-marketplace-compute.js"
38
50
  }
39
51
  },
40
52
  "files": [
@@ -57,8 +69,17 @@
57
69
  "permissions": [
58
70
  "./dist/types/permissions.d.ts"
59
71
  ],
72
+ "tunables": [
73
+ "./dist/types/tunables.d.ts"
74
+ ],
60
75
  "pet-contracts": [
61
76
  "./dist/types/pet-contracts.d.ts"
77
+ ],
78
+ "host-contract": [
79
+ "./dist/types/host-contract/index.d.ts"
80
+ ],
81
+ "plugin-marketplace-compute": [
82
+ "./dist/types/skills/plugins/plugin-marketplace.d.ts"
62
83
  ]
63
84
  }
64
85
  },
@@ -70,7 +91,7 @@
70
91
  "start": "node dist/cli.js",
71
92
  "test": "vitest run",
72
93
  "test:replay": "vitest run benchmarks/transcript-replay",
73
- "check": "pnpm run check:encoding-corruption && pnpm run check:mechanical-rules && pnpm run check:windows-hide && 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",
94
+ "check": "pnpm run check:encoding-corruption && pnpm run check:mechanical-rules && pnpm run check:windows-hide && tsc --noEmit && pnpm test && pnpm run check:architecture-boundaries && pnpm run check:route-a-teardown && pnpm run check:transcript-tool-persistence && 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",
74
95
  "test:watch": "vitest",
75
96
  "benchmark:hermes-superiority": "tsx benchmarks/hermes-superiority/runner.ts",
76
97
  "lint": "oxlint .",
@@ -78,6 +99,8 @@
78
99
  "check:mechanical-rules": "node scripts/check-mechanical-rules.mjs",
79
100
  "check:windows-hide": "node scripts/check-windows-hide.mjs src",
80
101
  "check:architecture-boundaries": "node scripts/check-architecture-boundaries.mjs",
102
+ "check:route-a-teardown": "node scripts/check-route-a-teardown.mjs",
103
+ "check:transcript-tool-persistence": "node scripts/check-transcript-tool-persistence.mjs",
81
104
  "check:provider-core-boundary": "node scripts/check-provider-core-boundary.mjs",
82
105
  "check:provider-core-release-sync": "node scripts/check-provider-core-release-sync.mjs",
83
106
  "check:pet-core-boundary": "node scripts/check-pet-core-boundary.mjs",
@@ -1,19 +0,0 @@
1
- import { type AgentRpcError, type AgentRpcRequest } from "../../protocol/wire/index.js";
2
- export interface SettingsHandlerHost {
3
- sendError?(id: string | number, code: number, message: string): void;
4
- sendResponse(id: string | number, result?: unknown, error?: AgentRpcError): void;
5
- writeClipboard?(text: string): Promise<void>;
6
- }
7
- export declare function handleSettingsListProviders(this: SettingsHandlerHost, msg: AgentRpcRequest): Promise<void>;
8
- export declare function handleSettingsAddKey(this: SettingsHandlerHost, msg: AgentRpcRequest): Promise<void>;
9
- export declare function handleSettingsRemoveKey(this: SettingsHandlerHost, msg: AgentRpcRequest): void;
10
- export declare function handleSettingsGetKey(this: SettingsHandlerHost, msg: AgentRpcRequest): void;
11
- export declare function handleSettingsCopyKey(this: SettingsHandlerHost, msg: AgentRpcRequest): Promise<void>;
12
- export declare function handleSettingsToggleKey(this: SettingsHandlerHost, msg: AgentRpcRequest): void;
13
- export declare function handleSettingsToggleModel(this: SettingsHandlerHost, msg: AgentRpcRequest): void;
14
- export declare function handleSettingsListModels(this: SettingsHandlerHost, msg: AgentRpcRequest): Promise<void>;
15
- export declare function handleSettingsSetActiveModel(this: SettingsHandlerHost, msg: AgentRpcRequest): void;
16
- export declare function handleSettingsGetActiveModel(this: SettingsHandlerHost, msg: AgentRpcRequest): void;
17
- export declare function handleSettingsGetOverview(this: SettingsHandlerHost, msg: AgentRpcRequest): Promise<void>;
18
- export declare function handleSettingsRefreshModels(this: SettingsHandlerHost, msg: AgentRpcRequest): Promise<void>;
19
- export declare function handleSettingsValidateKey(this: SettingsHandlerHost, msg: AgentRpcRequest): Promise<void>;
@@ -1,16 +0,0 @@
1
- /**
2
- * Persist "始终允许此文件夹" approvals into the USER-level settings.json
3
- * (`~/.qlogicagent/profiles/<owner>/settings.json` → permissions.rules).
4
- *
5
- * Same file config.update writes and the settings-watcher's user layer reads,
6
- * so a persisted rule survives restarts via loadInitialSettings/watchSettings.
7
- * turn-permission-sync leaves rules alone when a frame carries only `{ mode }`,
8
- * so desktop turns cannot wipe these entries.
9
- */
10
- /**
11
- * Append an allow rule for `pathPrefix` to the user settings, preserving the rest
12
- * of the file. Idempotent: an existing allow rule with the same prefix is kept as-is.
13
- */
14
- export declare function persistUserDirectoryAllowRule(rule: {
15
- pathPrefix: string;
16
- }): Promise<void>;
@@ -1,26 +0,0 @@
1
- /**
2
- * Tunable override store — the SINGLE write/read path for settings.tunables.
3
- *
4
- * Shared by the config.updateTunable RPC (UI settings page) and the `config`
5
- * tool (conversational tuning), so both go through identical validation,
6
- * persistence, and runtime sync. Values are hot: ModelRegistry.getTunable()
7
- * re-reads settings.json on every call, so a persisted override takes effect
8
- * on the next read with no restart.
9
- */
10
- import { type TunableDefaults } from "../runtime/config/tunable-defaults.js";
11
- /** Read the current override map from settings.json (missing file → empty). */
12
- export declare function readTunableOverrides(settingsPath: string): Record<string, unknown>;
13
- /**
14
- * Validate a tunable update against the declared defaults.
15
- * Returns an error message, or null when the update is acceptable.
16
- * Coercible values ("3" → 3, "true" → true) are NOT accepted here —
17
- * callers wanting leniency must coerce before validating.
18
- */
19
- export declare function validateTunableUpdate(key: string, value: unknown): string | null;
20
- /** Coerce a string value toward the tunable's declared type ("3"→3, "true"→true). */
21
- export declare function coerceTunableValue(key: string, value: unknown): unknown;
22
- /** Persist one override into settings.json and sync live runtime state. */
23
- export declare function writeTunableOverride(settingsPath: string, key: string, value: unknown): Promise<void>;
24
- /** Remove one override (value falls back to the declared default). */
25
- export declare function clearTunableOverride(settingsPath: string, key: string): Promise<void>;
26
- export type { TunableDefaults };
@@ -1,26 +0,0 @@
1
- /**
2
- * Settings watcher for canonical qlogicagent permission settings.
3
- *
4
- * Two layers (CC settings semantics):
5
- * - user level ~/.qlogicagent/profiles/<owner>/settings.json — where config.update persists
6
- * - project level <projectRoot>/.qlogicagent/settings.json — repo-local overrides
7
- * The project file's `permissions` object, when present, overrides the user file's.
8
- * Both layers are watched; either changing re-resolves the effective permissions.
9
- * (写读同源:此前 config.update 写用户级、watcher 只读项目级,重启后持久模式永远丢失。)
10
- *
11
- * Only the `permissions` object is accepted. Removed top-level aliases such as
12
- * `permissionMode`, `permissionRules`, and `defaultBehavior` must fail loudly.
13
- */
14
- import type { HookRegistry } from "../../contracts/hooks.js";
15
- import type { PermissionRuleEnginePort } from "../../runtime/ports/index.js";
16
- export interface SettingsFile {
17
- permissions?: unknown;
18
- }
19
- export interface SettingsWatcherDeps {
20
- projectRoot: string;
21
- ruleEngine: PermissionRuleEnginePort;
22
- hooks?: HookRegistry;
23
- log?: (msg: string) => void;
24
- }
25
- export declare function watchSettings(deps: SettingsWatcherDeps): () => void;
26
- export declare function loadInitialSettings(projectRoot: string, ruleEngine: PermissionRuleEnginePort): Promise<SettingsFile | null>;