okf-mcp 1.2.1 → 1.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 44ae2c50c714bc127ac861756a46e998d20f4310c77165ddcb616f7600c75517
4
- data.tar.gz: 9fec8976e46b7bbe983bd0261eba453a4b25c700dcde8085df36f7a0df3f924a
3
+ metadata.gz: e3ca85c635fb0dda3d4fc64a1b0b88aa112ea2e246502c79642c31e21b1921bb
4
+ data.tar.gz: 6a142dfd2a4de4a91691433d42f20b7cbe64bcd98007f96a1c9a371e57612ad9
5
5
  SHA512:
6
- metadata.gz: 7989702891ac272f637306102cadbd68f9e14f458b5cf81b373b681e3f9a8970fc248526f65038c449d498508820e143a2c9795b074ce456e3372882fd51889a
7
- data.tar.gz: 0a9f01ba82b4bf10592c23666051617f9be55f80848925cbd029a8ad7e42753d3f597491ea71e45f2a97c817c6d8acbf9203890d4b7afd28a17a6dd4c526207a
6
+ metadata.gz: cfecb3ac8b7238c6b3f331d0fc8edfcc43d9331339361c4c3f854213e0b2c8731a69471beeac2180b0f5966ea3503876c9d85cc493cc6b28a834c9128f65dd05
7
+ data.tar.gz: 2bd9dcfccb2039033342258f4a733cc8de081b5338680f1d9501c1095577651c49813b9139a8042e8c19235ebe9d6c26945385e37fb071a13b85ca87aa37a9ed
@@ -119,6 +119,24 @@ widen. A file that cannot be read or parsed keeps the last good set *without*
119
119
  latching its stamp, so a transient truncation is survived rather than made
120
120
  permanent until restart.
121
121
 
122
+ **The stamp watches every file the registry reads, not just its own.** okf's
123
+ registry can `link` another registry file, and that file's bundles resolve into
124
+ the served set — so a stamp over one path meant an `okf registry set` in the
125
+ linked file was never seen, and this server kept answering about the set it
126
+ booted with. That is the same silent wrong answer the rule above exists to
127
+ refuse, arriving through a second door. The link list comes from the kernel, so
128
+ adding or dropping a link moves the first path's stamp and the next pass watches
129
+ the new set; nothing has to be registered here.
130
+
131
+ The two kinds of file are watched under **different rules**, and the asymmetry is
132
+ the whole of it. This server's own registry going unreadable answers `nil`, which
133
+ holds the last good set — the paragraph above. A linked file is a pointer's
134
+ target, and okf already treats a missing one as *resolves to nothing, reported*;
135
+ following that here means a vanished target drops its bundles rather than
136
+ freezing them. Riding out an error and following a state change are different
137
+ jobs, and one stamp had to do both.
138
+ <!-- rule:okf-mcp-stamp-watches-links -->
139
+
122
140
  Four consequences of that rule had to be chased down after it landed. Two are
123
141
  the same mistake in different clothes — **something else was still a boot
124
142
  snapshot** — and two are what a *movable* served set costs a cache that was
data/.okf/log.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Update Log
2
2
 
3
+ ## 2026-08-21
4
+
5
+ * **The freshness stamp watches every file the registry reads** —
6
+ [the tool set](design/the-tool-set.md). okf's registry can now `link` another
7
+ registry file, and that file's bundles resolve into the served set; the stamp
8
+ still stat'd this server's own file alone, so an `okf registry set` over there
9
+ moved nothing it watched and a long-running server kept answering about the
10
+ set it booted with. That is the silent wrong answer the stamp exists to
11
+ prevent, arriving through a second door. The two kinds of file keep **different
12
+ rules**: this server's own registry going unreadable holds the last good set,
13
+ because a file caught mid-write must not empty what is being served, while a
14
+ linked target that vanishes drops its bundles — okf already reports a missing
15
+ one as resolving to nothing, and following that beats freezing it. Riding out
16
+ an error and following a state change are different jobs, and one stamp had to
17
+ do both.
18
+
19
+ * **`list_bundles` names the linked groups too.** They were resolvable as a
20
+ `bundle` argument and absent from the listing, because okf split them into a
21
+ second method — an agent could open `@brain` and never learn it existed. The
22
+ kernel folded them back into `groups_listing`, so this needed no change here
23
+ beyond the `link` key now on each row.
24
+
3
25
  ## 2026-08-19
4
26
  * **Addition**: **okf-mcp has a knowledge bundle, and `AGENTS.md` now relies on
5
27
  it** — [structure](structure/), [capabilities](capabilities/),
