@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
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");
|
|
@@ -235,7 +237,16 @@ function gitPaths(repo) {
|
|
|
235
237
|
return status.stdout
|
|
236
238
|
.split(/\r?\n/)
|
|
237
239
|
.filter(Boolean)
|
|
238
|
-
.
|
|
240
|
+
.flatMap((line) => {
|
|
241
|
+
// A staged rename/copy is one porcelain line, `R old -> new`; attribute
|
|
242
|
+
// both endpoints so a rename whose old and new paths are in Touch is not
|
|
243
|
+
// a false outside-Touch failure. Every other line carries one path.
|
|
244
|
+
const entry = line.slice(3).trim().replace(/\\/g, "/");
|
|
245
|
+
const arrow = entry.indexOf(" -> ");
|
|
246
|
+
return arrow === -1
|
|
247
|
+
? [entry]
|
|
248
|
+
: [entry.slice(0, arrow), entry.slice(arrow + 4)];
|
|
249
|
+
});
|
|
239
250
|
}
|
|
240
251
|
|
|
241
252
|
function touchEntries(task, contract = null) {
|
|
@@ -376,16 +387,29 @@ function completionChecks(repo, task, contract = null) {
|
|
|
376
387
|
: [["Findings", reviewFields.Findings]]
|
|
377
388
|
),
|
|
378
389
|
];
|
|
379
|
-
const reviewPassed =
|
|
380
|
-
reviewFields.Status
|
|
381
|
-
);
|
|
390
|
+
const reviewPassed = isPassingReviewStatus(reviewFields.Status);
|
|
382
391
|
const reviewProblems = [];
|
|
383
392
|
if (reviewMissing.length > 0 || !reviewPassed) {
|
|
393
|
+
const details = [];
|
|
394
|
+
if (!reviewPassed) {
|
|
395
|
+
const got = isConcrete(reviewFields.Status)
|
|
396
|
+
? ` (got "${String(reviewFields.Status).trim()}")`
|
|
397
|
+
: "";
|
|
398
|
+
details.push(
|
|
399
|
+
`Status must be one of ${ACCEPTED_REVIEW_STATUSES.join(", ")}${got}`
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
const otherMissing = reviewMissing.filter(([name]) => name !== "Status");
|
|
403
|
+
if (otherMissing.length > 0) {
|
|
404
|
+
details.push(
|
|
405
|
+
"these Review fields need concrete Evidence: "
|
|
406
|
+
+ otherMissing.map(([name]) => name).join(", ")
|
|
407
|
+
);
|
|
408
|
+
}
|
|
384
409
|
reviewProblems.push(
|
|
385
410
|
problem(
|
|
386
411
|
"semantic-review",
|
|
387
|
-
|
|
388
|
-
+ "Scope check, and Findings."
|
|
412
|
+
`Current-agent Review is incomplete — ${details.join("; ")}.`
|
|
389
413
|
)
|
|
390
414
|
);
|
|
391
415
|
} else if (
|
|
@@ -395,8 +419,10 @@ function completionChecks(repo, task, contract = null) {
|
|
|
395
419
|
problems.push(
|
|
396
420
|
problem(
|
|
397
421
|
"finding-owner",
|
|
398
|
-
"Review
|
|
399
|
-
+ "
|
|
422
|
+
"Review Findings must be `none` or carry a durable owner — a "
|
|
423
|
+
+ "`Discard reason:`/`Discard rationale:` prefix, a `keel/archive/…` "
|
|
424
|
+
+ "path, or an existing `openspec/changes/…` artifact; "
|
|
425
|
+
+ "`keel/HANDOFF.md` is not an owner."
|
|
400
426
|
)
|
|
401
427
|
);
|
|
402
428
|
}
|
|
@@ -441,7 +467,9 @@ function expectationProblems(content, tasks) {
|
|
|
441
467
|
return [
|
|
442
468
|
problem(
|
|
443
469
|
"expectation-coverage",
|
|
444
|
-
"tasks.md requires
|
|
470
|
+
"tasks.md requires a `## Expectation Coverage` section: one "
|
|
471
|
+
+ "`- E<n>: <expectation> Covered by: <task ids>` line per "
|
|
472
|
+
+ "expectation, or `- None.`."
|
|
445
473
|
),
|
|
446
474
|
];
|
|
447
475
|
}
|
|
@@ -459,7 +487,9 @@ function expectationProblems(content, tasks) {
|
|
|
459
487
|
return [
|
|
460
488
|
problem(
|
|
461
489
|
"expectation-coverage",
|
|
462
|
-
"Expectation Coverage must declare each E<n
|
|
490
|
+
"Expectation Coverage must declare each `E<n>` closure — "
|
|
491
|
+
+ "`- E<n>: <expectation> Covered by: <task ids>`, a `Durable owner:` "
|
|
492
|
+
+ "path, or a `Discard reason:` — or `- None.`."
|
|
463
493
|
),
|
|
464
494
|
];
|
|
465
495
|
}
|
|
@@ -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,
|