@christang/keel 5.3.4 → 5.3.5
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "keel",
|
|
3
|
-
"version": "5.3.
|
|
3
|
+
"version": "5.3.5",
|
|
4
4
|
"description": "Keel OpenSpec execution discipline: stateless continuity, task capsules, deterministic gates, and expectation alignment for Codex and Claude Code.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "TanglmChris",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "keel",
|
|
3
|
-
"version": "5.3.
|
|
3
|
+
"version": "5.3.5",
|
|
4
4
|
"description": "Keel OpenSpec execution discipline: stateless continuity, task capsules, deterministic gates, and expectation alignment for Codex and Claude Code.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "TanglmChris",
|
|
@@ -37,10 +37,13 @@ REQUIRED_SCRIPTS = [
|
|
|
37
37
|
"scripts/validate_plugin.py",
|
|
38
38
|
]
|
|
39
39
|
|
|
40
|
-
PACKAGE_VERSION = "5.3.
|
|
41
|
-
PROTOCOL_VERSION = "5.3.
|
|
40
|
+
PACKAGE_VERSION = "5.3.5"
|
|
41
|
+
PROTOCOL_VERSION = "5.3.5"
|
|
42
42
|
LEGACY_MANAGED_START = "<!-- keel:start version=2.1 -->"
|
|
43
43
|
OPENSPEC_SCHEMA_NAME = "keel-spec-driven"
|
|
44
|
+
# Mirrors KEEL_PACKAGE_NAME in scripts/install_to_repo.py, one of the two
|
|
45
|
+
# signals is_keel_source_repo reads.
|
|
46
|
+
KEEL_PACKAGE_NAME = "@christang/keel"
|
|
44
47
|
OPENSPEC_CONFIG_PATH = Path("openspec/config.yaml")
|
|
45
48
|
OPENSPEC_SCHEMA_ROOT = Path("openspec/schemas") / OPENSPEC_SCHEMA_NAME
|
|
46
49
|
OPENSPEC_SURFACE_OVERLAY_START = (
|
|
@@ -417,6 +420,17 @@ def validate_npm_package(errors: list[str]) -> None:
|
|
|
417
420
|
# Path expressions rooted at a tree the retirement check above requires to be
|
|
418
421
|
# absent. `src/core` and `src/skills` are live, so only the retired `src`
|
|
419
422
|
# children are listed.
|
|
423
|
+
# Keel subcommands that write. A scenario may point read-only ones at the
|
|
424
|
+
# repository root; these need a fixture.
|
|
425
|
+
MUTATING_KEEL_COMMANDS = (
|
|
426
|
+
"--install",
|
|
427
|
+
"--init",
|
|
428
|
+
"--uninstall",
|
|
429
|
+
"--clear",
|
|
430
|
+
"--update",
|
|
431
|
+
"--with-git-hooks",
|
|
432
|
+
)
|
|
433
|
+
|
|
420
434
|
RETIRED_PATH_EXPRESSIONS = (
|
|
421
435
|
r'ROOT\s*/\s*"dist"',
|
|
422
436
|
r'ROOT\s*/\s*"src"\s*/\s*"assets"',
|
|
@@ -458,6 +472,29 @@ def validate_paths(errors: list[str]) -> None:
|
|
|
458
472
|
f"retired custom distribution path must be removed: {retired}"
|
|
459
473
|
)
|
|
460
474
|
|
|
475
|
+
validator_source = (ROOT / "scripts" / "validate_plugin.py").read_text(
|
|
476
|
+
encoding="utf-8"
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
# A scenario that writes to the repository it validates can satisfy the very
|
|
480
|
+
# condition another check asserts, and a check whose input its own run
|
|
481
|
+
# produces cannot fail. Reads against ROOT are fine and common; writes are
|
|
482
|
+
# not. Keyed on the mutating subcommand rather than on ROOT itself, so
|
|
483
|
+
# `--version`, `--doctor`, and the gates stay legal.
|
|
484
|
+
for line_number, line in enumerate(validator_source.splitlines(), start=1):
|
|
485
|
+
invocation = re.search(r"run_(?:keel|install)\(\s*ROOT\s*,([^)]*)", line)
|
|
486
|
+
if not invocation:
|
|
487
|
+
continue
|
|
488
|
+
if any(
|
|
489
|
+
re.search(rf'"{command}"', invocation.group(1))
|
|
490
|
+
for command in MUTATING_KEEL_COMMANDS
|
|
491
|
+
):
|
|
492
|
+
errors.append(
|
|
493
|
+
"a scenario must not run a mutating Keel command against the "
|
|
494
|
+
"repository it validates; build a fixture instead: "
|
|
495
|
+
f"scripts/validate_plugin.py:{line_number}: {line.strip()}"
|
|
496
|
+
)
|
|
497
|
+
|
|
461
498
|
# Every Keel marker that carries a version is a shipped claim about which
|
|
462
499
|
# version this is. Derive the set from the markers that exist rather than a
|
|
463
500
|
# fixed list, because a fixed list is the next thing to fall behind — which
|
|
@@ -484,9 +521,6 @@ def validate_paths(errors: list[str]) -> None:
|
|
|
484
521
|
# directory yields no error, so the check reports success forever. Naming a
|
|
485
522
|
# retired tree in a string literal is fine — that is how the checks above
|
|
486
523
|
# state what must not exist; building a Path into one is not.
|
|
487
|
-
validator_source = (ROOT / "scripts" / "validate_plugin.py").read_text(
|
|
488
|
-
encoding="utf-8"
|
|
489
|
-
)
|
|
490
524
|
for line_number, line in enumerate(validator_source.splitlines(), start=1):
|
|
491
525
|
if any(re.search(pattern, line) for pattern in RETIRED_PATH_EXPRESSIONS):
|
|
492
526
|
errors.append(
|
|
@@ -5004,29 +5038,56 @@ def validate_source_repo_bootstrap_skip_scenario() -> int:
|
|
|
5004
5038
|
found = managed.search(path.read_text(encoding="utf-8"))
|
|
5005
5039
|
return found.group(0) if found else ""
|
|
5006
5040
|
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5041
|
+
# `is_keel_source_repo` reads exactly two signals — the package name and a
|
|
5042
|
+
# plugins/keel directory — so a fixture carrying both exercises the same
|
|
5043
|
+
# branch. Running this against the real repository used to work and used to
|
|
5044
|
+
# rewrite the .claude/ overlay markers as a side effect, which is how the
|
|
5045
|
+
# marker check ended up green on that side for the wrong reason.
|
|
5046
|
+
if not (ROOT / "AGENTS.md").is_file() or not block(ROOT / "AGENTS.md"):
|
|
5010
5047
|
report("source-repo-bootstrap-skip: Keel's AGENTS.md has no managed block.")
|
|
5011
5048
|
return 1
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
)
|
|
5028
|
-
|
|
5029
|
-
|
|
5049
|
+
|
|
5050
|
+
with tempfile.TemporaryDirectory(prefix="keel-source-repo-") as raw:
|
|
5051
|
+
fixture = Path(raw) / "keel"
|
|
5052
|
+
write_text(fixture / "package.json", json.dumps({"name": KEEL_PACKAGE_NAME}))
|
|
5053
|
+
write_text(fixture / "plugins/keel/.keep", "")
|
|
5054
|
+
own_agents = fixture / "AGENTS.md"
|
|
5055
|
+
write_text(own_agents, (ROOT / "AGENTS.md").read_text(encoding="utf-8"))
|
|
5056
|
+
before_tree = snapshot_files(fixture)
|
|
5057
|
+
before = block(own_agents)
|
|
5058
|
+
|
|
5059
|
+
result = run_keel(fixture, "--install", "--target", "claude")
|
|
5060
|
+
if result.returncode != 0:
|
|
5061
|
+
report("source-repo-bootstrap-skip: keel --install failed in Keel's repo.")
|
|
5062
|
+
report((result.stderr or result.stdout).strip())
|
|
5063
|
+
return 1
|
|
5064
|
+
if block(own_agents) != before:
|
|
5065
|
+
report(
|
|
5066
|
+
"source-repo-bootstrap-skip: keel --install rewrote Keel's own "
|
|
5067
|
+
"AGENTS.md managed block."
|
|
5068
|
+
)
|
|
5069
|
+
return 1
|
|
5070
|
+
if "skip AGENTS.md" not in (result.stdout or ""):
|
|
5071
|
+
report(
|
|
5072
|
+
"source-repo-bootstrap-skip: the skip was silent; it must be "
|
|
5073
|
+
"reported explicitly."
|
|
5074
|
+
)
|
|
5075
|
+
report((result.stdout or "").strip())
|
|
5076
|
+
return 1
|
|
5077
|
+
# The original defect was the missing assertion, not only the wrong
|
|
5078
|
+
# repository: name what the install must not have rewritten.
|
|
5079
|
+
rewritten = [
|
|
5080
|
+
name
|
|
5081
|
+
for name, text in before_tree.items()
|
|
5082
|
+
if (fixture / name).is_file()
|
|
5083
|
+
and (fixture / name).read_text(encoding="utf-8") != text
|
|
5084
|
+
]
|
|
5085
|
+
if rewritten:
|
|
5086
|
+
report(
|
|
5087
|
+
"source-repo-bootstrap-skip: keel --install rewrote files it "
|
|
5088
|
+
"did not announce: " + ", ".join(sorted(rewritten))
|
|
5089
|
+
)
|
|
5090
|
+
return 1
|
|
5030
5091
|
# A consuming project must still receive the bootstrap.
|
|
5031
5092
|
with tempfile.TemporaryDirectory(prefix="keel-bootstrap-consumer-") as raw:
|
|
5032
5093
|
consumer = Path(raw)
|