omkit 0.8.4 → 0.8.6
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/dist/cli/commands/ls.d.ts +12 -1
- package/dist/cli/commands/ls.js +18 -5
- package/dist/cli/ui/views/OmList.d.ts +7 -1
- package/dist/cli/ui/views/OmList.js +15 -6
- package/dist/client/order.d.ts +21 -0
- package/dist/client/order.js +26 -0
- package/dist/skill/model.js +5 -2
- package/package.json +1 -1
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { RegistrationSet, Registry } from "../../client/registry.ts";
|
|
2
2
|
export interface FormatOptions {
|
|
3
3
|
readonly json?: boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Where om depth is measured from for the listing order. Defaults to the working directory —
|
|
6
|
+
* the same root the interactive picker measures from, so `ls` and the picker agree.
|
|
7
|
+
*/
|
|
8
|
+
readonly root?: string;
|
|
4
9
|
/**
|
|
5
10
|
* What the oms and actions declare, from the discovery fork. Present only under
|
|
6
11
|
* `--describe`: reading it costs an import of every candidate file, which is why plain
|
|
@@ -8,5 +13,11 @@ export interface FormatOptions {
|
|
|
8
13
|
*/
|
|
9
14
|
readonly registrations?: RegistrationSet;
|
|
10
15
|
}
|
|
11
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Render a {@link Registry} for the terminal (plain text) or as JSON.
|
|
18
|
+
*
|
|
19
|
+
* Oms are listed with {@link byNesting} — the core workflows near the root first — in both
|
|
20
|
+
* modes, and in the registrations too, since under `--describe` the JSON `oms` key is theirs.
|
|
21
|
+
* Actions keep discovery order: they are looked up by name, not browsed.
|
|
22
|
+
*/
|
|
12
23
|
export declare function formatRegistry(registry: Registry, opts?: FormatOptions): string;
|
package/dist/cli/commands/ls.js
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
|
|
2
|
+
import { byNesting } from "../../client/order.js";
|
|
3
|
+
/**
|
|
4
|
+
* Render a {@link Registry} for the terminal (plain text) or as JSON.
|
|
5
|
+
*
|
|
6
|
+
* Oms are listed with {@link byNesting} — the core workflows near the root first — in both
|
|
7
|
+
* modes, and in the registrations too, since under `--describe` the JSON `oms` key is theirs.
|
|
8
|
+
* Actions keep discovery order: they are looked up by name, not browsed.
|
|
9
|
+
*/
|
|
3
10
|
export function formatRegistry(registry, opts = {}) {
|
|
11
|
+
const order = byNesting(opts.root ?? process.cwd());
|
|
12
|
+
const oms = [...registry.oms].sort(order);
|
|
13
|
+
const registrations = opts.registrations && {
|
|
14
|
+
...opts.registrations,
|
|
15
|
+
oms: [...opts.registrations.oms].sort(order),
|
|
16
|
+
};
|
|
4
17
|
if (opts.json)
|
|
5
|
-
return renderJson(registry,
|
|
6
|
-
const declared = index(
|
|
18
|
+
return renderJson({ ...registry, oms }, registrations);
|
|
19
|
+
const declared = index(registrations);
|
|
7
20
|
const lines = [
|
|
8
|
-
`oms (${
|
|
9
|
-
...
|
|
21
|
+
`oms (${oms.length})`,
|
|
22
|
+
...oms.flatMap((om) => row(`${om.name} ${path.basename(om.file)}:${om.line}`, [], declared?.get(key(om.name, om.file)))),
|
|
10
23
|
"",
|
|
11
24
|
`actions (${registry.actions.length})`,
|
|
12
25
|
...registry.actions.flatMap((a) => row(`${a.name} ${path.basename(a.file)}`, [a.publishesCapability ? "ref" : "", a.events ? "events" : ""], declared?.get(key(a.name, a.file)))),
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { type ReactElement } from "react";
|
|
2
2
|
import type { DiscoveredOm } from "../../../client/registry.ts";
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* A searchable, arrow-navigable list of oms; Enter selects the highlighted one.
|
|
5
|
+
*
|
|
6
|
+
* Rows are ordered by {@link byNesting} from the working directory — the same root the path
|
|
7
|
+
* column is rendered from, so the order matches what the column shows: the oms nearest the
|
|
8
|
+
* top of the project first, deeper ones after, and any shown as an absolute path last.
|
|
9
|
+
*/
|
|
4
10
|
export declare function OmList({ oms, onSelect, }: {
|
|
5
11
|
oms: DiscoveredOm[];
|
|
6
12
|
onSelect: (om: DiscoveredOm) => void;
|
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import {} from "react";
|
|
3
|
+
import { useMemo } from "react";
|
|
4
4
|
import { Text } from "ink";
|
|
5
5
|
import { SearchableList } from "./SearchableList.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
import { byNesting } from "../../../client/order.js";
|
|
7
|
+
/** Show the om's path relative to `root` when it's inside it; else the absolute path. */
|
|
8
|
+
function displayPath(file, root) {
|
|
9
|
+
const rel = path.relative(root, file);
|
|
9
10
|
return rel && !rel.startsWith("..") && !path.isAbsolute(rel) ? rel : file;
|
|
10
11
|
}
|
|
11
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* A searchable, arrow-navigable list of oms; Enter selects the highlighted one.
|
|
14
|
+
*
|
|
15
|
+
* Rows are ordered by {@link byNesting} from the working directory — the same root the path
|
|
16
|
+
* column is rendered from, so the order matches what the column shows: the oms nearest the
|
|
17
|
+
* top of the project first, deeper ones after, and any shown as an absolute path last.
|
|
18
|
+
*/
|
|
12
19
|
export function OmList({ oms, onSelect, }) {
|
|
20
|
+
const root = process.cwd();
|
|
21
|
+
const sorted = useMemo(() => [...oms].sort(byNesting(root)), [oms, root]);
|
|
13
22
|
// Column width so paths line up; capped so one long name can't push paths off-screen.
|
|
14
23
|
const nameWidth = Math.min(30, oms.reduce((w, o) => Math.max(w, o.name.length), 0));
|
|
15
|
-
return (_jsx(SearchableList, { items:
|
|
24
|
+
return (_jsx(SearchableList, { items: sorted, getKey: (o) => o.name, getSearchText: (o) => o.name, onSelect: onSelect, renderRow: (o, selected) => (_jsxs(Text, { children: [_jsx(Text, { color: selected ? "cyan" : undefined, children: selected ? "❯ " : " " }), _jsx(Text, { bold: selected, children: o.name.padEnd(nameWidth) }), " ", _jsx(Text, { dimColor: true, children: displayPath(o.file, root) })] })) }));
|
|
16
25
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** What the listing order needs from an entry: its name, and where it is defined. */
|
|
2
|
+
export interface Located {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly file: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* How many directories lie between `root` and `file`: `oms/build.ts` is 1, `build.ts` is 0.
|
|
8
|
+
* A file outside the root is `Infinity`, so it lists after everything the root contains rather
|
|
9
|
+
* than at a depth invented from its `..` segments.
|
|
10
|
+
*/
|
|
11
|
+
export declare function nestingDepth(file: string, root: string): number;
|
|
12
|
+
/**
|
|
13
|
+
* The order a project's oms are presented in: shallowest first, then by name, then by file.
|
|
14
|
+
*
|
|
15
|
+
* Where an om sits says what it is for. The workflows at the top of a project are the ones
|
|
16
|
+
* people reach for every day; one three folders down is a specialised variant or a helper
|
|
17
|
+
* behind them. Listing by depth puts the core oms first without asking authors to rank them.
|
|
18
|
+
* Depth is measured from the root the listing renders its paths from, so the order matches
|
|
19
|
+
* the column it sits beside. The file tie-break keeps two same-named oms in a fixed order.
|
|
20
|
+
*/
|
|
21
|
+
export declare function byNesting(root: string): (a: Located, b: Located) => number;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
/**
|
|
3
|
+
* How many directories lie between `root` and `file`: `oms/build.ts` is 1, `build.ts` is 0.
|
|
4
|
+
* A file outside the root is `Infinity`, so it lists after everything the root contains rather
|
|
5
|
+
* than at a depth invented from its `..` segments.
|
|
6
|
+
*/
|
|
7
|
+
export function nestingDepth(file, root) {
|
|
8
|
+
const rel = path.relative(root, file);
|
|
9
|
+
if (rel === "" || rel.startsWith("..") || path.isAbsolute(rel))
|
|
10
|
+
return Infinity;
|
|
11
|
+
return rel.split(path.sep).length - 1;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The order a project's oms are presented in: shallowest first, then by name, then by file.
|
|
15
|
+
*
|
|
16
|
+
* Where an om sits says what it is for. The workflows at the top of a project are the ones
|
|
17
|
+
* people reach for every day; one three folders down is a specialised variant or a helper
|
|
18
|
+
* behind them. Listing by depth puts the core oms first without asking authors to rank them.
|
|
19
|
+
* Depth is measured from the root the listing renders its paths from, so the order matches
|
|
20
|
+
* the column it sits beside. The file tie-break keeps two same-named oms in a fixed order.
|
|
21
|
+
*/
|
|
22
|
+
export function byNesting(root) {
|
|
23
|
+
return (a, b) => nestingDepth(a.file, root) - nestingDepth(b.file, root) ||
|
|
24
|
+
a.name.localeCompare(b.name) ||
|
|
25
|
+
a.file.localeCompare(b.file);
|
|
26
|
+
}
|
package/dist/skill/model.js
CHANGED
|
@@ -2,6 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { shapeHint } from "../core/schema-hint.js";
|
|
4
4
|
import { DEFAULT_TSCONFIG } from "../client/types.js";
|
|
5
|
+
import { byNesting } from "../client/order.js";
|
|
5
6
|
/**
|
|
6
7
|
* Fold a project's registrations and its AST scan into the model the skill renders from.
|
|
7
8
|
*
|
|
@@ -16,10 +17,12 @@ export function buildSkillModel(registrations, registry, project) {
|
|
|
16
17
|
const { root } = project;
|
|
17
18
|
const outlines = new Map(registry.oms.map((o) => [key(o.name, o.file), o.calls]));
|
|
18
19
|
const capabilities = new Map(registry.actions.map((a) => [key(a.name, a.file), a.publishesCapability]));
|
|
20
|
+
// Oms are what a reader picks from, so the core ones — those nearest the root — lead.
|
|
21
|
+
// Actions are looked up by name from an om's outline, so alphabetical is their lookup order.
|
|
19
22
|
const oms = registrations.oms
|
|
20
23
|
.filter(isExposed)
|
|
21
|
-
.
|
|
22
|
-
.
|
|
24
|
+
.sort(byNesting(root))
|
|
25
|
+
.map((om) => omEntry(om, outlines.get(key(om.name, om.file)), root));
|
|
23
26
|
const actions = registrations.actions
|
|
24
27
|
.filter(isExposed)
|
|
25
28
|
.map((a) => actionEntry(a, capabilities.get(key(a.name, a.file)), root))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omkit",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.6",
|
|
4
4
|
"description": "A tiny runtime for developer workflows: typed actions that pass runtime capabilities and emit typed events, under one run and one shared log. The operational/runtime layer to tskb's knowledge layer.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|