okf 1.11.0 → 1.13.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 +4 -4
- data/CHANGELOG.md +193 -1
- data/README.md +77 -428
- data/lib/okf/bundle/folder.rb +25 -2
- data/lib/okf/bundle/reader.rb +39 -16
- data/lib/okf/bundle/search.rb +5 -5
- data/lib/okf/bundle/skeleton.rb +241 -0
- data/lib/okf/bundle.rb +37 -17
- data/lib/okf/cli/catalog.rb +6 -6
- data/lib/okf/cli/command.rb +139 -19
- data/lib/okf/cli/dirs.rb +1 -1
- data/lib/okf/cli/files.rb +1 -1
- data/lib/okf/cli/graph.rb +115 -9
- data/lib/okf/cli/index.rb +2 -2
- data/lib/okf/cli/registry.rb +152 -15
- data/lib/okf/cli/render.rb +3 -2
- data/lib/okf/cli/search.rb +53 -8
- data/lib/okf/cli/server.rb +9 -5
- data/lib/okf/cli/stats.rb +8 -8
- data/lib/okf/cli/tags.rb +2 -2
- data/lib/okf/cli.rb +3 -3
- data/lib/okf/concept/file.rb +17 -2
- data/lib/okf/path.rb +17 -3
- data/lib/okf/registry.rb +351 -20
- data/lib/okf/render/graph/template.html.erb +211 -7
- data/lib/okf/render/graph.rb +27 -3
- data/lib/okf/safe_read.rb +50 -0
- data/lib/okf/server/app.rb +13 -3
- data/lib/okf/server/hub.rb +5 -3
- data/lib/okf/skill/SKILL.md +5 -1
- data/lib/okf/skill/playbooks/menu.md +2 -1
- data/lib/okf/skill/playbooks/refine.md +26 -0
- data/lib/okf/skill/reference/cli.md +81 -21
- data/lib/okf/version.rb +1 -1
- data/lib/okf.rb +2 -0
- metadata +4 -3
- data/CODE_OF_CONDUCT.md +0 -10
|
@@ -250,8 +250,8 @@ consuming agent is the fuzzy layer — when terms miss, learn the bundle's
|
|
|
250
250
|
vocabulary from `tags`/`types` and re-ask in its own words, rather than
|
|
251
251
|
hammering synonyms or reaching for `--fuzzy` before you have looked. Advisory read: **exit 0 even with zero matches**.
|
|
252
252
|
JSON, plain-dir mode: `{ bundle, query, count, matches: [{ id, title, type,
|
|
253
|
-
|
|
254
|
-
`@all` among them — swaps the envelope: `{ bundles: [{ slug, dir }, …],
|
|
253
|
+
dir, top_dir, tags, matched, score, snippet }] }`. Registry mode — any leading @ref,
|
|
254
|
+
`@all` or a `@group` among them (a group fans out to its member bundles) — swaps the envelope: `{ bundles: [{ slug, dir }, …],
|
|
255
255
|
query, count, matches: [{ slug, id, … }] }`; a parser must branch on which form
|
|
256
256
|
it called. The head maps each slug to its dir once, so a row resolves to
|
|
257
257
|
`<dir>/<id>.md` without a second lookup and without repeating a path per row.
|
|
@@ -275,7 +275,8 @@ enumeration drift a grep can't (you can't grep for a listing entry that is *miss
|
|
|
275
275
|
|
|
276
276
|
`--dir PATH` narrows to a directory **and everything below it**, and is
|
|
277
277
|
**repeatable** — `--dir model --dir format` shows both; `root` (or `.`) names the
|
|
278
|
-
bundle root
|
|
278
|
+
bundle root, unless the bundle really has a `root/` directory, which owns the
|
|
279
|
+
word. A `--dir` also brings the **chain from the root down to it**, so a branch is
|
|
279
280
|
never shown adrift of the authored context that says what it is — the root
|
|
280
281
|
`index.md`'s prose first among it. Those rows print with a leading `↑` and carry
|
|
281
282
|
`ancestor: true`; `--no-ancestors` drops them. Ascent and descent are separate
|
|
@@ -357,10 +358,10 @@ All are advisory reads (exit 0) sharing one data source (per-concept metadata pl
|
|
|
357
358
|
in/out link degree). Add `--json` to any for a machine substrate.
|
|
358
359
|
|
|
359
360
|
- **`catalog`** — every concept with its metadata (type, status, tags, timestamp,
|
|
360
|
-
in/out link degree, description), grouped by top-level
|
|
361
|
-
carries the full path). The "what's here, in
|
|
361
|
+
in/out link degree, description), grouped by top-level dir (`dir` on every row
|
|
362
|
+
carries the full path, `top_dir` the first segment). The "what's here, in
|
|
362
363
|
detail" view. JSON: `{ bundle, count, concepts: [{ id, title, type, description,
|
|
363
|
-
tags, timestamp, status, backlog_ref, dir,
|
|
364
|
+
tags, timestamp, status, backlog_ref, dir, top_dir, links_out, links_in }] }`.
|
|
364
365
|
- **`files`** — the folder tree: each concept's filename + title, grouped by
|
|
365
366
|
directory. The "how it's organised" view. JSON: `{ bundle, count, files: [{ path,
|
|
366
367
|
id, dir, type, title, description }] }`.
|
|
@@ -380,9 +381,9 @@ in/out link degree). Add `--json` to any for a machine substrate.
|
|
|
380
381
|
[{ type, count, concepts: [id, …] }] }`.
|
|
381
382
|
- **`stats`** — bundle rollups: concept / dir / type / cross-link / distinct-tag
|
|
382
383
|
totals plus per-type and per-dir breakdowns. The "shape at a glance" view. JSON:
|
|
383
|
-
`{ bundle, concepts, dirs,
|
|
384
|
-
by_type, by_dir,
|
|
385
|
-
|
|
384
|
+
`{ bundle, concepts, dirs, top_dirs, concept_types, cross_links, distinct_tags,
|
|
385
|
+
by_type, by_dir, by_top_dir }` (`top_dirs`/`by_top_dir` are the first-segment
|
|
386
|
+
rollup). `dirs`/`by_dir` cover every directory `okf dirs`
|
|
386
387
|
lists — counts are direct, so a directory holding nothing itself is present at
|
|
387
388
|
`0` rather than missing, and `by_dir.keys` is a complete list of what `--dir`
|
|
388
389
|
can address.
|
|
@@ -392,7 +393,9 @@ The four list views narrow with the same filters the browser panels offer —
|
|
|
392
393
|
itself (`tags` can't filter by tag). Matching is case-insensitive; `--type` and
|
|
393
394
|
`--tag` are exact, `--dir` takes the named directory **and everything below it**
|
|
394
395
|
(`--dir platform` reaches `platform/services/api`). A concept at the bundle root
|
|
395
|
-
lives in `.`, which `--dir` also accepts as plain `root` (no shell quoting)
|
|
396
|
+
lives in `.`, which `--dir` also accepts as plain `root` (no shell quoting) —
|
|
397
|
+
except in a bundle holding a real `root/` directory, where that directory takes
|
|
398
|
+
the name and `.` is the only spelling of the bundle root. A
|
|
396
399
|
filter that matches nothing is an empty view, not an error: `okf tags <dir> --dir
|
|
397
400
|
billing --json` answers "which tags does the billing cluster use?",
|
|
398
401
|
`okf catalog <dir> --tag auth` answers "what carries the auth tag?".
|
|
@@ -442,20 +445,38 @@ page listing the hosted bundles, so a stale bookmark after a rename gets a way
|
|
|
442
445
|
home. With **no** dir it serves the *persistent registry*, a plain JSON file
|
|
443
446
|
under `$OKF_HOME` (default `~/.okf`), managed by the
|
|
444
447
|
`okf registry` umbrella — like git's `remote` family, and split by what each
|
|
445
|
-
verb keys on.
|
|
448
|
+
verb keys on.
|
|
449
|
+
**`okf registry init`** creates a *project-local* registry instead: a
|
|
450
|
+
`.okf-registry.json` in the current directory, which okf discovers by walking up
|
|
451
|
+
from the working directory and uses in place of the global one while you are
|
|
452
|
+
inside its tree (the nearest wins, so nested registries resolve nearest-first).
|
|
453
|
+
Every registry op — and every `@slug` — then resolves through it, so a bare
|
|
454
|
+
`okf server` inside a repo serves that repo's bundles with no `$OKF_HOME` setup;
|
|
455
|
+
`okf registry list` names the local file it found. `OKF_NO_DISCOVERY=1` forces
|
|
456
|
+
the global registry — the escape hatch for a fixed-cwd caller (CI, a tool). A
|
|
457
|
+
local registry stores **portable** paths: a bundle inside its tree is written
|
|
458
|
+
relative to the `.okf-registry.json`, so committing the file lets it travel with
|
|
459
|
+
the repo (a checkout elsewhere, a container mounting it) and resolve unchanged;
|
|
460
|
+
a bundle outside the tree stays absolute, since it cannot travel. Paths still read
|
|
461
|
+
back absolute wherever the CLI reports them.
|
|
462
|
+
**Entry verbs** take a path: `okf registry set <dir>` adds it
|
|
446
463
|
(slug from the basename, or `--as`, which errors on a collision; `--default`
|
|
447
464
|
puts it first), and because the entry is keyed by path, `set` on an
|
|
448
465
|
already-registered dir updates it in place — refreshing its title, and renaming
|
|
449
|
-
it when `--as` is given. `okf registry del <dir|@slug>` removes
|
|
450
|
-
directory is already gone still deletes
|
|
466
|
+
it when `--as` is given. `okf registry del <dir|@slug>` removes a bundle *or* a group — by name, so an
|
|
467
|
+
entry whose directory is already gone still deletes, and removing a bundle
|
|
468
|
+
**cascade-drops** it from every group that named it (a group emptied that way is
|
|
469
|
+
deleted). Slug *or* dir, never both readings at
|
|
451
470
|
once: an argument with a `/` in it names a location and only a location, so
|
|
452
471
|
`del ./notes` refuses when no entry points there rather than stripping to the
|
|
453
472
|
slug `notes` and deleting a bundle somewhere else entirely.
|
|
454
473
|
<!-- rule:okf-registry-del-path-or-slug -->
|
|
455
474
|
**Slug verbs** take the name — bare, or as an `@slug`: `okf registry default <@slug>`
|
|
456
|
-
chooses which bundle `/` opens **by moving that entry to the front
|
|
457
|
-
|
|
458
|
-
|
|
475
|
+
chooses which bundle `/` opens **by moving that entry to the front** (a group is
|
|
476
|
+
refused — the default is one bundle), and
|
|
477
|
+
`okf registry rename <@slug> <new>` renames a bundle *or* group slug (mount path
|
|
478
|
+
and switcher name), **cascading** the new name into every group's member list —
|
|
479
|
+
`<new>` is a name being minted, so it is never a ref. The registry is ordered and **the first entry still on disk is the
|
|
459
480
|
default** — that is the whole rule, so the first bundle you register is the
|
|
460
481
|
default until you move another one, a rename keeps its position, and a `del`
|
|
461
482
|
promotes whatever is next. A vanished directory is stepped over (the server
|
|
@@ -464,11 +485,25 @@ cannot open one, so starring it would name a bundle `/` never serves), and
|
|
|
464
485
|
gives a directory that is not there. The file is hand-editable and reorders
|
|
465
486
|
visibly, which is the point: there is no stored slug that can dangle.
|
|
466
487
|
<!-- rule:okf-registry-default-position -->
|
|
488
|
+
**Group verbs** name a *set* of bundles under one slug — a durable subset for the
|
|
489
|
+
two verbs that take several bundles. `okf registry group <slug> <@member…>`
|
|
490
|
+
creates a group, or adds members to one (a union); members are bundle *or* group
|
|
491
|
+
slugs, so groups nest. A group shares the slug namespace with bundles (a slug
|
|
492
|
+
names one *or* the other, never both), `all` stays reserved, and a member set that
|
|
493
|
+
would make the group reach itself is refused. `okf registry ungroup <slug>
|
|
494
|
+
<@member…>` removes members; emptying a group deletes it. A group resolves,
|
|
495
|
+
recursively and path-deduped, to its bundle leaves — which **only `okf search`
|
|
496
|
+
and `okf server` consume**: every single-bundle verb (`lint`, `index`, …) refuses
|
|
497
|
+
a `@group` with exit 2, the same rule that refuses a second bundle. `@all` is
|
|
498
|
+
unchanged — it still names every registered *bundle*, groups being named subsets
|
|
499
|
+
of that.
|
|
467
500
|
`okf registry list` (or a bare
|
|
468
501
|
`okf registry`) stars the default and flags vanished dirs `(missing)` — the
|
|
469
|
-
server skips those with a note
|
|
502
|
+
server skips those with a note — and lists any groups with their members and
|
|
503
|
+
resolved leaf count; `--json` answers
|
|
470
504
|
`{ registry: <file>, count, bundles: [{ slug, title, dir, mount, default,
|
|
471
|
-
missing }] }`, naming the file it read so a
|
|
505
|
+
missing }], groups: [{ slug, members, resolved }] }`, naming the file it read so a
|
|
506
|
+
`$OKF_HOME` mismatch is visible. The hub roster is a
|
|
472
507
|
**boot-time snapshot**: restart `okf server` after registry changes. Behind a
|
|
473
508
|
hub the page gains a **bundle switcher** (⌘/Ctrl-K, or the rail button with its
|
|
474
509
|
bundle-count badge): the current bundle is pinned, the default chipped; ⏎
|
|
@@ -481,7 +516,10 @@ them all with the registry's first entry still on disk at `/` — the way to kee
|
|
|
481
516
|
several bundles a keystroke apart without re-passing paths.
|
|
482
517
|
`okf server @a @b` serves a registry subset, each mounted under its registered
|
|
483
518
|
slug — but as with any dirs-given run, the *first argument* lands at `/`; the
|
|
484
|
-
registry's own order applies only to the bundle-less run.
|
|
519
|
+
registry's own order applies only to the bundle-less run. A `@group` argument
|
|
520
|
+
fans out to its member bundles in the same way (`okf server @backend`), its first
|
|
521
|
+
member landing at `/`; `okf search @group <term…>` merges the group's members
|
|
522
|
+
into one ranking, exactly as naming them individually would.
|
|
485
523
|
|
|
486
524
|
**Trust boundary:** the page renders each fetched markdown body through
|
|
487
525
|
DOMPurify and escapes everything it inlines (every `<` in the graph data is
|
|
@@ -522,8 +560,30 @@ only when the task truly consumes every body; for one question, the
|
|
|
522
560
|
|
|
523
561
|
`--hubs` swaps the dump for the **inbound ranking**: every concept with at
|
|
524
562
|
least one inbound link, ranked by inbound degree, each with its links grouped
|
|
525
|
-
by *source
|
|
563
|
+
by *source top-level dir* (`core/status ×3 flows 2, billing 1`) — the evidence for
|
|
526
564
|
[refine](../playbooks/refine.md)'s hub origin test ("is this hub well-homed?").
|
|
527
565
|
A source at the bundle root counts under `(root)`. JSON: `{ bundle, count,
|
|
528
|
-
hubs: [{ id,
|
|
566
|
+
hubs: [{ id, top_dir, inbound, by_top_dir: { <top_dir>: n } }] }`. Advisory read, exit 0;
|
|
529
567
|
`--minimal`/`--no-body` shape node payloads and change nothing here.
|
|
568
|
+
|
|
569
|
+
`--traffic` asks the same question one grain coarser: **directories**, not
|
|
570
|
+
concepts. Every concept collapses into the directory it lives in and every link
|
|
571
|
+
between two directories collapses into one weighted arc, so a bundle's wiring
|
|
572
|
+
becomes a table you can read — measured on one 47-concept bundle, 227 links
|
|
573
|
+
collapsed into 50 arcs, of which the fitted cut draws 22. Each row carries the
|
|
574
|
+
directory's traffic split three ways
|
|
575
|
+
(`internal` / `out` / `in`) plus **cohesion**, its internal share of the total:
|
|
576
|
+
the evidence for [refine](../playbooks/refine.md)'s container test, where
|
|
577
|
+
`--hubs` only ever answered about concepts. Rows lead with the lowest cohesion,
|
|
578
|
+
so the directories with a case to answer come first, and a directory with no
|
|
579
|
+
traffic at all prints `—` rather than a `0%` it did not earn.
|
|
580
|
+
|
|
581
|
+
`--cut N` is the least arc weight drawn. It defaults to a value **fitted to the
|
|
582
|
+
bundle** — enough arcs for roughly 1.5 per directory, floored at 8 — because a
|
|
583
|
+
fixed weight cannot serve both ends: measured at weight 3 across ten bundles it
|
|
584
|
+
left 2 arcs on one and 136 on another. The JSON says which you got. Cohesion is
|
|
585
|
+
computed over *every* arc and never the drawn ones, so tightening the cut
|
|
586
|
+
changes the picture and never the evidence. JSON: `{ bundle, cut, fitted, dirs:
|
|
587
|
+
[{ dir, parent, count, subtree, internal, out, in, cohesion }], arcs: [{ source,
|
|
588
|
+
target, weight }], total_arcs }` — a fraction of the full dump (2.6 KB against
|
|
589
|
+
27 KB on that bundle), and the shape rather than the contents. Advisory, exit 0.
|
data/lib/okf/version.rb
CHANGED
data/lib/okf.rb
CHANGED
|
@@ -38,6 +38,7 @@ module OKF
|
|
|
38
38
|
|
|
39
39
|
# ── kernel: cross-cutting primitives ──
|
|
40
40
|
require "okf/path"
|
|
41
|
+
require "okf/safe_read"
|
|
41
42
|
|
|
42
43
|
# ── Markdown: parse structure out of a markdown document (§4/§5/§8) ──
|
|
43
44
|
require "okf/markdown/frontmatter"
|
|
@@ -48,6 +49,7 @@ module OKF
|
|
|
48
49
|
require "okf/concept"
|
|
49
50
|
require "okf/bundle"
|
|
50
51
|
require "okf/bundle/graph"
|
|
52
|
+
require "okf/bundle/skeleton"
|
|
51
53
|
require "okf/bundle/search"
|
|
52
54
|
# These two lines ARE the engine preference order. Each engine registers itself
|
|
53
55
|
# at load, `Search.engines` is registration order, and the router walks it after
|
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: 1.
|
|
4
|
+
version: 1.13.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rodrigo Serradura
|
|
@@ -78,7 +78,6 @@ extensions: []
|
|
|
78
78
|
extra_rdoc_files: []
|
|
79
79
|
files:
|
|
80
80
|
- CHANGELOG.md
|
|
81
|
-
- CODE_OF_CONDUCT.md
|
|
82
81
|
- LICENSE.txt
|
|
83
82
|
- NOTICE
|
|
84
83
|
- README.md
|
|
@@ -93,6 +92,7 @@ files:
|
|
|
93
92
|
- lib/okf/bundle/search.rb
|
|
94
93
|
- lib/okf/bundle/search/index.rb
|
|
95
94
|
- lib/okf/bundle/search/scan.rb
|
|
95
|
+
- lib/okf/bundle/skeleton.rb
|
|
96
96
|
- lib/okf/bundle/validator.rb
|
|
97
97
|
- lib/okf/bundle/validator/result.rb
|
|
98
98
|
- lib/okf/bundle/writer.rb
|
|
@@ -123,6 +123,7 @@ files:
|
|
|
123
123
|
- lib/okf/registry.rb
|
|
124
124
|
- lib/okf/render/graph.rb
|
|
125
125
|
- lib/okf/render/graph/template.html.erb
|
|
126
|
+
- lib/okf/safe_read.rb
|
|
126
127
|
- lib/okf/server/app.rb
|
|
127
128
|
- lib/okf/server/hub.rb
|
|
128
129
|
- lib/okf/server/hub/not_found.rb
|
|
@@ -154,7 +155,7 @@ metadata:
|
|
|
154
155
|
allowed_push_host: https://rubygems.org
|
|
155
156
|
homepage_uri: https://github.com/serradura/okf-gem
|
|
156
157
|
source_code_uri: https://github.com/serradura/okf-gem
|
|
157
|
-
changelog_uri: https://github.com/serradura/okf-gem/blob/main/CHANGELOG.md
|
|
158
|
+
changelog_uri: https://github.com/serradura/okf-gem/blob/main/okf/CHANGELOG.md
|
|
158
159
|
rubygems_mfa_required: 'true'
|
|
159
160
|
rdoc_options: []
|
|
160
161
|
require_paths:
|
data/CODE_OF_CONDUCT.md
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
# Code of Conduct
|
|
2
|
-
|
|
3
|
-
"okf" follows [The Ruby Community Conduct Guideline](https://www.ruby-lang.org/en/conduct) in all "collaborative space", which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.):
|
|
4
|
-
|
|
5
|
-
* Participants will be tolerant of opposing views.
|
|
6
|
-
* Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
|
|
7
|
-
* When interpreting the words and actions of others, participants should always assume good intentions.
|
|
8
|
-
* Behaviour which can be reasonably considered harassment will not be tolerated.
|
|
9
|
-
|
|
10
|
-
If you have any concerns about behaviour within this project, please contact us at ["rodrigo.serradura@gmail.com"](mailto:"rodrigo.serradura@gmail.com").
|