@christang/keel 5.1.2 → 5.2.0
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/tasks.md +13 -4
- package/bin/keel.js +218 -15
- 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 +0 -70
- package/scripts/validate_plugin.py +408 -96
- package/src/core/context.js +10 -3
- package/src/core/gates.js +30 -9
- package/src/core/task-contract.js +21 -0
package/src/core/context.js
CHANGED
|
@@ -5,7 +5,12 @@
|
|
|
5
5
|
const fs = require("fs");
|
|
6
6
|
const path = require("path");
|
|
7
7
|
const { spawnSync } = require("child_process");
|
|
8
|
-
const {
|
|
8
|
+
const {
|
|
9
|
+
ACCEPTED_REVIEW_STATUSES,
|
|
10
|
+
compileTaskContract,
|
|
11
|
+
field,
|
|
12
|
+
parseTasks,
|
|
13
|
+
} = require("./task-contract");
|
|
9
14
|
|
|
10
15
|
const NEXT_ACTIONS = new Set([
|
|
11
16
|
"discuss",
|
|
@@ -68,8 +73,10 @@ function taskHasCompletionEvidence(record, contract) {
|
|
|
68
73
|
(match) => match[1]
|
|
69
74
|
)
|
|
70
75
|
);
|
|
71
|
-
const reviewPassed =
|
|
72
|
-
|
|
76
|
+
const reviewPassed = new RegExp(
|
|
77
|
+
`^\\s*-\\s*Status:\\s*(?:${ACCEPTED_REVIEW_STATUSES.join("|")})\\s*$`,
|
|
78
|
+
"im"
|
|
79
|
+
).test(evidence);
|
|
73
80
|
return (
|
|
74
81
|
commandIds.length > 0
|
|
75
82
|
&& commandIds.every((commandId) => evidenceIds.has(commandId))
|
package/src/core/gates.js
CHANGED
|
@@ -6,10 +6,12 @@ const fs = require("fs");
|
|
|
6
6
|
const path = require("path");
|
|
7
7
|
const { spawnSync } = require("child_process");
|
|
8
8
|
const {
|
|
9
|
+
ACCEPTED_REVIEW_STATUSES,
|
|
9
10
|
RED_GREEN_VERIFICATION_STRATEGIES,
|
|
10
11
|
compileTaskContract,
|
|
11
12
|
field,
|
|
12
13
|
isConcrete,
|
|
14
|
+
isPassingReviewStatus,
|
|
13
15
|
parseTasks,
|
|
14
16
|
} = require("./task-contract");
|
|
15
17
|
const { startGuard } = require("./guard");
|
|
@@ -376,16 +378,29 @@ function completionChecks(repo, task, contract = null) {
|
|
|
376
378
|
: [["Findings", reviewFields.Findings]]
|
|
377
379
|
),
|
|
378
380
|
];
|
|
379
|
-
const reviewPassed =
|
|
380
|
-
reviewFields.Status
|
|
381
|
-
);
|
|
381
|
+
const reviewPassed = isPassingReviewStatus(reviewFields.Status);
|
|
382
382
|
const reviewProblems = [];
|
|
383
383
|
if (reviewMissing.length > 0 || !reviewPassed) {
|
|
384
|
+
const details = [];
|
|
385
|
+
if (!reviewPassed) {
|
|
386
|
+
const got = isConcrete(reviewFields.Status)
|
|
387
|
+
? ` (got "${String(reviewFields.Status).trim()}")`
|
|
388
|
+
: "";
|
|
389
|
+
details.push(
|
|
390
|
+
`Status must be one of ${ACCEPTED_REVIEW_STATUSES.join(", ")}${got}`
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
const otherMissing = reviewMissing.filter(([name]) => name !== "Status");
|
|
394
|
+
if (otherMissing.length > 0) {
|
|
395
|
+
details.push(
|
|
396
|
+
"these Review fields need concrete Evidence: "
|
|
397
|
+
+ otherMissing.map(([name]) => name).join(", ")
|
|
398
|
+
);
|
|
399
|
+
}
|
|
384
400
|
reviewProblems.push(
|
|
385
401
|
problem(
|
|
386
402
|
"semantic-review",
|
|
387
|
-
|
|
388
|
-
+ "Scope check, and Findings."
|
|
403
|
+
`Current-agent Review is incomplete — ${details.join("; ")}.`
|
|
389
404
|
)
|
|
390
405
|
);
|
|
391
406
|
} else if (
|
|
@@ -395,8 +410,10 @@ function completionChecks(repo, task, contract = null) {
|
|
|
395
410
|
problems.push(
|
|
396
411
|
problem(
|
|
397
412
|
"finding-owner",
|
|
398
|
-
"Review
|
|
399
|
-
+ "
|
|
413
|
+
"Review Findings must be `none` or carry a durable owner — a "
|
|
414
|
+
+ "`Discard reason:`/`Discard rationale:` prefix, a `keel/archive/…` "
|
|
415
|
+
+ "path, or an existing `openspec/changes/…` artifact; "
|
|
416
|
+
+ "`keel/HANDOFF.md` is not an owner."
|
|
400
417
|
)
|
|
401
418
|
);
|
|
402
419
|
}
|
|
@@ -441,7 +458,9 @@ function expectationProblems(content, tasks) {
|
|
|
441
458
|
return [
|
|
442
459
|
problem(
|
|
443
460
|
"expectation-coverage",
|
|
444
|
-
"tasks.md requires
|
|
461
|
+
"tasks.md requires a `## Expectation Coverage` section: one "
|
|
462
|
+
+ "`- E<n>: <expectation> Covered by: <task ids>` line per "
|
|
463
|
+
+ "expectation, or `- None.`."
|
|
445
464
|
),
|
|
446
465
|
];
|
|
447
466
|
}
|
|
@@ -459,7 +478,9 @@ function expectationProblems(content, tasks) {
|
|
|
459
478
|
return [
|
|
460
479
|
problem(
|
|
461
480
|
"expectation-coverage",
|
|
462
|
-
"Expectation Coverage must declare each E<n
|
|
481
|
+
"Expectation Coverage must declare each `E<n>` closure — "
|
|
482
|
+
+ "`- E<n>: <expectation> Covered by: <task ids>`, a `Durable owner:` "
|
|
483
|
+
+ "path, or a `Discard reason:` — or `- None.`."
|
|
463
484
|
),
|
|
464
485
|
];
|
|
465
486
|
}
|
|
@@ -97,6 +97,25 @@ const RED_GREEN_VERIFICATION_STRATEGIES = new Set([
|
|
|
97
97
|
"regression-first",
|
|
98
98
|
]);
|
|
99
99
|
|
|
100
|
+
// Single source of truth for the accepted completion Review `Status`
|
|
101
|
+
// vocabulary. Consumed by both the completion gate (src/core/gates.js) and the
|
|
102
|
+
// context "already reviewed" probe (src/core/context.js) so the two never
|
|
103
|
+
// diverge.
|
|
104
|
+
const ACCEPTED_REVIEW_STATUSES = [
|
|
105
|
+
"pass",
|
|
106
|
+
"passed",
|
|
107
|
+
"complete",
|
|
108
|
+
"completed",
|
|
109
|
+
"ok",
|
|
110
|
+
"done",
|
|
111
|
+
];
|
|
112
|
+
|
|
113
|
+
function isPassingReviewStatus(value) {
|
|
114
|
+
return ACCEPTED_REVIEW_STATUSES.includes(
|
|
115
|
+
String(value == null ? "" : value).trim().toLowerCase()
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
100
119
|
function verification(task) {
|
|
101
120
|
const compact = fieldValues(task, "Verify");
|
|
102
121
|
const strategyEntry = compact.find((entry) => /^Strategy:\s*/i.test(entry));
|
|
@@ -725,11 +744,13 @@ function loadTaskContract(repo, change, taskId) {
|
|
|
725
744
|
}
|
|
726
745
|
|
|
727
746
|
module.exports = {
|
|
747
|
+
ACCEPTED_REVIEW_STATUSES,
|
|
728
748
|
RED_GREEN_VERIFICATION_STRATEGIES,
|
|
729
749
|
SUPPORTED_VERIFICATION_STRATEGIES,
|
|
730
750
|
compileTaskContract,
|
|
731
751
|
field,
|
|
732
752
|
isConcrete,
|
|
753
|
+
isPassingReviewStatus,
|
|
733
754
|
loadTaskContract,
|
|
734
755
|
parseTasks,
|
|
735
756
|
taskStartContractProblems,
|