@zeyos/cli 0.3.0 → 0.4.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/bin/zeyos.mjs +6 -0
- package/commands/okf.mjs +192 -0
- package/package.json +2 -2
package/bin/zeyos.mjs
CHANGED
|
@@ -51,6 +51,7 @@ ${_c.bold('Commands:')}
|
|
|
51
51
|
${_c.cyan('describe')} <resource> Show a resource's fields, types and enums
|
|
52
52
|
${_c.cyan('doctor')} agent Check local CLI readiness for coding agents
|
|
53
53
|
${_c.cyan('skills')} <command> List / show / install ZeyOS agent skills
|
|
54
|
+
${_c.cyan('okf')} <command> List / show / check / export the OKF knowledge bundle
|
|
54
55
|
${_c.cyan('profile')} <command> Manage credential profiles / switch instances
|
|
55
56
|
|
|
56
57
|
${_c.bold('Global options:')}
|
|
@@ -120,6 +121,8 @@ const OPTIONS = {
|
|
|
120
121
|
'target': { type: 'string' },
|
|
121
122
|
'dir': { type: 'string' },
|
|
122
123
|
'no-logo': { type: 'boolean' },
|
|
124
|
+
// okf
|
|
125
|
+
'out': { type: 'string' },
|
|
123
126
|
// profile
|
|
124
127
|
'from-current': { type: 'boolean' },
|
|
125
128
|
};
|
|
@@ -147,6 +150,7 @@ const COMMANDS = {
|
|
|
147
150
|
doctor: '../commands/doctor.mjs',
|
|
148
151
|
skills: '../commands/skills.mjs',
|
|
149
152
|
skill: '../commands/skills.mjs',
|
|
153
|
+
okf: '../commands/okf.mjs',
|
|
150
154
|
profile: '../commands/profile.mjs',
|
|
151
155
|
profiles: '../commands/profile.mjs',
|
|
152
156
|
};
|
|
@@ -158,6 +162,7 @@ const COMMANDS = {
|
|
|
158
162
|
|
|
159
163
|
const ALWAYS_FLAGS = ['help', 'json', 'yaml', 'no-color', 'profile'];
|
|
160
164
|
const SKILLS_FLAGS = ['target', 'dir', 'global', 'local', 'force', 'yes', 'no-logo'];
|
|
165
|
+
const OKF_FLAGS = ['dir', 'out', 'force', 'no-logo'];
|
|
161
166
|
const PROFILE_FLAGS = ['base-url', 'client-id', 'secret', 'local', 'from-current'];
|
|
162
167
|
const DELETE_FLAGS = ['force', 'query'];
|
|
163
168
|
const GET_FLAGS = ['fields', 'extdata', 'tags', 'expand', 'all', 'query'];
|
|
@@ -182,6 +187,7 @@ const COMMAND_FLAGS = {
|
|
|
182
187
|
doctor: [],
|
|
183
188
|
skills: SKILLS_FLAGS,
|
|
184
189
|
skill: SKILLS_FLAGS,
|
|
190
|
+
okf: OKF_FLAGS,
|
|
185
191
|
profile: PROFILE_FLAGS,
|
|
186
192
|
profiles: PROFILE_FLAGS,
|
|
187
193
|
};
|
package/commands/okf.mjs
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* zeyos okf <list|show|check|build|export>
|
|
3
|
+
*
|
|
4
|
+
* Work with the Open Knowledge Format (OKF v0.1) bundle that ships with
|
|
5
|
+
* @zeyos/client (under okf/): a directory of Markdown concept docs describing the
|
|
6
|
+
* ZeyOS data model (entities, schema, foreign keys, enums, indexes, operations)
|
|
7
|
+
* plus curated metrics, playbooks, and query concepts. Consumers — coding agents,
|
|
8
|
+
* viewers, search — read it; this command lists/shows/validates the shipped bundle
|
|
9
|
+
* and can synthesize or export one.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { readFileSync, existsSync, cpSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
13
|
+
import { homedir } from 'node:os';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
import { createRequire } from 'node:module';
|
|
16
|
+
|
|
17
|
+
import { loadOkfBundle, validateOkfFiles, buildOkf, OKF_VERSION } from '@zeyos/client';
|
|
18
|
+
import { outputMode, printJson, printYaml, printTable, colors, success, error, info, warn } from '../lib/output.mjs';
|
|
19
|
+
|
|
20
|
+
const require = createRequire(import.meta.url);
|
|
21
|
+
|
|
22
|
+
export const USAGE = `\
|
|
23
|
+
Usage: zeyos okf <command> [options]
|
|
24
|
+
|
|
25
|
+
Commands:
|
|
26
|
+
list List concepts in the OKF bundle (type, id, title)
|
|
27
|
+
show <concept> Print a concept doc (e.g. "tickets" or "entities/tickets")
|
|
28
|
+
check Validate the bundle for OKF v0.1 conformance
|
|
29
|
+
build [--out <dir>] Synthesize an OKF bundle from the client's schema
|
|
30
|
+
export [--out <dir>] Copy the shipped okf/ bundle into a directory
|
|
31
|
+
|
|
32
|
+
Options:
|
|
33
|
+
--dir <path> Read from an explicit bundle directory (list/show/check)
|
|
34
|
+
--out <path> Write to this directory (build/export; default ./okf)
|
|
35
|
+
--force Overwrite an existing target (export)
|
|
36
|
+
--json Output as JSON
|
|
37
|
+
--yaml Output as YAML
|
|
38
|
+
-h, --help Show this help
|
|
39
|
+
|
|
40
|
+
Examples:
|
|
41
|
+
zeyos okf list
|
|
42
|
+
zeyos okf show tickets
|
|
43
|
+
zeyos okf check
|
|
44
|
+
zeyos okf export --out ./vendor/okf
|
|
45
|
+
zeyos okf build --out ./okf-live`;
|
|
46
|
+
|
|
47
|
+
// Locate the okf/ bundle shipped inside the @zeyos/client package (mirrors the
|
|
48
|
+
// skills command's findAgentsDir).
|
|
49
|
+
function findOkfDir() {
|
|
50
|
+
let entry;
|
|
51
|
+
try {
|
|
52
|
+
entry = require.resolve('@zeyos/client');
|
|
53
|
+
} catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
let dir = path.dirname(entry);
|
|
57
|
+
for (let i = 0; i < 6; i++) {
|
|
58
|
+
const candidate = path.join(dir, 'okf');
|
|
59
|
+
if (existsSync(path.join(candidate, 'index.md'))) return candidate;
|
|
60
|
+
const parent = path.dirname(dir);
|
|
61
|
+
if (parent === dir) break;
|
|
62
|
+
dir = parent;
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function expandHome(p) {
|
|
68
|
+
if (p === '~') return homedir();
|
|
69
|
+
if (p.startsWith('~/') || p.startsWith('~\\')) return path.join(homedir(), p.slice(2));
|
|
70
|
+
return p;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function displayPath(abs) {
|
|
74
|
+
const rel = path.relative(process.cwd(), abs);
|
|
75
|
+
if (rel && !rel.startsWith('..') && !path.isAbsolute(rel)) return rel;
|
|
76
|
+
const home = homedir();
|
|
77
|
+
if (abs === home || abs.startsWith(home + path.sep)) return '~' + abs.slice(home.length);
|
|
78
|
+
return abs;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function resolveInputDir(values) {
|
|
82
|
+
if (values.dir) return path.resolve(expandHome(values.dir));
|
|
83
|
+
const found = findOkfDir();
|
|
84
|
+
if (!found) {
|
|
85
|
+
error('Could not locate the bundled OKF bundle (the @zeyos/client okf/ directory). Pass --dir <path>.');
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
return found;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function conceptsToRows(concepts) {
|
|
92
|
+
return Object.entries(concepts)
|
|
93
|
+
.map(([id, { frontmatter }]) => ({ type: frontmatter.type || '(none)', concept: id, title: frontmatter.title || '' }))
|
|
94
|
+
.sort((a, b) => a.concept.localeCompare(b.concept));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function runList(values) {
|
|
98
|
+
const dir = resolveInputDir(values);
|
|
99
|
+
const { version, concepts } = await loadOkfBundle(dir);
|
|
100
|
+
const rows = conceptsToRows(concepts);
|
|
101
|
+
const mode = outputMode(values);
|
|
102
|
+
if (mode === 'json') return printJson({ version, concepts: rows });
|
|
103
|
+
if (mode === 'yaml') return printYaml({ version, concepts: rows });
|
|
104
|
+
printTable(rows, ['type', 'concept', 'title']);
|
|
105
|
+
info(`OKF v${version || OKF_VERSION} — ${rows.length} concepts in ${displayPath(dir)}. Show one with: zeyos okf show <concept>`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function runShow(values, name) {
|
|
109
|
+
const dir = resolveInputDir(values);
|
|
110
|
+
const candidates = [name, `${name}.md`, `entities/${name}.md`, path.join(dir, name), path.join(dir, `${name}.md`), path.join(dir, 'entities', `${name}.md`)];
|
|
111
|
+
for (const candidate of candidates) {
|
|
112
|
+
const abs = path.isAbsolute(candidate) ? candidate : path.join(dir, candidate);
|
|
113
|
+
if (existsSync(abs)) {
|
|
114
|
+
process.stdout.write(readFileSync(abs, 'utf8'));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
error(`Unknown concept "${name}". Run "zeyos okf list".`);
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function runCheck(values) {
|
|
123
|
+
const dir = resolveInputDir(values);
|
|
124
|
+
const { files } = await loadOkfBundle(dir);
|
|
125
|
+
const result = validateOkfFiles(files);
|
|
126
|
+
const mode = outputMode(values);
|
|
127
|
+
if (mode === 'json') { printJson(result); process.exit(result.valid ? 0 : 1); }
|
|
128
|
+
if (mode === 'yaml') { printYaml(result); process.exit(result.valid ? 0 : 1); }
|
|
129
|
+
if (result.valid) {
|
|
130
|
+
success(`OKF bundle is conformant: ${result.conceptCount} concepts, 0 errors (${displayPath(dir)}).`);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
for (const err of result.errors) error(`${err.path}: ${err.message}`);
|
|
134
|
+
error(`OKF bundle is NOT conformant: ${result.errors.length} error(s).`);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function writeBundle(outDir, files) {
|
|
139
|
+
for (const [rel, content] of Object.entries(files)) {
|
|
140
|
+
const abs = path.join(outDir, rel);
|
|
141
|
+
mkdirSync(path.dirname(abs), { recursive: true });
|
|
142
|
+
writeFileSync(abs, content, 'utf8');
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function runBuild(values) {
|
|
147
|
+
const outDir = path.resolve(expandHome(values.out || 'okf'));
|
|
148
|
+
const files = buildOkf();
|
|
149
|
+
writeBundle(outDir, files);
|
|
150
|
+
const mode = outputMode(values);
|
|
151
|
+
const summary = { out: outDir, files: Object.keys(files).length };
|
|
152
|
+
if (mode === 'json') return printJson(summary);
|
|
153
|
+
if (mode === 'yaml') return printYaml(summary);
|
|
154
|
+
success(`Synthesized ${summary.files} OKF files → ${displayPath(outDir)}`);
|
|
155
|
+
info('This is the runtime projection from the client schema (structural only). The shipped okf/ bundle adds curated metrics, playbooks, and notes.');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function runExport(values) {
|
|
159
|
+
const dir = resolveInputDir(values);
|
|
160
|
+
const outDir = path.resolve(expandHome(values.out || 'okf'));
|
|
161
|
+
if (existsSync(outDir) && !values.force) {
|
|
162
|
+
if (path.resolve(dir) === outDir) {
|
|
163
|
+
warn(`Source and target are the same (${displayPath(outDir)}); nothing to do.`);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
error(`Target ${displayPath(outDir)} already exists. Use --force to overwrite.`);
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
cpSync(dir, outDir, { recursive: true });
|
|
170
|
+
const mode = outputMode(values);
|
|
171
|
+
const summary = { from: dir, out: outDir };
|
|
172
|
+
if (mode === 'json') return printJson(summary);
|
|
173
|
+
if (mode === 'yaml') return printYaml(summary);
|
|
174
|
+
success(`Exported OKF bundle → ${displayPath(outDir)}`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export async function run(values, positional = []) {
|
|
178
|
+
const sub = positional[0] || 'list';
|
|
179
|
+
const rest = positional.slice(1);
|
|
180
|
+
switch (sub) {
|
|
181
|
+
case 'list': return runList(values);
|
|
182
|
+
case 'show':
|
|
183
|
+
if (!rest[0]) { error('Usage: zeyos okf show <concept>'); process.exit(1); }
|
|
184
|
+
return runShow(values, rest[0]);
|
|
185
|
+
case 'check': return runCheck(values);
|
|
186
|
+
case 'build': return runBuild(values);
|
|
187
|
+
case 'export': return runExport(values);
|
|
188
|
+
default:
|
|
189
|
+
error(`Unknown okf command "${sub}".\n\n${USAGE}`);
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeyos/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Command-line interface for the ZeyOS API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"node": ">=18.3"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@zeyos/client": "^0.
|
|
42
|
+
"@zeyos/client": "^0.4.0"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"test": "node --test test/offline.mjs"
|