okf 2.1.1 → 2.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.
@@ -507,11 +507,15 @@ module OKF
507
507
  # than by slug: a rename in the file changes the slug and nothing else,
508
508
  # and a row that lost its identity over a rename is the bug this avoids.
509
509
  def manager_rows
510
- return @bundles.map { |bundle| hosted_row(bundle, bundle.slug) } if registry.nil?
510
+ return @bundles.map { |bundle| hosted_row(bundle, bundle.slug).merge(link: nil) } if registry.nil?
511
511
 
512
512
  registry.listing.map do |entry|
513
513
  hosted = @bundles.find { |bundle| bundle.folder.root == entry[:dir] }
514
- hosted ? hosted_row(hosted, entry[:slug], entry[:dir]) : unhosted_row(entry)
514
+ row = hosted ? hosted_row(hosted, entry[:slug], entry[:dir]) : unhosted_row(entry)
515
+ # A bundle that arrived through a link is read-only here, and the page
516
+ # has to know: the registry refuses every write against one, so a row
517
+ # offering the menu would offer three actions that can only fail.
518
+ row.merge(link: entry[:link])
515
519
  end
516
520
  end
517
521
 
@@ -2,7 +2,9 @@
2
2
 
3
3
  Kind: reference. Answers: which file a registry op writes and how okf finds it,
4
4
  which verbs key on a path and which on a slug, what a group is and which two
5
- verbs consume one, and why the default is a position rather than a stored slug.
5
+ verbs consume one, why the default is a position rather than a stored slug, and
6
+ what a link brings in from another registry file — against what an import copies
7
+ out of one.
6
8
 
7
9
  The *persistent registry* is a plain JSON file under `$OKF_HOME` (default
8
10
  `~/.okf`), managed by the `okf registry` umbrella — like git's `remote` family,
@@ -11,18 +13,28 @@ and split by what each verb keys on. It is what every `@slug` resolves through
11
13
  ([serve.md](serve.md)).
12
14
 
13
15
  **`okf registry init`** creates a *project-local* registry instead: a
14
- `.okf-registry.json` in the current directory, which okf discovers by walking up
16
+ `.okf.json` in the current directory, which okf discovers by walking up
15
17
  from the working directory and uses in place of the global one while you are
16
18
  inside its tree (the nearest wins, so nested registries resolve nearest-first).
17
19
  Every registry op — and every `@slug` — then resolves through it, so a bare
18
20
  `okf server` inside a repo serves that repo's bundles with no `$OKF_HOME` setup;
19
21
  `okf registry list` names the local file it found. `OKF_NO_DISCOVERY=1` forces
20
- the global registry — the escape hatch for a fixed-cwd caller (CI, a tool). A
22
+ the global registry — the escape hatch for a fixed-cwd caller (CI, a tool) — and
23
+ **`-g`/`--global` says the same thing for one command**, on every subcommand but
24
+ `init` (whose whole job is to create a local file). So `okf registry list -g`
25
+ reads the global registry from inside a repo, and `okf registry set <dir> -g`
26
+ registers there without leaving. `list` names the file it read whenever either
27
+ lever is in play, so which registry answered is never a guess. A
21
28
  local registry stores **portable** paths: a bundle inside its tree is written
22
- relative to the `.okf-registry.json`, so committing the file lets it travel with
29
+ relative to the `.okf.json`, so committing the file lets it travel with
23
30
  the repo (a checkout elsewhere, a container mounting it) and resolve unchanged;
24
31
  a bundle outside the tree stays absolute, since it cannot travel. Paths still read
25
32
  back absolute wherever the CLI reports them.
33
+ The file okf writes is `.okf.json`; the older `.okf-registry.json` is still
34
+ discovered, both names checked in each directory on the way up so "nearest wins"
35
+ keeps its shape, and `okf registry` — that verb alone, never `lint` or `search` —
36
+ notes the old name once so it can be retired with a `git mv`.
37
+
26
38
  **Entry verbs** take a path: `okf registry set <dir>` adds it
27
39
  (slug from the basename, or `--as`, which errors on a collision; `--default`
28
40
  puts it first), and because the entry is keyed by path, `set` on an
@@ -61,10 +73,41 @@ and `okf server` consume**: every single-bundle verb (`lint`, `index`, …) refu
61
73
  a `@group` with exit 2, the same rule that refuses a second bundle. `@all` is
62
74
  unchanged — it still names every registered *bundle*, groups being named subsets
63
75
  of that.
