@panaversity/ksor 0.0.31 → 0.0.32
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# @panaversity/ksor
|
|
2
2
|
|
|
3
|
+
## 0.0.32
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 658c496: One instruction per tool, as tabs.
|
|
8
|
+
|
|
9
|
+
A document that has to say the same thing two ways — one command for one agent,
|
|
10
|
+
another for another — can now put each in its own fenced block and give the
|
|
11
|
+
fence a `tab`:
|
|
12
|
+
|
|
13
|
+
````markdown
|
|
14
|
+
```bash tab="Claude Code" tab-group="agent"
|
|
15
|
+
curl -fsSL https://claude.ai/install.sh | bash
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```bash tab="OpenCode" tab-group="agent"
|
|
19
|
+
curl -fsSL https://opencode.ai/install | bash
|
|
20
|
+
```
|
|
21
|
+
````
|
|
22
|
+
|
|
23
|
+
Consecutive blocks declaring a `tab` become one tab group. **This is still
|
|
24
|
+
CommonMark** — a fence's info string is free text, so any other markdown reader
|
|
25
|
+
shows both blocks one after another, correct and readable, just without the
|
|
26
|
+
picker. Nothing framework-shaped enters `knowledge/`.
|
|
27
|
+
|
|
28
|
+
`tab-group` is the part worth knowing: blocks sharing a group name switch
|
|
29
|
+
together across the whole page, and the choice is remembered for the reader's
|
|
30
|
+
next visit. A document with ten tabbed sections is one decision rather than ten.
|
|
31
|
+
|
|
32
|
+
A tool the site recognises takes its own colour and mark on its tab — Claude
|
|
33
|
+
Code and OpenCode ship known. Anything else renders in the site's own accent,
|
|
34
|
+
which is the right default for tabs that are `npm`/`pnpm` or `US`/`EU`. The list
|
|
35
|
+
lives in `system/site/app/global.css` and is yours to extend or delete.
|
|
36
|
+
|
|
3
37
|
## 0.0.31
|
|
4
38
|
|
|
5
39
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@panaversity/ksor",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.32",
|
|
4
4
|
"description": "Knowledge System of Record — compile governed markdown into a static site for people and an MCP server for AI agents, with citations and measured abstention.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"abstention",
|
|
@@ -633,6 +633,35 @@ CI — and a first deploy without it serves an empty record. Full walkthrough:
|
|
|
633
633
|
Declaring both `deck:` and `slides.url:` is refused — two presentations with
|
|
634
634
|
nothing to say which one governs.
|
|
635
635
|
|
|
636
|
+
- **One instruction per tool, as tabs.** When a document has to say the same
|
|
637
|
+
thing two ways — one command for one agent, another for another — put each in
|
|
638
|
+
its own fenced block and give the fence a `tab`:
|
|
639
|
+
|
|
640
|
+
````markdown
|
|
641
|
+
```bash tab="Claude Code" tab-group="agent"
|
|
642
|
+
curl -fsSL https://claude.ai/install.sh | bash
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
```bash tab="OpenCode" tab-group="agent"
|
|
646
|
+
curl -fsSL https://opencode.ai/install | bash
|
|
647
|
+
```
|
|
648
|
+
````
|
|
649
|
+
|
|
650
|
+
Consecutive blocks that declare a `tab` become one tab group. This is still
|
|
651
|
+
CommonMark: a fence's info string is free text, so any other markdown reader
|
|
652
|
+
shows both blocks one after another — correct, just without the picker.
|
|
653
|
+
|
|
654
|
+
**`tab-group` is what makes the choice stick.** Blocks sharing a group name
|
|
655
|
+
switch together across the whole page and the choice is remembered for the
|
|
656
|
+
reader's next visit, so a document with ten tabbed sections is one decision
|
|
657
|
+
rather than ten. Leave it off and each group is independent, which is almost
|
|
658
|
+
never what you want. Use the same group name for the same axis throughout a
|
|
659
|
+
record.
|
|
660
|
+
|
|
661
|
+
A tool the site knows gets its own colour and mark on its tab; anything else
|
|
662
|
+
renders in the site's accent. The list lives in `system/site/app/global.css`
|
|
663
|
+
and is yours — adding a tool is one colour and one mark.
|
|
664
|
+
|
|
636
665
|
- Copy load-bearing values (numbers, thresholds, dates) exactly from their
|
|
637
666
|
source, and name the source in `provenance`.
|
|
638
667
|
|
|
@@ -274,6 +274,97 @@ html > body[data-scroll-locked] {
|
|
|
274
274
|
--ksor-caution: #e0906e;
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
+
/* A tool's own colour, across the whole block.
|
|
278
|
+
|
|
279
|
+
When a document gives one instruction per tool, the tab is the moment a
|
|
280
|
+
reader picks theirs, so the choice is worth being unmistakable. The colour
|
|
281
|
+
is not confined to the tab: the strip and the panel take a wash of it too,
|
|
282
|
+
in two different strengths, so the block says which tool you are reading at
|
|
283
|
+
any scroll position and the strip still reads as a distinct band.
|
|
284
|
+
|
|
285
|
+
Each tool declares ONE value and shared rules do the rest, so adding a tool
|
|
286
|
+
is a line rather than a set. `:has()` lifts the active tab's colour onto the
|
|
287
|
+
container, which is what lets the panel follow the tab.
|
|
288
|
+
|
|
289
|
+
Keyed on `data-tab-value`, which `components/mdx.tsx` puts on the trigger.
|
|
290
|
+
Radix also encodes the value in its generated id, but that is a private
|
|
291
|
+
format and keying on it would drop the branding silently if it changed.
|
|
292
|
+
|
|
293
|
+
THIS BLOCK IS YOURS. These are the tools this scaffold happened to know
|
|
294
|
+
about; a tab value matching nothing renders in the site's own accent, which
|
|
295
|
+
is the right default for a record whose tabs are npm/pnpm or US/EU. Add
|
|
296
|
+
your own, or delete the block — nothing else depends on it. Values are the
|
|
297
|
+
vendors' own. */
|
|
298
|
+
.prose [data-orientation]:has([data-tab-value="Claude Code"][data-state="active"]) {
|
|
299
|
+
--ksor-tool: #da7756;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.prose [data-orientation]:has([data-tab-value="OpenCode"][data-state="active"]) {
|
|
303
|
+
--ksor-tool: #6366f1;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/* A decorative mark per tool. Purely visual — the label beside it is the
|
|
307
|
+
accessible name — so it is CSS content rather than markup an author would
|
|
308
|
+
have to write. */
|
|
309
|
+
.prose [role="tab"][data-tab-value="Claude Code"]::before {
|
|
310
|
+
content: "\2726";
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.prose [role="tab"][data-tab-value="OpenCode"]::before {
|
|
314
|
+
content: "</>";
|
|
315
|
+
font-size: 0.85em;
|
|
316
|
+
letter-spacing: -0.05em;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/* Everything below is shared, and applies only where a tool was recognised. */
|
|
320
|
+
.prose [data-orientation]:has([data-tab-value][data-state="active"]) {
|
|
321
|
+
background-color: color-mix(in oklab, var(--ksor-tool) 7%, transparent);
|
|
322
|
+
border-color: color-mix(in oklab, var(--ksor-tool) 28%, transparent);
|
|
323
|
+
overflow: hidden;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/* The strip is a BAND: stronger than the panel, full width, and the tabs sit
|
|
327
|
+
inside it rather than floating above it. */
|
|
328
|
+
.prose [data-orientation]:has([data-tab-value][data-state="active"]) > [role="tablist"] {
|
|
329
|
+
background-color: color-mix(in oklab, var(--ksor-tool) 20%, transparent);
|
|
330
|
+
border-bottom: 1px solid color-mix(in oklab, var(--ksor-tool) 26%, transparent);
|
|
331
|
+
padding: 0.5rem;
|
|
332
|
+
gap: 0.25rem;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.prose [role="tab"][data-tab-value] {
|
|
336
|
+
display: inline-flex;
|
|
337
|
+
align-items: center;
|
|
338
|
+
gap: 0.5rem;
|
|
339
|
+
/* Big enough to be a target and to read as a block rather than a word. */
|
|
340
|
+
padding: 0.7rem 1.5rem;
|
|
341
|
+
font-size: 0.95rem;
|
|
342
|
+
font-weight: 600;
|
|
343
|
+
border-radius: 0.25rem;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.prose [role="tab"][data-tab-value][data-state="active"] {
|
|
347
|
+
background-color: var(--ksor-tool);
|
|
348
|
+
color: #fff;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.prose [role="tab"][data-tab-value][data-state="inactive"]:hover {
|
|
352
|
+
background-color: color-mix(in oklab, var(--ksor-tool) 14%, transparent);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/* The code sits INSET on the wash, with its own surface, so the panel reads as
|
|
356
|
+
a frame around it. A tinted block on a tinted panel is one colour with words
|
|
357
|
+
in it, and the code is the part somebody actually has to read. */
|
|
358
|
+
.prose [data-orientation]:has([data-tab-value][data-state="active"]) figure {
|
|
359
|
+
margin: 1.25rem;
|
|
360
|
+
background-color: var(--card);
|
|
361
|
+
border-color: color-mix(in oklab, var(--ksor-tool) 18%, transparent);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.dark .prose [data-orientation]:has([data-tab-value][data-state="active"]) figure {
|
|
365
|
+
background-color: color-mix(in oklab, var(--muted) 88%, #000);
|
|
366
|
+
}
|
|
367
|
+
|
|
277
368
|
/* The slide STAGE.
|
|
278
369
|
|
|
279
370
|
A slide is a projected surface, and reading as one at a glance is most of
|
|
@@ -1,9 +1,37 @@
|
|
|
1
1
|
import defaultMdxComponents from "fumadocs-ui/mdx";
|
|
2
|
+
import { CodeBlockTabsTrigger } from "fumadocs-ui/components/codeblock";
|
|
3
|
+
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
|
|
2
4
|
import type { MDXComponents } from "mdx/types";
|
|
5
|
+
import type * as React from "react";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A tab trigger that says WHICH tab it is, in an attribute we own.
|
|
9
|
+
*
|
|
10
|
+
* Radix already encodes the value in its generated `id`
|
|
11
|
+
* (`radix-…-trigger-Claude Code`), and styling could key on that — but that is
|
|
12
|
+
* a private format, so a change upstream would drop the branding silently and
|
|
13
|
+
* nothing would go red. One attribute of our own costs a few lines and cannot
|
|
14
|
+
* be taken away.
|
|
15
|
+
*
|
|
16
|
+
* `app/global.css` uses it to give a known tool its own colour; a tab value it
|
|
17
|
+
* does not recognise simply renders in the site's own accent.
|
|
18
|
+
*/
|
|
19
|
+
function BrandedTabsTrigger({
|
|
20
|
+
value,
|
|
21
|
+
...props
|
|
22
|
+
}: React.ComponentProps<typeof CodeBlockTabsTrigger>): React.ReactElement {
|
|
23
|
+
return <CodeBlockTabsTrigger data-tab-value={value} value={value} {...props} />;
|
|
24
|
+
}
|
|
3
25
|
|
|
4
26
|
export function getMDXComponents(components?: MDXComponents) {
|
|
5
27
|
return {
|
|
6
28
|
...defaultMdxComponents,
|
|
29
|
+
// `remarkCodeTab` (source.config.ts) rewrites consecutive fenced blocks
|
|
30
|
+
// that declare `tab="…"` into these, so they have to be in the map or the
|
|
31
|
+
// build fails on an unknown component rather than at authoring time.
|
|
32
|
+
Tabs,
|
|
33
|
+
Tab,
|
|
34
|
+
CodeBlockTabsTrigger: BrandedTabsTrigger,
|
|
7
35
|
...components,
|
|
8
36
|
} satisfies MDXComponents;
|
|
9
37
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { defineCollections, defineConfig, defineDocs } from "fumadocs-mdx/config";
|
|
2
|
+
import { remarkCodeTab } from "fumadocs-core/mdx-plugins/remark-code-tab";
|
|
2
3
|
import { metaSchema, pageSchema } from "fumadocs-core/source/schema";
|
|
3
4
|
import { z } from "zod";
|
|
4
5
|
import { DeckSchema } from "./lib/deck";
|
|
@@ -114,6 +115,28 @@ export const slides = defineCollections({
|
|
|
114
115
|
|
|
115
116
|
export default defineConfig({
|
|
116
117
|
mdxOptions: {
|
|
117
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Alternative versions of the same instruction, as TABS.
|
|
120
|
+
*
|
|
121
|
+
* A record often has to say the same thing twice — one way for one tool,
|
|
122
|
+
* one for another — and stacking both is how a reader follows the wrong
|
|
123
|
+
* one. `remarkCodeTab` turns consecutive fenced blocks that declare a
|
|
124
|
+
* `tab="…"` into a tab group.
|
|
125
|
+
*
|
|
126
|
+
* The reason this works HERE, where a JSX `<Tabs>` cannot: a fence's info
|
|
127
|
+
* string is free text in CommonMark. `\`\`\`bash tab="Claude Code"` is a
|
|
128
|
+
* perfectly ordinary bash block to every other markdown reader, which sees
|
|
129
|
+
* both blocks one after another and is not misled — it just does not get
|
|
130
|
+
* to pick. So the record stays framework-free (critical rule 2) and the
|
|
131
|
+
* site still renders the affordance.
|
|
132
|
+
*
|
|
133
|
+
* `CodeBlockTabs` rather than `Tabs`, and the difference is not cosmetic:
|
|
134
|
+
* only that branch honours `tab-group`, which is what makes ONE choice
|
|
135
|
+
* apply to every group on the page and persist to the next visit. The
|
|
136
|
+
* `Tabs` branch drops the attribute silently, so a reader with a
|
|
137
|
+
* ten-section document would pick their tool ten times (verified against
|
|
138
|
+
* fumadocs-core 16.14.5, remark-code-tab.js).
|
|
139
|
+
*/
|
|
140
|
+
remarkPlugins: [[remarkCodeTab, { Tabs: "CodeBlockTabs" }]],
|
|
118
141
|
},
|
|
119
142
|
});
|