okf 1.10.0 → 1.12.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 +294 -0
- data/README.md +310 -445
- data/lib/okf/bundle/folder.rb +24 -5
- data/lib/okf/bundle/linter.rb +1 -1
- data/lib/okf/bundle/search/index.rb +13 -3
- data/lib/okf/bundle/search.rb +93 -13
- data/lib/okf/bundle/skeleton.rb +241 -0
- data/lib/okf/bundle.rb +19 -14
- data/lib/okf/cli/catalog.rb +6 -6
- data/lib/okf/cli/command.rb +241 -14
- data/lib/okf/cli/dirs.rb +118 -0
- data/lib/okf/cli/files.rb +2 -2
- data/lib/okf/cli/graph.rb +115 -9
- data/lib/okf/cli/index.rb +67 -25
- data/lib/okf/cli/loose.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 +33 -2
- data/lib/okf/cli/server.rb +16 -5
- data/lib/okf/cli/stats.rb +36 -11
- data/lib/okf/cli/tags.rb +29 -7
- data/lib/okf/cli/types.rb +1 -1
- data/lib/okf/cli.rb +10 -6
- data/lib/okf/registry.rb +351 -20
- data/lib/okf/render/graph/template.html.erb +504 -103
- data/lib/okf/render/graph.rb +27 -3
- data/lib/okf/server/app.rb +74 -3
- data/lib/okf/server/hub.rb +40 -30
- data/lib/okf/skill/SKILL.md +17 -10
- data/lib/okf/skill/playbooks/consume.md +3 -3
- data/lib/okf/skill/playbooks/maintain.md +4 -3
- data/lib/okf/skill/playbooks/menu.md +3 -2
- data/lib/okf/skill/playbooks/refine.md +30 -3
- data/lib/okf/skill/playbooks/search.md +7 -7
- data/lib/okf/skill/reference/cli.md +171 -32
- data/lib/okf/version.rb +1 -1
- data/lib/okf.rb +10 -0
- metadata +21 -8
|
@@ -150,7 +150,7 @@ as Ruby regular expressions with `--regexp`/`-e` (an invalid pattern is a usage
|
|
|
150
150
|
error, exit 2). `--fuzzy` forgives typos; pairing it with `-e` is a usage error,
|
|
151
151
|
since a pattern is matched literally rather than by edit distance.
|
|
152
152
|
`--in a,b` restricts the searched fields (title, id, tags, type, description,
|
|
153
|
-
body); the shared `--type/--
|
|
153
|
+
body); the shared `--type/--dir/--tag` filters narrow the candidates *first*,
|
|
154
154
|
so a search scoped by what `index` taught you stays surgical.
|
|
155
155
|
|
|
156
156
|
**The default is exact, so an exact query means what it looks like.** A phrase in
|
|
@@ -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.
|
|
@@ -273,8 +273,30 @@ there, its child directories, and the concept listing. Run it first when picking
|
|
|
273
273
|
an existing bundle: it is the cheapest high-signal orientation, and it surfaces
|
|
274
274
|
enumeration drift a grep can't (you can't grep for a listing entry that is *missing*).
|
|
275
275
|
|
|
276
|
-
`--
|
|
277
|
-
format` shows both; `root`
|
|
276
|
+
`--dir PATH` narrows to a directory **and everything below it**, and is
|
|
277
|
+
**repeatable** — `--dir model --dir format` shows both; `root` (or `.`) names the
|
|
278
|
+
bundle root. A `--dir` also brings the **chain from the root down to it**, so a branch is
|
|
279
|
+
never shown adrift of the authored context that says what it is — the root
|
|
280
|
+
`index.md`'s prose first among it. Those rows print with a leading `↑` and carry
|
|
281
|
+
`ancestor: true`; `--no-ancestors` drops them. Ascent and descent are separate
|
|
282
|
+
axes, so `--depth` never bounds the chain: `--dir X --depth 0` is X alone, plus
|
|
283
|
+
how you get to X. A `--dir` that names nothing gains no chain — a lone root row
|
|
284
|
+
would read as a partial answer to a query that matched nothing.
|
|
285
|
+
|
|
286
|
+
`--depth N` bounds how far below the starting point the map reaches
|
|
287
|
+
(the `--dir` when one is given, else the bundle root), counted **relatively**:
|
|
288
|
+
`--depth 1` is the top of the tree, `--dir X --depth 1` is one branch of it, and
|
|
289
|
+
the pair walks down a level at a time.
|
|
290
|
+
|
|
291
|
+
**On a bundle of any size the map is unreadable whole** — every directory is a
|
|
292
|
+
section, and even `--no-body` keeps one listing row per *concept* — so narrow
|
|
293
|
+
rather than paging it: `okf dirs` is the orientation, `--dir <branch> --depth 1`
|
|
294
|
+
is the step down into it,
|
|
295
|
+
and `--except body,listing` on top of either is the lean JSON skeleton. Full
|
|
296
|
+
`index` output on a few hundred concepts runs to hundreds of KB; the same map at
|
|
297
|
+
`--depth 1` is a couple of KB.
|
|
298
|
+
|
|
299
|
+
`--no-body` drops the prose to a
|
|
278
300
|
skeleton (headers, rollups, child pointers). For a directory that has concepts but
|
|
279
301
|
**no `index.md`**, the listing is **synthesized** from the concepts' descriptions
|
|
280
302
|
and tagged `(no index.md)` — §6 explicitly permits synthesizing a map on the fly.
|
|
@@ -283,7 +305,49 @@ It is a **read view**: advisory, always exit 0. A synthesized directory is a
|
|
|
283
305
|
*signal* (a map worth writing), never a defect — `index` emits no lint findings and
|
|
284
306
|
never fails a bundle. JSON: `{ bundle, count, directories: [{ dir, index_path,
|
|
285
307
|
present, synthesized, count, types, tags, subdirs, body, listing: [{ id, title,
|
|
286
|
-
description, type, tags }] }] }
|
|
308
|
+
description, type, tags }] }] }` — `ancestor` marks a row that is there to place
|
|
309
|
+
the branch rather than to answer about it.
|
|
310
|
+
|
|
311
|
+
## dirs — the bundle's clusters and their sizes
|
|
312
|
+
|
|
313
|
+
`okf dirs <dir>` lists every directory the bundle has — the ones holding
|
|
314
|
+
concepts, the ones carrying an `index.md`, and the empty intermediates that only
|
|
315
|
+
exist to connect the tree — with the number of concepts living **directly** in
|
|
316
|
+
each and the number in its **subtree**. A cluster *is* a directory here, so this
|
|
317
|
+
is the view that tells you what `--dir` can be pointed at and how much sits
|
|
318
|
+
behind each choice.
|
|
319
|
+
|
|
320
|
+
Two numbers, because one cannot answer the question. `count` is direct, so the
|
|
321
|
+
column sums to the bundle's concept total and a dir holding only sub-directories
|
|
322
|
+
reads `0` rather than a hidden rollup. `subtree` is defined as *exactly what
|
|
323
|
+
`--dir <that row>` returns*, so the row and the flag can never disagree — which
|
|
324
|
+
is also why the root's subtree is its own direct count (`.` is a prefix of
|
|
325
|
+
nothing). Without it a truncated listing is all zeroes at the top of a deep tree,
|
|
326
|
+
which is where you most need to know where the mass is. The human table shows the
|
|
327
|
+
second column only where some dir actually nests.
|
|
328
|
+
|
|
329
|
+
`--dir PATH` (repeatable) narrows to a directory and its subtree, and brings the
|
|
330
|
+
**chain up to the root** with it so the branch is placed rather than shown
|
|
331
|
+
adrift — those rows are marked `↑`, carry `ancestor: true`, and stay out of
|
|
332
|
+
`total` (`--no-ancestors` drops them). `--depth N` keeps only N levels below the
|
|
333
|
+
starting point — the `--dir` when one is given,
|
|
334
|
+
the bundle root otherwise. Relative, not absolute, so `--dir a/b --depth 1`
|
|
335
|
+
reads "a/b and one level under it" without your first working out how deep `a/b`
|
|
336
|
+
is. `--depth 0` is the starting point alone. A `--depth` that is not a whole
|
|
337
|
+
number is a usage error (exit 2).
|
|
338
|
+
|
|
339
|
+
**This is the first command to run on a bundle you do not know** — the same first
|
|
340
|
+
move [SKILL.md](../SKILL.md) prescribes. `okf dirs <dir>` is one row per
|
|
341
|
+
directory, so its size tracks the tree rather than the concept count: it tells
|
|
342
|
+
you the shape and where the weight sits, `--depth 1` trims it further on a deep
|
|
343
|
+
bundle, and you then descend with `okf index --dir`, one level at a time.
|
|
344
|
+
|
|
345
|
+
The root prints `(root)` and stores `.` — the split every grouped view keeps, so
|
|
346
|
+
a table and its `--json` never disagree about which spelling is the data. JSON:
|
|
347
|
+
`{ bundle, total, count, dirs: [{ dir, ancestor, count, subtree, subdirs }] }`,
|
|
348
|
+
root first. `count` is rows printed, chain included; `total` sums the direct
|
|
349
|
+
counts of the rows you actually asked for, which is what keeps a row's `subtree`
|
|
350
|
+
equal to the `total` that `--dir` on that row returns.
|
|
287
351
|
|
|
288
352
|
## catalog / files / tags / types / stats — the server views, as text
|
|
289
353
|
|
|
@@ -293,15 +357,16 @@ All are advisory reads (exit 0) sharing one data source (per-concept metadata pl
|
|
|
293
357
|
in/out link degree). Add `--json` to any for a machine substrate.
|
|
294
358
|
|
|
295
359
|
- **`catalog`** — every concept with its metadata (type, status, tags, timestamp,
|
|
296
|
-
in/out link degree, description), grouped by top-level
|
|
360
|
+
in/out link degree, description), grouped by top-level dir (`dir` on every row
|
|
361
|
+
carries the full path, `top_dir` the first segment). The "what's here, in
|
|
297
362
|
detail" view. JSON: `{ bundle, count, concepts: [{ id, title, type, description,
|
|
298
|
-
tags, timestamp, status, backlog_ref, dir,
|
|
363
|
+
tags, timestamp, status, backlog_ref, dir, top_dir, links_out, links_in }] }`.
|
|
299
364
|
- **`files`** — the folder tree: each concept's filename + title, grouped by
|
|
300
365
|
directory. The "how it's organised" view. JSON: `{ bundle, count, files: [{ path,
|
|
301
366
|
id, dir, type, title, description }] }`.
|
|
302
367
|
- **`tags`** — every tag with the concepts that carry it, ordered by count
|
|
303
368
|
descending. The "what themes dominate" view. JSON: `{ bundle, count, tags: [{ tag,
|
|
304
|
-
count, concepts: [id, …] }] }`. `--by type|
|
|
369
|
+
count, concepts: [id, …] }] }`. `--by type|dir` regroups the list per concept
|
|
305
370
|
dimension with **within-group** counts (a tag spanning groups appears in each);
|
|
306
371
|
each row also carries the tag's **total** across the narrowed set, printed
|
|
307
372
|
`count/total` when they differ — so a tag's locality reads per row (a plain
|
|
@@ -313,18 +378,32 @@ in/out link degree). Add `--json` to any for a machine substrate.
|
|
|
313
378
|
- **`types`** — every type with the concepts that carry it, ordered by count
|
|
314
379
|
descending. The "what kinds of knowledge" view. JSON: `{ bundle, count, types:
|
|
315
380
|
[{ type, count, concepts: [id, …] }] }`.
|
|
316
|
-
- **`stats`** — bundle rollups: concept /
|
|
317
|
-
totals plus per-type and per-
|
|
318
|
-
`{ bundle, concepts,
|
|
381
|
+
- **`stats`** — bundle rollups: concept / dir / type / cross-link / distinct-tag
|
|
382
|
+
totals plus per-type and per-dir breakdowns. The "shape at a glance" view. JSON:
|
|
383
|
+
`{ bundle, concepts, dirs, top_dirs, concept_types, cross_links, distinct_tags,
|
|
384
|
+
by_type, by_dir, by_top_dir }` (`top_dirs`/`by_top_dir` are the first-segment
|
|
385
|
+
rollup). `dirs`/`by_dir` cover every directory `okf dirs`
|
|
386
|
+
lists — counts are direct, so a directory holding nothing itself is present at
|
|
387
|
+
`0` rather than missing, and `by_dir.keys` is a complete list of what `--dir`
|
|
388
|
+
can address.
|
|
319
389
|
|
|
320
390
|
The four list views narrow with the same filters the browser panels offer —
|
|
321
|
-
`--type TYPE`, `--
|
|
322
|
-
itself (`tags` can't filter by tag). Matching is case-insensitive and
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
391
|
+
`--type TYPE`, `--dir PATH`, `--tag TAG`; each takes the ones orthogonal to
|
|
392
|
+
itself (`tags` can't filter by tag). Matching is case-insensitive; `--type` and
|
|
393
|
+
`--tag` are exact, `--dir` takes the named directory **and everything below it**
|
|
394
|
+
(`--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). A
|
|
396
|
+
filter that matches nothing is an empty view, not an error: `okf tags <dir> --dir
|
|
397
|
+
billing --json` answers "which tags does the billing cluster use?",
|
|
398
|
+
`okf catalog <dir> --tag auth` answers "what carries the auth tag?".
|
|
399
|
+
|
|
400
|
+
**`--area` is deprecated.** It still works — matching the *first path segment*
|
|
401
|
+
only, its old behavior unchanged — and prints `warning: --area is deprecated, use
|
|
402
|
+
--dir` on stderr (stdout stays clean, so a `--json` consumer is unaffected). Same
|
|
403
|
+
for `tags --by area`. Both go in a later release; write `--dir` in anything new.
|
|
404
|
+
On `index` it combines with neither `--depth` nor `--dir` — exit 2, because it is
|
|
405
|
+
*exact* and both of those select a range, so the pair used to return the area
|
|
406
|
+
plus whatever the other flag selected: an answer to neither question.
|
|
328
407
|
|
|
329
408
|
Reach for `stats` first to size a bundle, `catalog`/`files` to enumerate it, `tags`
|
|
330
409
|
to find thematic clusters — all without standing up the server.
|
|
@@ -340,10 +419,13 @@ in a body render as diagrams, and a click (or tap) opens the diagram full
|
|
|
340
419
|
screen with drag-to-pan and wheel/pinch zoom. Concepts render as nodes
|
|
341
420
|
coloured by `type` and sized by degree, links as edges, with a detail panel
|
|
342
421
|
(rendered markdown, "Links to" / "Linked from" backlinks), layout switching,
|
|
343
|
-
type/
|
|
422
|
+
type/dir/tag filters on every view (the dir chips take a directory *and* its
|
|
423
|
+
subtree, the same rule `--dir` uses), and search. Cluster mode groups the
|
|
424
|
+
concepts into one box per directory, nested to a depth picked beside the layout
|
|
425
|
+
select — depth 1 is the flat view, and a flat bundle is offered no control. The authored layer is in the
|
|
344
426
|
UI too: the Files view carries **Files | Indexes** tabs — the Indexes tab
|
|
345
427
|
lists the log first (the chronological index), then every `index.md` — and
|
|
346
|
-
folder nodes in file-tree mode and
|
|
428
|
+
folder nodes in file-tree mode and directory boxes in cluster mode open a
|
|
347
429
|
directory's §6 map in the inspector (authored, or synthesized when none
|
|
348
430
|
exists). Links to an `index.md`, `log.md`, or bare directory navigate instead
|
|
349
431
|
of dead-ending, and the log is fetched fresh on every read, so a
|
|
@@ -360,20 +442,38 @@ page listing the hosted bundles, so a stale bookmark after a rename gets a way
|
|
|
360
442
|
home. With **no** dir it serves the *persistent registry*, a plain JSON file
|
|
361
443
|
under `$OKF_HOME` (default `~/.okf`), managed by the
|
|
362
444
|
`okf registry` umbrella — like git's `remote` family, and split by what each
|
|
363
|
-
verb keys on.
|
|
445
|
+
verb keys on.
|
|
446
|
+
**`okf registry init`** creates a *project-local* registry instead: a
|
|
447
|
+
`.okf-registry.json` in the current directory, which okf discovers by walking up
|
|
448
|
+
from the working directory and uses in place of the global one while you are
|
|
449
|
+
inside its tree (the nearest wins, so nested registries resolve nearest-first).
|
|
450
|
+
Every registry op — and every `@slug` — then resolves through it, so a bare
|
|
451
|
+
`okf server` inside a repo serves that repo's bundles with no `$OKF_HOME` setup;
|
|
452
|
+
`okf registry list` names the local file it found. `OKF_NO_DISCOVERY=1` forces
|
|
453
|
+
the global registry — the escape hatch for a fixed-cwd caller (CI, a tool). A
|
|
454
|
+
local registry stores **portable** paths: a bundle inside its tree is written
|
|
455
|
+
relative to the `.okf-registry.json`, so committing the file lets it travel with
|
|
456
|
+
the repo (a checkout elsewhere, a container mounting it) and resolve unchanged;
|
|
457
|
+
a bundle outside the tree stays absolute, since it cannot travel. Paths still read
|
|
458
|
+
back absolute wherever the CLI reports them.
|
|
459
|
+
**Entry verbs** take a path: `okf registry set <dir>` adds it
|
|
364
460
|
(slug from the basename, or `--as`, which errors on a collision; `--default`
|
|
365
461
|
puts it first), and because the entry is keyed by path, `set` on an
|
|
366
462
|
already-registered dir updates it in place — refreshing its title, and renaming
|
|
367
|
-
it when `--as` is given. `okf registry del <dir|@slug>` removes
|
|
368
|
-
directory is already gone still deletes
|
|
463
|
+
it when `--as` is given. `okf registry del <dir|@slug>` removes a bundle *or* a group — by name, so an
|
|
464
|
+
entry whose directory is already gone still deletes, and removing a bundle
|
|
465
|
+
**cascade-drops** it from every group that named it (a group emptied that way is
|
|
466
|
+
deleted). Slug *or* dir, never both readings at
|
|
369
467
|
once: an argument with a `/` in it names a location and only a location, so
|
|
370
468
|
`del ./notes` refuses when no entry points there rather than stripping to the
|
|
371
469
|
slug `notes` and deleting a bundle somewhere else entirely.
|
|
372
470
|
<!-- rule:okf-registry-del-path-or-slug -->
|
|
373
471
|
**Slug verbs** take the name — bare, or as an `@slug`: `okf registry default <@slug>`
|
|
374
|
-
chooses which bundle `/` opens **by moving that entry to the front
|
|
375
|
-
|
|
376
|
-
|
|
472
|
+
chooses which bundle `/` opens **by moving that entry to the front** (a group is
|
|
473
|
+
refused — the default is one bundle), and
|
|
474
|
+
`okf registry rename <@slug> <new>` renames a bundle *or* group slug (mount path
|
|
475
|
+
and switcher name), **cascading** the new name into every group's member list —
|
|
476
|
+
`<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
|
|
377
477
|
default** — that is the whole rule, so the first bundle you register is the
|
|
378
478
|
default until you move another one, a rename keeps its position, and a `del`
|
|
379
479
|
promotes whatever is next. A vanished directory is stepped over (the server
|
|
@@ -382,11 +482,25 @@ cannot open one, so starring it would name a bundle `/` never serves), and
|
|
|
382
482
|
gives a directory that is not there. The file is hand-editable and reorders
|
|
383
483
|
visibly, which is the point: there is no stored slug that can dangle.
|
|
384
484
|
<!-- rule:okf-registry-default-position -->
|
|
485
|
+
**Group verbs** name a *set* of bundles under one slug — a durable subset for the
|
|
486
|
+
two verbs that take several bundles. `okf registry group <slug> <@member…>`
|
|
487
|
+
creates a group, or adds members to one (a union); members are bundle *or* group
|
|
488
|
+
slugs, so groups nest. A group shares the slug namespace with bundles (a slug
|
|
489
|
+
names one *or* the other, never both), `all` stays reserved, and a member set that
|
|
490
|
+
would make the group reach itself is refused. `okf registry ungroup <slug>
|
|
491
|
+
<@member…>` removes members; emptying a group deletes it. A group resolves,
|
|
492
|
+
recursively and path-deduped, to its bundle leaves — which **only `okf search`
|
|
493
|
+
and `okf server` consume**: every single-bundle verb (`lint`, `index`, …) refuses
|
|
494
|
+
a `@group` with exit 2, the same rule that refuses a second bundle. `@all` is
|
|
495
|
+
unchanged — it still names every registered *bundle*, groups being named subsets
|
|
496
|
+
of that.
|
|
385
497
|
`okf registry list` (or a bare
|
|
386
498
|
`okf registry`) stars the default and flags vanished dirs `(missing)` — the
|
|
387
|
-
server skips those with a note
|
|
499
|
+
server skips those with a note — and lists any groups with their members and
|
|
500
|
+
resolved leaf count; `--json` answers
|
|
388
501
|
`{ registry: <file>, count, bundles: [{ slug, title, dir, mount, default,
|
|
389
|
-
missing }] }`, naming the file it read so a
|
|
502
|
+
missing }], groups: [{ slug, members, resolved }] }`, naming the file it read so a
|
|
503
|
+
`$OKF_HOME` mismatch is visible. The hub roster is a
|
|
390
504
|
**boot-time snapshot**: restart `okf server` after registry changes. Behind a
|
|
391
505
|
hub the page gains a **bundle switcher** (⌘/Ctrl-K, or the rail button with its
|
|
392
506
|
bundle-count badge): the current bundle is pinned, the default chipped; ⏎
|
|
@@ -399,7 +513,10 @@ them all with the registry's first entry still on disk at `/` — the way to kee
|
|
|
399
513
|
several bundles a keystroke apart without re-passing paths.
|
|
400
514
|
`okf server @a @b` serves a registry subset, each mounted under its registered
|
|
401
515
|
slug — but as with any dirs-given run, the *first argument* lands at `/`; the
|
|
402
|
-
registry's own order applies only to the bundle-less run.
|
|
516
|
+
registry's own order applies only to the bundle-less run. A `@group` argument
|
|
517
|
+
fans out to its member bundles in the same way (`okf server @backend`), its first
|
|
518
|
+
member landing at `/`; `okf search @group <term…>` merges the group's members
|
|
519
|
+
into one ranking, exactly as naming them individually would.
|
|
403
520
|
|
|
404
521
|
**Trust boundary:** the page renders each fetched markdown body through
|
|
405
522
|
DOMPurify and escapes everything it inlines (every `<` in the graph data is
|
|
@@ -440,8 +557,30 @@ only when the task truly consumes every body; for one question, the
|
|
|
440
557
|
|
|
441
558
|
`--hubs` swaps the dump for the **inbound ranking**: every concept with at
|
|
442
559
|
least one inbound link, ranked by inbound degree, each with its links grouped
|
|
443
|
-
by *source
|
|
560
|
+
by *source top-level dir* (`core/status ×3 flows 2, billing 1`) — the evidence for
|
|
444
561
|
[refine](../playbooks/refine.md)'s hub origin test ("is this hub well-homed?").
|
|
445
562
|
A source at the bundle root counts under `(root)`. JSON: `{ bundle, count,
|
|
446
|
-
hubs: [{ id,
|
|
563
|
+
hubs: [{ id, top_dir, inbound, by_top_dir: { <top_dir>: n } }] }`. Advisory read, exit 0;
|
|
447
564
|
`--minimal`/`--no-body` shape node payloads and change nothing here.
|
|
565
|
+
|
|
566
|
+
`--traffic` asks the same question one grain coarser: **directories**, not
|
|
567
|
+
concepts. Every concept collapses into the directory it lives in and every link
|
|
568
|
+
between two directories collapses into one weighted arc, so a bundle's wiring
|
|
569
|
+
becomes a table you can read — measured on one 47-concept bundle, 227 links
|
|
570
|
+
collapsed into 50 arcs, of which the fitted cut draws 22. Each row carries the
|
|
571
|
+
directory's traffic split three ways
|
|
572
|
+
(`internal` / `out` / `in`) plus **cohesion**, its internal share of the total:
|
|
573
|
+
the evidence for [refine](../playbooks/refine.md)'s container test, where
|
|
574
|
+
`--hubs` only ever answered about concepts. Rows lead with the lowest cohesion,
|
|
575
|
+
so the directories with a case to answer come first, and a directory with no
|
|
576
|
+
traffic at all prints `—` rather than a `0%` it did not earn.
|
|
577
|
+
|
|
578
|
+
`--cut N` is the least arc weight drawn. It defaults to a value **fitted to the
|
|
579
|
+
bundle** — enough arcs for roughly 1.5 per directory, floored at 8 — because a
|
|
580
|
+
fixed weight cannot serve both ends: measured at weight 3 across ten bundles it
|
|
581
|
+
left 2 arcs on one and 136 on another. The JSON says which you got. Cohesion is
|
|
582
|
+
computed over *every* arc and never the drawn ones, so tightening the cut
|
|
583
|
+
changes the picture and never the evidence. JSON: `{ bundle, cut, fitted, dirs:
|
|
584
|
+
[{ dir, parent, count, subtree, internal, out, in, cohesion }], arcs: [{ source,
|
|
585
|
+
target, weight }], total_arcs }` — a fraction of the full dump (2.6 KB against
|
|
586
|
+
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
|
@@ -25,6 +25,15 @@ module OKF
|
|
|
25
25
|
value.respond_to?(:empty?) ? value.empty? : false
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
# The directory a concept lives in, derived from its §2 id: the id *is* the
|
|
29
|
+
# path minus `.md`, so putting the suffix back and taking the dirname is the
|
|
30
|
+
# definition rather than a parse of it. One home for it because three views
|
|
31
|
+
# answer with a `dir` — the catalog, the search rows, the linter's per-directory
|
|
32
|
+
# checks — and a rule spelled three times is three things to keep in step.
|
|
33
|
+
def self.dir_of(id)
|
|
34
|
+
File.dirname("#{id}.md")
|
|
35
|
+
end
|
|
36
|
+
|
|
28
37
|
require "okf/version"
|
|
29
38
|
|
|
30
39
|
# ── kernel: cross-cutting primitives ──
|
|
@@ -39,6 +48,7 @@ module OKF
|
|
|
39
48
|
require "okf/concept"
|
|
40
49
|
require "okf/bundle"
|
|
41
50
|
require "okf/bundle/graph"
|
|
51
|
+
require "okf/bundle/skeleton"
|
|
42
52
|
require "okf/bundle/search"
|
|
43
53
|
# These two lines ARE the engine preference order. Each engine registers itself
|
|
44
54
|
# 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.12.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rodrigo Serradura
|
|
@@ -54,11 +54,22 @@ dependencies:
|
|
|
54
54
|
description: |
|
|
55
55
|
OKF (Open Knowledge Format) is portable knowledge: Markdown files with YAML
|
|
56
56
|
frontmatter that both humans and agents read from one source. This gem is the
|
|
57
|
-
Ruby-native way to work with it.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
Ruby-native way to work with it.
|
|
58
|
+
|
|
59
|
+
Its companion agent skill authors and curates a bundle. The `okf` command-line
|
|
60
|
+
tool validates the result for v0.1 (§9) conformance, lints its curation
|
|
61
|
+
quality, and answers questions about it: ranked full-text search, and a
|
|
62
|
+
progressive-disclosure map that reads a large bundle a directory at a time
|
|
63
|
+
rather than loading it whole. `okf server` opens it as an interactive
|
|
64
|
+
knowledge graph and `okf render` bakes that same page into one self-contained
|
|
65
|
+
HTML file you can host anywhere. A per-user registry names your bundles, so
|
|
66
|
+
every verb reaches them by @slug from any directory and one search can span
|
|
67
|
+
them all.
|
|
68
|
+
|
|
69
|
+
Everything the CLI does also runs in-process through a library API
|
|
70
|
+
(OKF::Bundle and friends), and the graph server is a mountable Rack app. It
|
|
71
|
+
adds no service to your stack: rack, webrick and minifts are the only runtime
|
|
72
|
+
dependencies, and it runs on every Ruby since 2.4.
|
|
62
73
|
email:
|
|
63
74
|
- rodrigo.serradura@gmail.com
|
|
64
75
|
executables:
|
|
@@ -82,12 +93,14 @@ files:
|
|
|
82
93
|
- lib/okf/bundle/search.rb
|
|
83
94
|
- lib/okf/bundle/search/index.rb
|
|
84
95
|
- lib/okf/bundle/search/scan.rb
|
|
96
|
+
- lib/okf/bundle/skeleton.rb
|
|
85
97
|
- lib/okf/bundle/validator.rb
|
|
86
98
|
- lib/okf/bundle/validator/result.rb
|
|
87
99
|
- lib/okf/bundle/writer.rb
|
|
88
100
|
- lib/okf/cli.rb
|
|
89
101
|
- lib/okf/cli/catalog.rb
|
|
90
102
|
- lib/okf/cli/command.rb
|
|
103
|
+
- lib/okf/cli/dirs.rb
|
|
91
104
|
- lib/okf/cli/files.rb
|
|
92
105
|
- lib/okf/cli/graph.rb
|
|
93
106
|
- lib/okf/cli/index.rb
|
|
@@ -160,6 +173,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
160
173
|
requirements: []
|
|
161
174
|
rubygems_version: 4.0.16
|
|
162
175
|
specification_version: 4
|
|
163
|
-
summary: 'The complete
|
|
164
|
-
|
|
176
|
+
summary: 'The complete Open Knowledge Format toolkit: an agent skill, a CLI and library,
|
|
177
|
+
ranked search, and a live knowledge graph. 100% local.'
|
|
165
178
|
test_files: []
|