@christang/keel 5.1.2 → 5.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +114 -158
- package/README.zh-CN.md +118 -197
- package/assets/bootstrap/AGENTS.md +1 -1
- package/{plugins/keel/skills/keel-align-expectations/references → assets/lenses}/hardware-dsl.md +4 -2
- package/{plugins/keel/skills/keel-align-expectations/references → assets/lenses}/hardware.md +4 -2
- package/{plugins/keel/skills/keel-align-expectations/references → assets/lenses}/web.md +4 -2
- package/assets/openspec/schemas/keel-spec-driven/schema.yaml +11 -5
- package/assets/openspec/schemas/keel-spec-driven/templates/design.md +1 -1
- package/assets/openspec/schemas/keel-spec-driven/templates/tasks.md +13 -4
- package/bin/keel.js +221 -18
- package/package.json +1 -1
- package/plugins/keel/.claude-plugin/plugin.json +1 -1
- package/plugins/keel/.codex-plugin/plugin.json +1 -1
- package/plugins/keel/skills/keel-align-expectations/SKILL.md +2 -6
- package/plugins/keel/skills/keel-debug-failure/SKILL.md +2 -2
- package/plugins/keel/skills/keel-review-checklist/SKILL.md +2 -2
- package/plugins/keel/skills/keel-tdd-or-test-first/SKILL.md +2 -2
- package/scripts/bump_version.js +140 -0
- package/scripts/install_to_repo.py +3 -73
- package/scripts/validate_plugin.py +558 -107
- package/src/core/context.js +10 -3
- package/src/core/gates.js +40 -10
- package/src/core/task-contract.js +21 -0
|
@@ -51,23 +51,11 @@ KEEL_HOOK_NAME = "keel-gate"
|
|
|
51
51
|
KEEL_HOOK_ROOT = Path(".claude") / "hooks" / KEEL_HOOK_NAME
|
|
52
52
|
SUPPORTED_TARGETS = ("claude", "codex", "opencode")
|
|
53
53
|
AGENT_PROTOCOL_TARGETS = {"codex", "opencode"}
|
|
54
|
-
TARGET_SKILL_ROOTS = {
|
|
55
|
-
"claude": Path(".claude") / "skills",
|
|
56
|
-
"codex": Path(".agents") / "skills",
|
|
57
|
-
"opencode": Path(".opencode") / "skills",
|
|
58
|
-
}
|
|
59
54
|
TARGET_ADAPTER_PATHS = {
|
|
60
55
|
"claude": Path(".claude") / "keel" / "keel-adapter.js",
|
|
61
56
|
"codex": Path(".agents") / "keel" / "keel-adapter.js",
|
|
62
57
|
"opencode": Path(".opencode") / "keel" / "keel-adapter.js",
|
|
63
58
|
}
|
|
64
|
-
CORE_KEEL_SKILLS = {
|
|
65
|
-
"keel-align-expectations",
|
|
66
|
-
"keel-debug-failure",
|
|
67
|
-
"keel-handoff",
|
|
68
|
-
"keel-review-checklist",
|
|
69
|
-
"keel-tdd-or-test-first",
|
|
70
|
-
}
|
|
71
59
|
HANDOFF_FIELDS = {"schema", "owner", "action", "reason"}
|
|
72
60
|
HANDOFF_ACTIONS = {
|
|
73
61
|
"discuss",
|
|
@@ -158,10 +146,6 @@ def target_set(target: str) -> set[str]:
|
|
|
158
146
|
return set(target_names(target))
|
|
159
147
|
|
|
160
148
|
|
|
161
|
-
def core_skill_names() -> set[str]:
|
|
162
|
-
return set(CORE_KEEL_SKILLS)
|
|
163
|
-
|
|
164
|
-
|
|
165
149
|
def file_action(relative_path: str, source_path: Path) -> InstallAction:
|
|
166
150
|
if not source_path.is_file():
|
|
167
151
|
raise ValueError(f"missing packaged asset: {source_path}")
|
|
@@ -233,31 +217,6 @@ def openspec_schema_actions() -> list[InstallAction]:
|
|
|
233
217
|
return actions
|
|
234
218
|
|
|
235
219
|
|
|
236
|
-
def skill_actions(target: str) -> list[InstallAction]:
|
|
237
|
-
actions: list[InstallAction] = []
|
|
238
|
-
selected_skill_names = core_skill_names()
|
|
239
|
-
for target_name in target_names(target):
|
|
240
|
-
skill_destination_root = TARGET_SKILL_ROOTS[target_name]
|
|
241
|
-
skills_root = dist_asset(target_name, "skills")
|
|
242
|
-
if skills_root.is_dir():
|
|
243
|
-
for skill in sorted(skills_root.iterdir()):
|
|
244
|
-
if not skill.is_dir():
|
|
245
|
-
continue
|
|
246
|
-
if skill.name not in selected_skill_names:
|
|
247
|
-
continue
|
|
248
|
-
for skill_file in sorted(skill.rglob("*")):
|
|
249
|
-
if not skill_file.is_file():
|
|
250
|
-
continue
|
|
251
|
-
relative_file = skill_file.relative_to(skill).as_posix()
|
|
252
|
-
actions.append(
|
|
253
|
-
file_action(
|
|
254
|
-
(skill_destination_root / skill.name / relative_file).as_posix(),
|
|
255
|
-
skill_file,
|
|
256
|
-
)
|
|
257
|
-
)
|
|
258
|
-
return actions
|
|
259
|
-
|
|
260
|
-
|
|
261
220
|
def agent_actions(target: str) -> list[InstallAction]:
|
|
262
221
|
actions: list[InstallAction] = []
|
|
263
222
|
if "claude" not in target_set(target):
|
|
@@ -945,35 +904,6 @@ def rmdir_if_empty_action(relative_dir: str) -> PlannedAction:
|
|
|
945
904
|
return PlannedAction("rmdir", Path(relative_dir))
|
|
946
905
|
|
|
947
906
|
|
|
948
|
-
def plan_uninstall_skill_actions(repo: Path, target: str) -> list[PlannedAction]:
|
|
949
|
-
actions: list[PlannedAction] = []
|
|
950
|
-
for target_name in target_names(target):
|
|
951
|
-
skill_root = TARGET_SKILL_ROOTS[target_name]
|
|
952
|
-
target_actions = skill_actions(target_name)
|
|
953
|
-
for action in target_actions:
|
|
954
|
-
if action.source_path is None:
|
|
955
|
-
continue
|
|
956
|
-
actions.append(
|
|
957
|
-
plan_uninstall_packaged_file(
|
|
958
|
-
repo,
|
|
959
|
-
action.relative_path.as_posix(),
|
|
960
|
-
action.source_path,
|
|
961
|
-
)
|
|
962
|
-
)
|
|
963
|
-
|
|
964
|
-
skill_dirs: set[Path] = set()
|
|
965
|
-
for action in target_actions:
|
|
966
|
-
parent = action.relative_path.parent
|
|
967
|
-
while parent != skill_root:
|
|
968
|
-
skill_dirs.add(parent)
|
|
969
|
-
parent = parent.parent
|
|
970
|
-
for skill_dir in sorted(skill_dirs, key=lambda path: len(path.parts), reverse=True):
|
|
971
|
-
actions.append(rmdir_if_empty_action(skill_dir.as_posix()))
|
|
972
|
-
actions.append(rmdir_if_empty_action(skill_root.as_posix()))
|
|
973
|
-
actions.append(rmdir_if_empty_action(skill_root.parent.as_posix()))
|
|
974
|
-
return actions
|
|
975
|
-
|
|
976
|
-
|
|
977
907
|
def plan_uninstall_agent_actions(repo: Path, target: str) -> list[PlannedAction]:
|
|
978
908
|
actions: list[PlannedAction] = []
|
|
979
909
|
if "claude" not in target_set(target):
|
|
@@ -1080,7 +1010,7 @@ def main() -> int:
|
|
|
1080
1010
|
parser.add_argument(
|
|
1081
1011
|
"--profile",
|
|
1082
1012
|
action="append",
|
|
1083
|
-
help="Obsolete
|
|
1013
|
+
help="Obsolete; domain guidance is now user-authored lenses in keel/lenses/*.md.",
|
|
1084
1014
|
)
|
|
1085
1015
|
args = parser.parse_args()
|
|
1086
1016
|
|
|
@@ -1089,8 +1019,8 @@ def main() -> int:
|
|
|
1089
1019
|
if args.profile:
|
|
1090
1020
|
print(
|
|
1091
1021
|
"Install failed: --profile is no longer supported; web, hardware, "
|
|
1092
|
-
"and hardware-dsl guidance is
|
|
1093
|
-
"keel
|
|
1022
|
+
"and hardware-dsl guidance is now user-authored lenses in "
|
|
1023
|
+
"keel/lenses/*.md (scaffold with `keel lenses add`)",
|
|
1094
1024
|
file=sys.stderr,
|
|
1095
1025
|
)
|
|
1096
1026
|
return 1
|