@almadar/std 3.8.0 → 3.10.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.
- package/dist/behaviors/behaviors-registry.json +15946 -0
- package/dist/behaviors/index.d.ts +1 -0
- package/dist/behaviors/index.js +559 -454
- package/dist/behaviors/index.js.map +1 -1
- package/dist/behaviors/query.d.ts +81 -0
- package/dist/behaviors/query.js +132 -0
- package/dist/behaviors/query.js.map +1 -0
- package/dist/behaviors-registry.json +15946 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +559 -454
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Behavior Registry Query Helpers
|
|
3
|
+
*
|
|
4
|
+
* Programmatic access to behaviors-registry.json for filtering,
|
|
5
|
+
* searching, and summarizing behaviors. Used by @almadar/skills
|
|
6
|
+
* to compose agent prompts dynamically.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
interface RegistryEntry {
|
|
11
|
+
name: string;
|
|
12
|
+
level: 'atom' | 'molecule' | 'organism';
|
|
13
|
+
family: string;
|
|
14
|
+
layer: string;
|
|
15
|
+
description: string;
|
|
16
|
+
statePattern: string;
|
|
17
|
+
complexity: {
|
|
18
|
+
states: number;
|
|
19
|
+
events: number;
|
|
20
|
+
transitions: number;
|
|
21
|
+
};
|
|
22
|
+
defaultEntity: {
|
|
23
|
+
name: string;
|
|
24
|
+
persistence: string;
|
|
25
|
+
fields: Array<{
|
|
26
|
+
name: string;
|
|
27
|
+
type: string;
|
|
28
|
+
default?: string;
|
|
29
|
+
}>;
|
|
30
|
+
};
|
|
31
|
+
defaultLabels: {
|
|
32
|
+
title: string;
|
|
33
|
+
entitySingular: string;
|
|
34
|
+
entityPlural: string;
|
|
35
|
+
};
|
|
36
|
+
composableWith: string[];
|
|
37
|
+
connectableEvents: string[];
|
|
38
|
+
eventPayloads: Record<string, Array<{
|
|
39
|
+
name: string;
|
|
40
|
+
type: string;
|
|
41
|
+
required: boolean;
|
|
42
|
+
}>>;
|
|
43
|
+
}
|
|
44
|
+
interface BehaviorSummary {
|
|
45
|
+
name: string;
|
|
46
|
+
level: string;
|
|
47
|
+
description: string;
|
|
48
|
+
states: string[];
|
|
49
|
+
events: string[];
|
|
50
|
+
slots: string[];
|
|
51
|
+
patterns: string[];
|
|
52
|
+
complexity: {
|
|
53
|
+
states: number;
|
|
54
|
+
events: number;
|
|
55
|
+
transitions: number;
|
|
56
|
+
};
|
|
57
|
+
composableWith: string[];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Read and cache the behavior registry.
|
|
61
|
+
*/
|
|
62
|
+
declare function getBehaviorRegistry(): Record<string, RegistryEntry>;
|
|
63
|
+
/**
|
|
64
|
+
* Filter behaviors by domain. Matches against layer (primary) and family (fallback).
|
|
65
|
+
*/
|
|
66
|
+
declare function getBehaviorsByDomain(domain: string): RegistryEntry[];
|
|
67
|
+
/**
|
|
68
|
+
* Filter behaviors by connectable operations (events).
|
|
69
|
+
* Returns behaviors sorted by match count (most matching ops first).
|
|
70
|
+
*/
|
|
71
|
+
declare function getBehaviorsByOperations(ops: string[]): RegistryEntry[];
|
|
72
|
+
/**
|
|
73
|
+
* Fuzzy search across name, description, family, layer, and entity name.
|
|
74
|
+
*/
|
|
75
|
+
declare function searchBehaviors(query: string): RegistryEntry[];
|
|
76
|
+
/**
|
|
77
|
+
* Get a compact summary of a behavior including slots and patterns from the .orb file.
|
|
78
|
+
*/
|
|
79
|
+
declare function getBehaviorSummary(name: string): BehaviorSummary | null;
|
|
80
|
+
|
|
81
|
+
export { type BehaviorSummary, type RegistryEntry, getBehaviorRegistry, getBehaviorSummary, getBehaviorsByDomain, getBehaviorsByOperations, searchBehaviors };
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'fs';
|
|
2
|
+
import { dirname, resolve } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
// behaviors/query.ts
|
|
6
|
+
var __dirname$1 = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
var EXPORTS_DIR = resolve(__dirname$1, "exports");
|
|
8
|
+
var LEVEL_DIRS = ["atoms", "molecules", "organisms"];
|
|
9
|
+
function loadGoldenOrb(behaviorName) {
|
|
10
|
+
for (const level of LEVEL_DIRS) {
|
|
11
|
+
const orbPath = resolve(EXPORTS_DIR, level, `${behaviorName}.orb`);
|
|
12
|
+
if (existsSync(orbPath)) {
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(readFileSync(orbPath, "utf-8"));
|
|
15
|
+
} catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// behaviors/query.ts
|
|
24
|
+
var __dirname2 = dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
var REGISTRY_PATH = resolve(__dirname2, "behaviors-registry.json");
|
|
26
|
+
var registryCache = null;
|
|
27
|
+
function getBehaviorRegistry() {
|
|
28
|
+
if (registryCache) return registryCache;
|
|
29
|
+
try {
|
|
30
|
+
const raw = JSON.parse(readFileSync(REGISTRY_PATH, "utf-8"));
|
|
31
|
+
registryCache = raw.behaviors;
|
|
32
|
+
return registryCache;
|
|
33
|
+
} catch {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function getBehaviorsByDomain(domain) {
|
|
38
|
+
const registry = getBehaviorRegistry();
|
|
39
|
+
const lower = domain.toLowerCase();
|
|
40
|
+
return Object.values(registry).filter((b) => {
|
|
41
|
+
return b.layer.toLowerCase() === lower || b.layer.toLowerCase().includes(lower) || b.family.toLowerCase() === lower || b.family.toLowerCase().includes(lower);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function getBehaviorsByOperations(ops) {
|
|
45
|
+
const registry = getBehaviorRegistry();
|
|
46
|
+
const upperOps = ops.map((o) => o.toUpperCase());
|
|
47
|
+
const scored = Object.values(registry).map((b) => {
|
|
48
|
+
const matches = upperOps.filter(
|
|
49
|
+
(op) => b.connectableEvents.some((e) => e.toUpperCase() === op || e.toUpperCase().includes(op))
|
|
50
|
+
);
|
|
51
|
+
return { entry: b, score: matches.length };
|
|
52
|
+
});
|
|
53
|
+
return scored.filter((s) => s.score > 0).sort((a, b) => b.score - a.score).map((s) => s.entry);
|
|
54
|
+
}
|
|
55
|
+
function searchBehaviors(query) {
|
|
56
|
+
const registry = getBehaviorRegistry();
|
|
57
|
+
const tokens = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
58
|
+
const scored = Object.values(registry).map((b) => {
|
|
59
|
+
const searchText = [
|
|
60
|
+
b.name,
|
|
61
|
+
b.description,
|
|
62
|
+
b.family,
|
|
63
|
+
b.layer,
|
|
64
|
+
b.defaultEntity.name,
|
|
65
|
+
b.statePattern
|
|
66
|
+
].join(" ").toLowerCase();
|
|
67
|
+
const score = tokens.filter((t) => searchText.includes(t)).length;
|
|
68
|
+
return { entry: b, score };
|
|
69
|
+
});
|
|
70
|
+
return scored.filter((s) => s.score > 0).sort((a, b) => b.score - a.score).map((s) => s.entry);
|
|
71
|
+
}
|
|
72
|
+
function getBehaviorSummary(name) {
|
|
73
|
+
const registry = getBehaviorRegistry();
|
|
74
|
+
const entry = registry[name];
|
|
75
|
+
if (!entry) return null;
|
|
76
|
+
const summary = {
|
|
77
|
+
name: entry.name,
|
|
78
|
+
level: entry.level,
|
|
79
|
+
description: entry.description,
|
|
80
|
+
states: entry.statePattern.split(", ").filter(Boolean),
|
|
81
|
+
events: entry.connectableEvents,
|
|
82
|
+
slots: [],
|
|
83
|
+
patterns: [],
|
|
84
|
+
complexity: entry.complexity,
|
|
85
|
+
composableWith: entry.composableWith.slice(0, 10)
|
|
86
|
+
};
|
|
87
|
+
try {
|
|
88
|
+
const orb = loadGoldenOrb(name);
|
|
89
|
+
if (orb) {
|
|
90
|
+
const slots = /* @__PURE__ */ new Set();
|
|
91
|
+
const patterns = /* @__PURE__ */ new Set();
|
|
92
|
+
extractSlotsAndPatterns(orb, slots, patterns);
|
|
93
|
+
summary.slots = Array.from(slots);
|
|
94
|
+
summary.patterns = Array.from(patterns);
|
|
95
|
+
}
|
|
96
|
+
} catch {
|
|
97
|
+
}
|
|
98
|
+
return summary;
|
|
99
|
+
}
|
|
100
|
+
function extractSlotsAndPatterns(obj, slots, patterns) {
|
|
101
|
+
if (Array.isArray(obj)) {
|
|
102
|
+
if (obj.length >= 3 && obj[0] === "render-ui" && typeof obj[1] === "string") {
|
|
103
|
+
slots.add(obj[1]);
|
|
104
|
+
if (obj[2] && typeof obj[2] === "object") {
|
|
105
|
+
extractPatternTypes(obj[2], patterns);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
for (const item of obj) {
|
|
109
|
+
extractSlotsAndPatterns(item, slots, patterns);
|
|
110
|
+
}
|
|
111
|
+
} else if (obj && typeof obj === "object") {
|
|
112
|
+
for (const value of Object.values(obj)) {
|
|
113
|
+
extractSlotsAndPatterns(value, slots, patterns);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function extractPatternTypes(node, patterns) {
|
|
118
|
+
if (!node || typeof node !== "object") return;
|
|
119
|
+
const obj = node;
|
|
120
|
+
if (typeof obj.type === "string") {
|
|
121
|
+
patterns.add(obj.type);
|
|
122
|
+
}
|
|
123
|
+
if (Array.isArray(obj.children)) {
|
|
124
|
+
for (const child of obj.children) {
|
|
125
|
+
extractPatternTypes(child, patterns);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export { getBehaviorRegistry, getBehaviorSummary, getBehaviorsByDomain, getBehaviorsByOperations, searchBehaviors };
|
|
131
|
+
//# sourceMappingURL=query.js.map
|
|
132
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../behaviors/exports-reader.ts","../../behaviors/query.ts"],"names":["__dirname","dirname","fileURLToPath","resolve","readFileSync"],"mappings":"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","file":"query.js","sourcesContent":["/**\n * Exports Reader\n *\n * Provides programmatic access to the golden .orb files in behaviors/exports/.\n * Other packages import these functions instead of reading the filesystem directly.\n *\n * Directory structure mirrors functions/:\n * exports/atoms/*.orb\n * exports/molecules/*.orb\n * exports/organisms/*.orb\n *\n * @packageDocumentation\n */\n\nimport { readdirSync, readFileSync, existsSync } from 'fs';\nimport { resolve, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport type { BehaviorSchema } from './types.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst EXPORTS_DIR = resolve(__dirname, 'exports');\nconst LEVEL_DIRS = ['atoms', 'molecules', 'organisms'] as const;\n\nexport type BehaviorLevel = typeof LEVEL_DIRS[number];\n\n/** Read all .orb files from a single directory. */\nfunction readOrbDir(dir: string): Array<{ name: string; path: string }> {\n try {\n return readdirSync(dir)\n .filter((f: string) => f.endsWith('.orb'))\n .map((f: string) => ({ name: f.replace('.orb', ''), path: resolve(dir, f) }));\n } catch {\n return [];\n }\n}\n\n/** Read all .orb entries across atoms/molecules/organisms. */\nfunction readAllOrbEntries(): Array<{ name: string; path: string; level: BehaviorLevel }> {\n const entries: Array<{ name: string; path: string; level: BehaviorLevel }> = [];\n for (const level of LEVEL_DIRS) {\n for (const entry of readOrbDir(resolve(EXPORTS_DIR, level))) {\n entries.push({ ...entry, level });\n }\n }\n return entries;\n}\n\n/**\n * List all available golden behavior names (without .orb extension).\n */\nexport function getAllBehaviorNames(): string[] {\n return readAllOrbEntries().map(e => e.name);\n}\n\n/**\n * Load all golden .orb files as BehaviorSchema objects.\n * Sets `.name` to the behavior identifier (e.g., \"std-list\") from the filename,\n * overriding the orbital name inside the .orb file.\n */\nexport function getAllBehaviors(): BehaviorSchema[] {\n return readAllOrbEntries().map(e => {\n const schema = JSON.parse(readFileSync(e.path, 'utf-8')) as BehaviorSchema;\n schema.name = e.name;\n return schema;\n });\n}\n\n/**\n * Load all golden .orb files for a specific level (atoms, molecules, organisms).\n */\nexport function getBehaviorsByLevel(level: BehaviorLevel): BehaviorSchema[] {\n return readOrbDir(resolve(EXPORTS_DIR, level)).map(e =>\n JSON.parse(readFileSync(e.path, 'utf-8')) as BehaviorSchema\n );\n}\n\n/**\n * Load a single golden .orb file by behavior name.\n * Searches across all levels. Returns null if not found.\n */\nexport function loadGoldenOrb(behaviorName: string): BehaviorSchema | null {\n for (const level of LEVEL_DIRS) {\n const orbPath = resolve(EXPORTS_DIR, level, `${behaviorName}.orb`);\n if (existsSync(orbPath)) {\n try {\n return JSON.parse(readFileSync(orbPath, 'utf-8')) as BehaviorSchema;\n } catch {\n return null;\n }\n }\n }\n return null;\n}\n\n/**\n * Check if a golden .orb file exists for the given behavior name.\n */\nexport function hasGoldenOrb(behaviorName: string): boolean {\n return LEVEL_DIRS.some(level =>\n existsSync(resolve(EXPORTS_DIR, level, `${behaviorName}.orb`))\n );\n}\n\n/**\n * Get a single behavior by name.\n * Alias for loadGoldenOrb for compatibility.\n */\nexport function getBehavior(behaviorName: string): BehaviorSchema | null {\n return loadGoldenOrb(behaviorName);\n}\n","/**\n * Behavior Registry Query Helpers\n *\n * Programmatic access to behaviors-registry.json for filtering,\n * searching, and summarizing behaviors. Used by @almadar/skills\n * to compose agent prompts dynamically.\n *\n * @packageDocumentation\n */\n\nimport { readFileSync } from 'fs';\nimport { resolve, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport { loadGoldenOrb } from './exports-reader.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst REGISTRY_PATH = resolve(__dirname, 'behaviors-registry.json');\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface RegistryEntry {\n name: string;\n level: 'atom' | 'molecule' | 'organism';\n family: string;\n layer: string;\n description: string;\n statePattern: string;\n complexity: { states: number; events: number; transitions: number };\n defaultEntity: {\n name: string;\n persistence: string;\n fields: Array<{ name: string; type: string; default?: string }>;\n };\n defaultLabels: {\n title: string;\n entitySingular: string;\n entityPlural: string;\n };\n composableWith: string[];\n connectableEvents: string[];\n eventPayloads: Record<string, Array<{ name: string; type: string; required: boolean }>>;\n}\n\nexport interface BehaviorSummary {\n name: string;\n level: string;\n description: string;\n states: string[];\n events: string[];\n slots: string[];\n patterns: string[];\n complexity: { states: number; events: number; transitions: number };\n composableWith: string[];\n}\n\n// ============================================================================\n// Registry Cache\n// ============================================================================\n\nlet registryCache: Record<string, RegistryEntry> | null = null;\n\n/**\n * Read and cache the behavior registry.\n */\nexport function getBehaviorRegistry(): Record<string, RegistryEntry> {\n if (registryCache) return registryCache;\n try {\n const raw = JSON.parse(readFileSync(REGISTRY_PATH, 'utf-8')) as {\n behaviors: Record<string, RegistryEntry>;\n };\n registryCache = raw.behaviors;\n return registryCache;\n } catch {\n return {};\n }\n}\n\n// ============================================================================\n// Query Functions\n// ============================================================================\n\n/**\n * Filter behaviors by domain. Matches against layer (primary) and family (fallback).\n */\nexport function getBehaviorsByDomain(domain: string): RegistryEntry[] {\n const registry = getBehaviorRegistry();\n const lower = domain.toLowerCase();\n return Object.values(registry).filter((b) => {\n return b.layer.toLowerCase() === lower ||\n b.layer.toLowerCase().includes(lower) ||\n b.family.toLowerCase() === lower ||\n b.family.toLowerCase().includes(lower);\n });\n}\n\n/**\n * Filter behaviors by connectable operations (events).\n * Returns behaviors sorted by match count (most matching ops first).\n */\nexport function getBehaviorsByOperations(ops: string[]): RegistryEntry[] {\n const registry = getBehaviorRegistry();\n const upperOps = ops.map(o => o.toUpperCase());\n\n const scored = Object.values(registry).map((b) => {\n const matches = upperOps.filter(op =>\n b.connectableEvents.some(e => e.toUpperCase() === op || e.toUpperCase().includes(op))\n );\n return { entry: b, score: matches.length };\n });\n\n return scored\n .filter(s => s.score > 0)\n .sort((a, b) => b.score - a.score)\n .map(s => s.entry);\n}\n\n/**\n * Fuzzy search across name, description, family, layer, and entity name.\n */\nexport function searchBehaviors(query: string): RegistryEntry[] {\n const registry = getBehaviorRegistry();\n const tokens = query.toLowerCase().split(/\\s+/).filter(Boolean);\n\n const scored = Object.values(registry).map((b) => {\n const searchText = [\n b.name,\n b.description,\n b.family,\n b.layer,\n b.defaultEntity.name,\n b.statePattern,\n ].join(' ').toLowerCase();\n\n const score = tokens.filter(t => searchText.includes(t)).length;\n return { entry: b, score };\n });\n\n return scored\n .filter(s => s.score > 0)\n .sort((a, b) => b.score - a.score)\n .map(s => s.entry);\n}\n\n/**\n * Get a compact summary of a behavior including slots and patterns from the .orb file.\n */\nexport function getBehaviorSummary(name: string): BehaviorSummary | null {\n const registry = getBehaviorRegistry();\n const entry = registry[name];\n if (!entry) return null;\n\n // Base data from registry\n const summary: BehaviorSummary = {\n name: entry.name,\n level: entry.level,\n description: entry.description,\n states: entry.statePattern.split(', ').filter(Boolean),\n events: entry.connectableEvents,\n slots: [],\n patterns: [],\n complexity: entry.complexity,\n composableWith: entry.composableWith.slice(0, 10),\n };\n\n // Enrich with slots and patterns from the actual .orb file\n try {\n const orb = loadGoldenOrb(name);\n if (orb) {\n const slots = new Set<string>();\n const patterns = new Set<string>();\n extractSlotsAndPatterns(orb, slots, patterns);\n summary.slots = Array.from(slots);\n summary.patterns = Array.from(patterns);\n }\n } catch {\n // .orb load failed, return registry-only data\n }\n\n return summary;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Walk an object recursively to extract render-ui slots and pattern types.\n */\nfunction extractSlotsAndPatterns(\n obj: unknown,\n slots: Set<string>,\n patterns: Set<string>,\n): void {\n if (Array.isArray(obj)) {\n // Check for render-ui effect: [\"render-ui\", slotName, uiTree]\n if (obj.length >= 3 && obj[0] === 'render-ui' && typeof obj[1] === 'string') {\n slots.add(obj[1]);\n if (obj[2] && typeof obj[2] === 'object') {\n extractPatternTypes(obj[2], patterns);\n }\n }\n for (const item of obj) {\n extractSlotsAndPatterns(item, slots, patterns);\n }\n } else if (obj && typeof obj === 'object') {\n for (const value of Object.values(obj)) {\n extractSlotsAndPatterns(value, slots, patterns);\n }\n }\n}\n\n/**\n * Walk a render-ui tree to collect all pattern type values.\n */\nfunction extractPatternTypes(node: unknown, patterns: Set<string>): void {\n if (!node || typeof node !== 'object') return;\n const obj = node as Record<string, unknown>;\n if (typeof obj.type === 'string') {\n patterns.add(obj.type);\n }\n if (Array.isArray(obj.children)) {\n for (const child of obj.children) {\n extractPatternTypes(child, patterns);\n }\n }\n}\n"]}
|