76
+ **Link verbs** point the *global* registry at another registry file, so its
77
+ bundles resolve here without being copied. `okf registry link <name> <file>`
78
+ adds the pointer (the target must exist); its bundles then answer to their own
79
+ slugs, or to `<name>-<slug>` when a name is already taken here, and `@<name>`
80
+ resolves as a group over them. Nothing is written but the pointer — the target
81
+ keeps owning its rows, so an edit there shows here on the next read, and every
82
+ write aimed at a linked bundle (`rename`, `del`, `default`, `set --as`, `group`)
83
+ is refused naming the file that does own it. `okf registry unlink <name>` drops
84
+ the pointer and its bundles. Links are the **global** registry's alone: a
85
+ project-local one parses them and does not resolve them, which is why a linked
86
+ file's own links are never followed and there is no chain to cycle. A target
87
+ that is gone or unparseable is listed `(missing)`/`(unreadable)` and resolves to
88
+ nothing — one dead pointer never takes down the registry holding it.
89
+ <!-- rule:okf-registry-links-global-only -->
90
+ **`okf registry import <@slug…>`** is the opposite trade: it *copies* chosen rows
91
+ out of another registry file into the one in force, and they become yours —
92
+ editable, renameable, groupable, and untouched when the source changes. The
93
+ source is `--from FILE`, defaulting to the global registry, because `-g` goes on
94
+ meaning the registry written *to*. A group ask brings its members, and any group
95
+ nested inside it, recreated under the same names. Slugs are preserved, so a
96
+ collision **refuses** rather than being minted around the way a link's is — you
97
+ typed this name, and the gem may not substitute one you chose (`--as` renames a
98
+ single ask). A bundle already registered here under another name refuses first.
99
+ Every ask is checked before anything is written, so an import either lands whole
100
+ or leaves the file byte-for-byte alone.
101
+ <!-- rule:okf-registry-import-all-or-nothing -->
64
102
  `okf registry list` (or a bare
65
103
  `okf registry`) stars the default and flags vanished dirs `(missing)` — the
66
104
  server skips those with a note — and lists any groups with their members and
67
105
  resolved leaf count; `--json` answers
68
106
  `{ registry: <file>, count, bundles: [{ slug, title, dir, mount, default,
69
- missing }], groups: [{ slug, members, resolved }] }`, naming the file it read so a
70
- `$OKF_HOME` mismatch is visible.
107
+ missing, link, origin }], groups: [{ slug, members, resolved, link }], links:
108
+ [{ slug, registry, bundles, missing, unreadable }] }`, naming the file it read so a
109
+ `$OKF_HOME` mismatch is visible. On a bundle row `link` names the link it arrived
110
+ through (null when the registry owns it) and `origin` the slug it carries in that
111
+ file — the two differ only where a collision moved the name. `groups` lists both
112
+ kinds, own first, each carrying the same `link` key, since a linked group
113
+ resolves as a ref like any other.
@@ -20,7 +20,7 @@ when it has one.
20
20
  | [cli/map.md](cli/map.md) | `index` `dirs` | orientation: the §8 directory map and the cluster sizes, how `--dir`/`--depth`/ancestors compose, what a synthesized listing means, how not to page the bundle |
21
21
  | [cli/views.md](cli/views.md) | `catalog` `files` `tags` `types` `stats` | the browser panels as text — per-concept metadata, the folder tree, tag and type rollups, bundle totals, and the JSON each emits |
22
22
  | [cli/serve.md](cli/serve.md) | `server` `render` | the interactive page and its static twin — what renders, what is fetched live, many bundles behind one hub, the trust boundary both share |
23
- | [cli/registry.md](cli/registry.md) | `registry` (`init` `set` `del` `default` `rename` `group` `ungroup` `list`) | naming bundles once: which file is written and how it is found, path-keyed vs slug-keyed verbs, groups, why the default is a position |
23
+ | [cli/registry.md](cli/registry.md) | `registry` (`init` `set` `del` `default` `rename` `group` `ungroup` `link` `unlink` `list`) | naming bundles once: which file is written and how it is found, path-keyed vs slug-keyed verbs, groups, why the default is a position |
24
24
  | [cli/graph.md](cli/graph.md) | `graph` | the raw node/edge dump and what it costs, plus the two rankings [refine](../playbooks/refine.md) reads — `--hubs` by concept, `--traffic` by directory |
25
25
 
26
26
  A question that ends in *what does the spec actually say* leaves the CLI
data/lib/okf/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OKF
4
- VERSION = "2.1.1"
4
+ VERSION = "2.2.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: okf
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Serradura