@christang/keel 5.2.2 → 5.2.4

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.
@@ -1,4 +1,4 @@
1
- <!-- keel:start version=5.2.2 -->
1
+ <!-- keel:start version=5.2.4 -->
2
2
  ## Keel Bootstrap
3
3
 
4
4
  - Start every session with `keel context`; OpenSpec artifacts and Git are the only durable authority — never native memory, goals, or transcripts.
package/bin/keel.js CHANGED
@@ -15,6 +15,7 @@ const {
15
15
  runGate,
16
16
  } = require("../src/core/gates");
17
17
  const {
18
+ isKeelSourceRepo,
18
19
  probeCapabilities,
19
20
  renderCapabilities,
20
21
  } = require("../src/core/capabilities");
@@ -1202,7 +1203,12 @@ function printTargetSurface(repo, target) {
1202
1203
  sourceDetail = `plugin source unreadable at ${manifestRelative}`;
1203
1204
  }
1204
1205
  }
1205
- printDoctorLine("native plugin source", sourceStatus, sourceDetail);
1206
+ // Development-only check: plugins/keel/ exists only in Keel's own source
1207
+ // repository, so in a consuming project it is permanently `missing` and
1208
+ // there is nothing the author can do about it.
1209
+ if (isKeelSourceRepo(repo)) {
1210
+ printDoctorLine("native plugin source", sourceStatus, sourceDetail);
1211
+ }
1206
1212
  printDoctorLine(
1207
1213
  "native plugin runtime",
1208
1214
  "manual",
@@ -1229,7 +1235,12 @@ function printTargetSurface(repo, target) {
1229
1235
  printDoctorLine(
1230
1236
  "Keel behavioral skills",
1231
1237
  "plugin",
1232
- "keel-* skills are delivered by the installed Keel plugin (see native plugin status above); install the plugin if it is missing"
1238
+ isKeelSourceRepo(repo)
1239
+ ? "keel-* skills are delivered by the installed Keel plugin (see native "
1240
+ + "plugin status above); install the plugin if it is missing"
1241
+ : "keel-* skills are delivered by the installed Keel plugin; verify it "
1242
+ + "with the runtime's own plugin listing, since Keel cannot observe "
1243
+ + "installation from this repository"
1233
1244
  );
1234
1245
 
1235
1246
  const commands = commandSurfaceForTarget(target, repo);
@@ -1333,10 +1344,28 @@ function runDoctor(options) {
1333
1344
  printTargetSurface(repo, options.target);
1334
1345
  printLensSurface(repo, options.target);
1335
1346
  printFastPrePushSurface(repo);
1347
+ printSourceRepoCliResolution(repo);
1336
1348
 
1337
1349
  return checkStatus;
1338
1350
  }
1339
1351
 
1352
+ // Only meaningful in Keel's own repository: a bare `keel` resolves to the
1353
+ // installed package, so gate commands verify the released CLI rather than the
1354
+ // working tree. The failure mode is a silently stale result, not an error, so
1355
+ // it is worth stating rather than leaving to be discovered.
1356
+ function printSourceRepoCliResolution(repo) {
1357
+ if (!isKeelSourceRepo(repo)) return;
1358
+ process.stdout.write("\nKeel source repository:\n");
1359
+ printDoctorLine(
1360
+ "gate CLI resolution",
1361
+ "advisory",
1362
+ "a bare `keel` runs the installed package, so gate results will not "
1363
+ + "reflect uncommitted changes to gate, contract, or capability code; "
1364
+ + "run `node bin/keel.js gate <stage> . --change <c> --task <t>` "
1365
+ + "instead — the repository argument is required"
1366
+ );
1367
+ }
1368
+
1340
1369
  function readFastCheck(repo) {
1341
1370
  const configPath = path.join(repo, "keel", "config.yaml");
1342
1371
  if (!fs.existsSync(configPath)) return null;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@christang/keel",
3
3
  "displayName": "Keel",
4
4
  "description": "Keel OpenSpec execution discipline CLI for Claude Code, Codex, and OpenCode.",
5
- "version": "5.2.2",
5
+ "version": "5.2.4",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keel",
3
- "version": "5.2.2",
3
+ "version": "5.2.4",
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.2.2",
3
+ "version": "5.2.4",
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",
@@ -33,6 +33,14 @@ KEEL_CONFIG_TEMPLATE = (
33
33
  "# Example:\n"
34
34
  "# fast_check: npm test -- --fast\n"
35
35
  )
36
+ KEEL_GITIGNORE_PATH = KEEL_ROOT / ".gitignore"
37
+ KEEL_GITIGNORE_TEMPLATE = (
38
+ "# Keel local state. keel/ otherwise holds project content that belongs in\n"
39
+ "# version control (config.yaml, CHANGELOG.md, archive/); the write-guard\n"
40
+ "# manifest is per-clone session state that a gate run writes and\n"
41
+ "# `keel guard clear` removes.\n"
42
+ "guard.json\n"
43
+ )
36
44
  GITHOOKS_DIR = ".githooks"
37
45
  PRE_PUSH_PATH = Path(GITHOOKS_DIR) / "pre-push"
38
46
  OPENSPEC_ROOT = Path("openspec")
@@ -222,6 +230,14 @@ def keel_config_action() -> InstallAction:
222
230
  )
223
231
 
224
232
 
233
+ def keel_gitignore_action() -> InstallAction:
234
+ return InstallAction(
235
+ relative_path=KEEL_GITIGNORE_PATH,
236
+ content=KEEL_GITIGNORE_TEMPLATE,
237
+ strategy="keel-config-scaffold",
238
+ )
239
+
240
+
225
241
  def read_fast_check(repo: Path) -> str | None:
226
242
  """Return the project's declared fast inner-loop command, or None.
227
243
 
@@ -432,11 +448,38 @@ def unmanaged_keel_content_warning(repo: Path, relative_path: str) -> bool:
432
448
  return False
433
449
 
434
450
 
451
+ KEEL_PACKAGE_NAME = "@christang/keel"
452
+
453
+
454
+ def is_keel_source_repo(repo: Path) -> bool:
455
+ """Whether `repo` is Keel's own source repository.
456
+
457
+ Mirrors `isKeelSourceRepo` in src/core/capabilities.js. Both signals are
458
+ required so a project that merely vendors a plugins/keel/ directory is not
459
+ misclassified as Keel's own source.
460
+ """
461
+ try:
462
+ manifest = json.loads((repo / "package.json").read_text(encoding="utf-8"))
463
+ except (OSError, ValueError):
464
+ return False
465
+ if manifest.get("name") != KEEL_PACKAGE_NAME:
466
+ return False
467
+ return (repo / "plugins" / "keel").is_dir()
468
+
469
+
435
470
  def collect_actions(repo: Path, target: str) -> list[InstallAction]:
436
471
  actions: list[InstallAction] = []
437
472
  targets = target_set(target)
438
473
 
439
- if not unmanaged_keel_content_warning(repo, "AGENTS.md"):
474
+ # Keel's own AGENTS.md carries the full protocol that the validation suite
475
+ # asserts on; the packaged bootstrap is the shorter consumer-facing text.
476
+ # Writing it here replaces the protocol and turns the repository red.
477
+ if is_keel_source_repo(repo):
478
+ print(
479
+ "skip AGENTS.md: Keel source repository, whose AGENTS.md carries "
480
+ "the full protocol; the consumer bootstrap is not written here"
481
+ )
482
+ elif not unmanaged_keel_content_warning(repo, "AGENTS.md"):
440
483
  actions.append(
441
484
  managed_file_action("AGENTS.md", PACKAGE_ROOT / BOOTSTRAP_ASSET)
442
485
  )
@@ -445,6 +488,7 @@ def collect_actions(repo: Path, target: str) -> list[InstallAction]:
445
488
 
446
489
  actions.append(openspec_config_action())
447
490
  actions.append(keel_config_action())
491
+ actions.append(keel_gitignore_action())
448
492
  actions.extend(openspec_schema_actions())
449
493
  return actions
450
494