data/CHANGELOG.md CHANGED
@@ -5,6 +5,42 @@ All notable changes to this project are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.3.0] - 2026-08-22
9
+
10
+ ### Fixed
11
+
12
+ - **A long-running server now sees writes inside a *linked* registry.** okf gained
13
+ `okf registry link`, which folds another registry file's bundles into the served
14
+ set; the freshness stamp still watched only this server's own registry file, so
15
+ an `okf registry set` in the linked file never moved it and the server kept
16
+ answering about the set it booted with. The stamp now covers every file the
17
+ registry reads. The link list comes from the kernel, so adding or dropping a
18
+ link moves the first path's stamp and the next pass watches the new set.
19
+
20
+ The two kinds of file keep different rules. This server's own registry going
21
+ unreadable still answers `nil` and holds the last good set — a file caught
22
+ mid-write must not empty what is being served. A linked file is a pointer's
23
+ target, and okf already reports a missing one as resolving to nothing, so a
24
+ vanished target drops its bundles instead of freezing them.
25
+
26
+ ### Changed
27
+
28
+ - **The `mcp` floor moves to `~> 1.3`.** `Gemfile.lock` is not committed, so the
29
+ suite resolves the newest SDK the requirement admits and proves itself against
30
+ that one; the floor tracks what the suite proves, and 1.3.0 shipped. Nothing in
31
+ this gem changed for it — all 324 tests pass against 1.3.0 — but a floor that
32
+ admits an SDK the suite never ran against is the claim the floor test exists to
33
+ refuse.
34
+
35
+ - **The `okf` floor moves to 2.2.0**, the kernel that ships `registry link` and
36
+ `Registry#links_listing`. The stamp reads that method, and against 2.1.1 every
37
+ refresh would raise NoMethodError straight past the SystemCallError rescue.
38
+ `rake verify_okf_floor` gates `release` on exactly this and now passes.
39
+
40
+ - `list_bundles` groups now carry a `link` key — `null` for a group this registry
41
+ owns, the link's name for one that arrived through a link (okf ≥ 2.2). Linked
42
+ groups were already resolvable as a `bundle` argument and are now listed too.
43
+
8
44
  ## [1.2.1] - 2026-08-20
9
45
 
10
46
  ### Fixed
data/README.md CHANGED
@@ -77,8 +77,9 @@ bundles only when the registry itself is what is being served.
77
77
 
78
78
  With no arguments the registry *is* what is served, so it is followed rather
79
79
  than snapshotted: `okf registry set`, `rename` or `del` in another terminal
80
- shows up on the next tool call, without a restart. The file is re-read only
81
- when its fingerprint moves, so the cost is a `stat`. Bundle contents are never
80
+ shows up on the next tool call, without a restart. A write inside a registry the
81
+ first one *links* counts too. The files are re-read only when a fingerprint
82
+ moves, so the cost is a `stat` each. Bundle contents are never
82
83
  snapshotted either — bodies are read live, and a bundle is re-parsed whenever
83
84
  one of its files changes.
84
85
 
@@ -15,7 +15,7 @@ module OKF
15
15
  # names a registered bundle or group, whose slug is reserved before any
16
16
  # plain-dir basename is deduped — the server verb's rule). No argv means
17
17
  # the active kernel registry, resolved exactly as the CLI resolves it:
18
- # a project-local .okf-registry.json discovered from cwd, else
18
+ # a project-local .okf.json discovered from cwd, else
19
19
  # $OKF_HOME/registry.json, OKF_NO_DISCOVERY=1 forcing global.
20
20
  class Registry
21
21
  # One served bundle: the +slug+ tools name it by, its absolute +root+ on
@@ -297,10 +297,34 @@ module OKF
297
297
  # mtime *and* size, the pair the residency layer already uses: a second
298
298
  # write inside one filesystem timestamp tick moves the size when it does
299
299
  # not move the clock.
300
+ #
301
+ # Every file the registry reads, not just its own. A link puts bundles in a
302
+ # second file, and watching only the first meant a `registry set` over there
303
+ # was never seen: this server would keep answering about the set it booted
304
+ # with, which is the one failure a stamp exists to prevent. The link list
305
+ # itself comes from the kernel, so adding or dropping a link moves the first
306
+ # entry and the next pass watches the new set.
307
+ # The two files are watched under different rules, and the asymmetry is the
308
+ # point. This server's *own* registry going unreadable answers nil, which
309
+ # holds the last good set — a file caught mid-write must not empty what is
310
+ # being served. A *linked* file is only a pointer's target, and the kernel
311
+ # already treats a missing one as "resolves to nothing, reported", so its
312
+ # absence is a state change to follow rather than an error to ride out.
300
313
  def registry_stamp
301
314
  return nil if @kernel.nil?
302
315
 
303
- stat = ::File.stat(@kernel.path)
316
+ own = file_stamp(@kernel.path)
317
+ return nil if own.nil?
318
+
319
+ [ own ] + @kernel.links_listing.map { |row| file_stamp(row[:registry]) }
320
+ rescue OKF::Error, SystemCallError
321
+ nil
322
+ end
323
+
324
+ # nil for a file that is not there — a state in its own right for a link, so
325
+ # a target appearing or vanishing moves the stamp exactly as an edit does.
326
+ def file_stamp(path)
327
+ stat = ::File.stat(path)
304
328
  [ stat.mtime.to_f, stat.size ]
305
329
  rescue SystemCallError
306
330
  nil
@@ -2,6 +2,6 @@
2
2
 
3
3
  module OKF
4
4
  module MCP
5
- VERSION = "1.2.1"
5
+ VERSION = "1.3.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: okf-mcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Serradura
@@ -15,21 +15,21 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '1.2'
18
+ version: '1.3'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '1.2'
25
+ version: '1.3'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: okf
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: 2.1.1
32
+ version: 2.2.0
33
33
  - - "<"
34
34
  - !ruby/object:Gem::Version
35
35
  version: '3'
@@ -39,7 +39,7 @@ dependencies:
39
39
  requirements:
40
40
  - - ">="
41
41
  - !ruby/object:Gem::Version
42
- version: 2.1.1
42
+ version: 2.2.0
43
43
  - - "<"
44
44
  - !ruby/object:Gem::Version
45
45
  version: '3'