@christang/keel 5.3.3 → 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/assets/bootstrap/AGENTS.md +2 -2
- package/assets/openspec/schemas/keel-spec-driven/schema.yaml +16 -4
- package/assets/openspec/schemas/keel-spec-driven/templates/tasks.md +16 -9
- package/package.json +1 -1
- package/plugins/keel/.claude-plugin/plugin.json +1 -1
- package/plugins/keel/.codex-plugin/plugin.json +1 -1
- package/scripts/bump_version.js +46 -8
- package/scripts/validate_plugin.py +753 -123
- package/src/core/gates.js +110 -38
- package/src/core/task-contract.js +62 -16
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
<!-- keel:start version=5.3.
|
|
1
|
+
<!-- keel:start version=5.3.5 -->
|
|
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.
|
|
5
|
-
- Obey the selected task capsule: `keel gate task-start` before implementing, record its fingerprint in Evidence `Contract`, and pass `keel gate task-complete` before checking complete. Touch
|
|
5
|
+
- Obey the selected task capsule: `keel gate task-start` before implementing, record its fingerprint in Evidence `Contract`, and pass `keel gate task-complete` before checking complete. Touch bounds product writes; the change's own dir is exempt. On Claude a passing `task-start` guards it by default (`--no-guard` opts out).
|
|
6
6
|
- One current agent owns writes; helpers return read-only report/evidence only. No commit, sync, or archive without explicit authorization.
|
|
7
7
|
- Native plugin projections (SessionStart context) are disposable views, never authority; without the plugin or hook, run the commands manually.
|
|
8
8
|
- Keel skills and hooks come from the `keel` native plugin (`codex plugin add` / `claude plugin install`); `keel --init` owns only the OpenSpec schema, overlays, and this bootstrap.
|
|
@@ -93,8 +93,15 @@ artifacts:
|
|
|
93
93
|
Verify selects the least-cost strategy that still proves the resolved
|
|
94
94
|
Acceptance: vertical-tdd, regression-first, characterization,
|
|
95
95
|
snapshot-characterization, rendered-behavior, or evidence-first.
|
|
96
|
-
Red-green strategies record per-label `.red` and `.green` Evidence
|
|
97
|
-
the
|
|
96
|
+
Red-green strategies record per-label `.red` and `.green` Evidence in
|
|
97
|
+
addition to the bare `M<n>` Evidence, which is always required; all three
|
|
98
|
+
must be concrete before completion. An `M<n>` may carry a comma-separated
|
|
99
|
+
tag set after its label, drawn from `fast`, `full`, and `regression`.
|
|
100
|
+
`fast`/`full` marks which checks the fast inner-loop pre-push runs.
|
|
101
|
+
`regression` marks a check asserting that something already green stays
|
|
102
|
+
green: it has no honest red, so it is exempt from `.red`/`.green` while
|
|
103
|
+
still needing its bare `M<n>` Evidence, and a red-green strategy must keep
|
|
104
|
+
at least one check untagged.
|
|
98
105
|
The Task Authoring Gate requires every relevant critical expectation to
|
|
99
106
|
be covered by a slice, deferred to a durable owner, or explicitly
|
|
100
107
|
discarded with rationale before the slice can be selected for execution.
|
|
@@ -137,14 +144,19 @@ artifacts:
|
|
|
137
144
|
Review with Status, Acceptance check, Scope check, and Findings. Status is
|
|
138
145
|
one of pass, passed, complete, completed, ok, or done. Findings
|
|
139
146
|
are `none` or carry a durable owner — a `Discard reason:`/`Discard
|
|
140
|
-
rationale:` prefix,
|
|
141
|
-
|
|
147
|
+
rationale:` prefix, an absolute `https://…` reference, or any
|
|
148
|
+
repo-relative path that exists, named after `Durable owner:` so it reads
|
|
149
|
+
as the owner rather than a file the finding mentions;
|
|
150
|
+
`keel/HANDOFF.md` is never the owner.
|
|
142
151
|
tasks.md carries two change-level sections beside its tasks.
|
|
143
152
|
`## Invalidates` is required by task-start, before any task of the
|
|
144
153
|
change runs: one `- I<n>: "the wording that is now wrong" — where it lives.`
|
|
145
154
|
line per statement this change makes stale, closed by `Updated by: <task
|
|
146
155
|
ids>` naming tasks of this change, a `Durable owner:`, or a `Discard
|
|
147
156
|
reason:`, or `- None.` when the change makes no existing statement wrong.
|
|
157
|
+
A `Durable owner:` is an absolute `https://…` reference or any
|
|
158
|
+
repo-relative path that exists; a path with no file behind it is refused,
|
|
159
|
+
and `keel/HANDOFF.md` is a pointer override rather than an owner.
|
|
148
160
|
Quote the wording a reader would search for rather than only listing
|
|
149
161
|
files, because the text that goes stale is the text the author was not
|
|
150
162
|
already holding in mind; naming it while tasks are authored is what lets
|
|
@@ -20,10 +20,16 @@
|
|
|
20
20
|
rendered-behavior, or evidence-first. Each M<n> check must prove the
|
|
21
21
|
resolved Acceptance through the public interface, not build-only or
|
|
22
22
|
shape-only evidence. Red-green strategies record per-label `.red` and
|
|
23
|
-
`.green` Evidence entries
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
`.green` Evidence entries IN ADDITION TO the bare `M<n>` entry, which
|
|
24
|
+
is always required; all three must be concrete before completion.
|
|
25
|
+
An M<n> check may carry an optional comma-separated tag set after its
|
|
26
|
+
label, drawn from fast, full, and regression (e.g. `M1 (fast): …`,
|
|
27
|
+
`M2 (regression): …`, `M3 (fast, regression): …`). fast/full marks
|
|
28
|
+
which checks the fast inner-loop pre-push runs; an untagged check is
|
|
29
|
+
full. regression marks a check that asserts something already green
|
|
30
|
+
stays green: it has no honest red, so it is exempt from `.red`/`.green`
|
|
31
|
+
but still needs its bare `M<n>` Evidence, and a red-green strategy must
|
|
32
|
+
keep at least one check untagged. change-close still needs every
|
|
27
33
|
M<n>'s Evidence. -->
|
|
28
34
|
- Strategy: <strategy>
|
|
29
35
|
- M1: <public behavior check>
|
|
@@ -32,7 +38,7 @@
|
|
|
32
38
|
- M1: pending
|
|
33
39
|
- Review:
|
|
34
40
|
<!-- Status: one of pass, passed, complete, completed, ok, done -->
|
|
35
|
-
<!-- Findings: none, or carry a durable owner — a "Discard reason:"/"Discard rationale:" prefix,
|
|
41
|
+
<!-- Findings: none, or carry a durable owner — a "Discard reason:"/"Discard rationale:" prefix, an absolute https://… reference, or any repo-relative path that exists (keel/archive/…, an openspec/changes/… artifact, or the repository's own ledger) named after "Durable owner:"; not keel/HANDOFF.md, which is a pointer override -->
|
|
36
42
|
- Status: pending
|
|
37
43
|
- Acceptance check: pending
|
|
38
44
|
- Scope check: pending
|
|
@@ -84,8 +90,9 @@
|
|
|
84
90
|
Each entry quotes the wording a reader would SEARCH for — not just the
|
|
85
91
|
files you already remembered, because the text that goes stale is the text
|
|
86
92
|
you were not thinking about — then says where it lives, then closes:
|
|
87
|
-
`Updated by: 1.1` (tasks of this change), `Durable owner: <url or path
|
|
88
|
-
|
|
93
|
+
`Updated by: 1.1` (tasks of this change), `Durable owner: <url or path>`
|
|
94
|
+
— an absolute https:// reference, or any repo-relative path that exists;
|
|
95
|
+
keel/HANDOFF.md is refused — or `Discard reason: why it stands`. Use `- None.` when this change makes
|
|
89
96
|
no existing statement wrong.
|
|
90
97
|
|
|
91
98
|
- I1: "the exact wording that is now wrong" — where that wording lives. Updated by: 1.1
|
|
@@ -96,6 +103,6 @@
|
|
|
96
103
|
|
|
97
104
|
<!-- change-close requires this section. One line per critical expectation:
|
|
98
105
|
`- E1: the expectation Covered by: 1.1` (task ids that own it), or a
|
|
99
|
-
`Durable owner:
|
|
100
|
-
closure. Use `- None.` only when the change has no critical expectations. -->
|
|
106
|
+
`Durable owner: <url or any repo-relative path that exists>` /
|
|
107
|
+
`Discard reason: why` closure. Use `- None.` only when the change has no critical expectations. -->
|
|
101
108
|
- None.
|
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",
|
package/scripts/bump_version.js
CHANGED
|
@@ -74,8 +74,45 @@ function replaceInFile(relPath, replacements) {
|
|
|
74
74
|
process.stdout.write(` updated ${relPath}\n`);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
// Every Keel marker carrying `version=` is a shipped claim about which version
|
|
78
|
+
// this is, and they must all move together. Sweeping for the markers that exist
|
|
79
|
+
// is what keeps a target from falling behind: the `.codex/` overlays sat four
|
|
80
|
+
// versions back because only the surfaces something happened to touch got
|
|
81
|
+
// refreshed, and nothing failed while they drifted.
|
|
82
|
+
const MARKER_SKIP_PREFIXES = [
|
|
83
|
+
"node_modules",
|
|
84
|
+
".git",
|
|
85
|
+
path.join("openspec", "changes", "archive"),
|
|
86
|
+
path.join("keel", "archive"),
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
function sweepVersionMarkers(dir, oldVersion, newVersion, touched) {
|
|
90
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
91
|
+
const full = path.join(dir, entry.name);
|
|
92
|
+
const relative = path.relative(ROOT, full);
|
|
93
|
+
if (MARKER_SKIP_PREFIXES.some((prefix) => relative.startsWith(prefix))) continue;
|
|
94
|
+
if (entry.isDirectory()) {
|
|
95
|
+
sweepVersionMarkers(full, oldVersion, newVersion, touched);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (!/\.(md|json)$/.test(entry.name)) continue;
|
|
99
|
+
const content = fs.readFileSync(full, "utf8");
|
|
100
|
+
const updated = content.replace(
|
|
101
|
+
new RegExp(`(keel:[a-z-]+(?::end)?\\s+version=)${oldVersion.replace(/\./g, "\\.")}\\b`, "g"),
|
|
102
|
+
`$1${newVersion}`
|
|
103
|
+
);
|
|
104
|
+
if (updated !== content) {
|
|
105
|
+
fs.writeFileSync(full, updated);
|
|
106
|
+
touched.push(relative.split(path.sep).join("/"));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
77
111
|
function prependChangelogEntry(newVersion) {
|
|
78
|
-
|
|
112
|
+
// Read line endings as the file has them: a CRLF checkout made the header
|
|
113
|
+
// comparison below fail after every version marker had already been written,
|
|
114
|
+
// leaving the repository half-bumped.
|
|
115
|
+
let content = fs.readFileSync(CHANGELOG_PATH, "utf8").replace(/\r\n/g, "\n");
|
|
79
116
|
if (content.includes(`## ${newVersion} `) || content.includes(`## ${newVersion}\n`)) {
|
|
80
117
|
process.stdout.write(` keel/CHANGELOG.md already has a ${newVersion} entry\n`);
|
|
81
118
|
return;
|
|
@@ -118,13 +155,14 @@ function main() {
|
|
|
118
155
|
[`PACKAGE_VERSION = "${oldVersion}"`, `PACKAGE_VERSION = "${newVersion}"`],
|
|
119
156
|
[`PROTOCOL_VERSION = "${oldVersion}"`, `PROTOCOL_VERSION = "${newVersion}"`],
|
|
120
157
|
]);
|
|
121
|
-
replaceInFile("AGENTS.md", [
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
158
|
+
replaceInFile("AGENTS.md", [[`v${oldVersion}`, `v${newVersion}`]]);
|
|
159
|
+
|
|
160
|
+
const touched = [];
|
|
161
|
+
sweepVersionMarkers(ROOT, oldVersion, newVersion, touched);
|
|
162
|
+
for (const relative of touched) {
|
|
163
|
+
process.stdout.write(` updated marker ${relative}\n`);
|
|
164
|
+
}
|
|
165
|
+
|
|
128
166
|
prependChangelogEntry(newVersion);
|
|
129
167
|
|
|
130
168
|
process.stdout.write(
|