@oml/cli 0.12.0 → 0.14.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/README.md +29 -21
- package/out/{auth.d.ts → auth/auth.d.ts} +7 -0
- package/out/{auth.js → auth/auth.js} +42 -3
- package/out/auth/auth.js.map +1 -0
- package/out/{platform-constants.js → auth/constants.js} +1 -1
- package/out/auth/constants.js.map +1 -0
- package/out/{platform.d.ts → auth/platform.d.ts} +5 -7
- package/out/{platform.js → auth/platform.js} +39 -17
- package/out/auth/platform.js.map +1 -0
- package/out/cli.d.ts +6 -0
- package/out/cli.js +214 -59
- package/out/cli.js.map +1 -1
- package/out/commands/export.d.ts +8 -0
- package/out/commands/export.js +27 -0
- package/out/commands/export.js.map +1 -0
- package/out/commands/lint.d.ts +22 -2
- package/out/commands/lint.js +64 -18
- package/out/commands/lint.js.map +1 -1
- package/out/commands/reason.d.ts +2 -9
- package/out/commands/reason.js +52 -48
- package/out/commands/reason.js.map +1 -1
- package/out/commands/render.d.ts +1 -9
- package/out/commands/render.js +15 -726
- package/out/commands/render.js.map +1 -1
- package/out/commands/server/actions.d.ts +22 -0
- package/out/commands/server/actions.js +394 -0
- package/out/commands/server/actions.js.map +1 -0
- package/out/commands/server/require.d.ts +1 -0
- package/out/commands/server/require.js +89 -0
- package/out/commands/server/require.js.map +1 -0
- package/out/commands/server/rest.d.ts +2 -0
- package/out/commands/server/rest.js +117 -0
- package/out/commands/server/rest.js.map +1 -0
- package/out/commands/validate.d.ts +3 -3
- package/out/commands/validate.js +35 -171
- package/out/commands/validate.js.map +1 -1
- package/package.json +5 -7
- package/src/{auth.ts → auth/auth.ts} +54 -3
- package/src/{platform.ts → auth/platform.ts} +41 -17
- package/src/cli.ts +249 -59
- package/src/commands/export.ts +54 -0
- package/src/commands/lint.ts +88 -18
- package/src/commands/reason.ts +69 -56
- package/src/commands/render.ts +23 -995
- package/src/commands/server/actions.ts +480 -0
- package/src/commands/server/require.ts +99 -0
- package/src/commands/server/rest.ts +135 -0
- package/src/commands/validate.ts +46 -207
- package/out/auth.js.map +0 -1
- package/out/backend/backend-types.d.ts +0 -21
- package/out/backend/backend-types.js +0 -3
- package/out/backend/backend-types.js.map +0 -1
- package/out/backend/create-backend.d.ts +0 -2
- package/out/backend/create-backend.js +0 -6
- package/out/backend/create-backend.js.map +0 -1
- package/out/backend/direct-backend.d.ts +0 -20
- package/out/backend/direct-backend.js +0 -150
- package/out/backend/direct-backend.js.map +0 -1
- package/out/backend/reasoned-output.d.ts +0 -38
- package/out/backend/reasoned-output.js +0 -568
- package/out/backend/reasoned-output.js.map +0 -1
- package/out/commands/closure.d.ts +0 -33
- package/out/commands/closure.js +0 -537
- package/out/commands/closure.js.map +0 -1
- package/out/commands/compile.d.ts +0 -11
- package/out/commands/compile.js +0 -63
- package/out/commands/compile.js.map +0 -1
- package/out/platform-constants.js.map +0 -1
- package/out/platform.js.map +0 -1
- package/src/backend/backend-types.ts +0 -27
- package/src/backend/create-backend.ts +0 -8
- package/src/backend/direct-backend.ts +0 -169
- package/src/backend/reasoned-output.ts +0 -697
- package/src/commands/closure.ts +0 -624
- package/src/commands/compile.ts +0 -88
- /package/out/{platform-constants.d.ts → auth/constants.d.ts} +0 -0
- /package/src/{platform-constants.ts → auth/constants.ts} +0 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// Copyright (c) 2026 Modelware. All rights reserved.
|
|
2
|
+
import * as fs from 'node:fs/promises';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import { createHash } from 'node:crypto';
|
|
6
|
+
const DEFAULT_HOST = '127.0.0.1';
|
|
7
|
+
function workspaceHash(workspaceRoot) {
|
|
8
|
+
return createHash('sha256').update(path.resolve(workspaceRoot)).digest('hex');
|
|
9
|
+
}
|
|
10
|
+
function serverLockFileForWorkspace(workspaceRoot) {
|
|
11
|
+
return path.join(os.homedir(), '.oml', 'workspaces', workspaceHash(workspaceRoot), 'server.lock');
|
|
12
|
+
}
|
|
13
|
+
function isProcessAlive(pid) {
|
|
14
|
+
try {
|
|
15
|
+
process.kill(pid, 0);
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function parseServerState(raw) {
|
|
23
|
+
try {
|
|
24
|
+
const parsed = JSON.parse(raw);
|
|
25
|
+
const pid = Number(parsed.pid);
|
|
26
|
+
const port = Number(parsed.port);
|
|
27
|
+
if (!Number.isFinite(pid) || !Number.isFinite(port)) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
const pidInt = Math.trunc(pid);
|
|
31
|
+
const portInt = Math.trunc(port);
|
|
32
|
+
if (pidInt <= 0 || portInt <= 0 || portInt > 65535) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
return { pid: pidInt, port: portInt };
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async function readRunningState(workspaceRoot = process.cwd()) {
|
|
42
|
+
const lockFile = serverLockFileForWorkspace(path.resolve(workspaceRoot));
|
|
43
|
+
try {
|
|
44
|
+
const raw = (await fs.readFile(lockFile, 'utf-8')).trim();
|
|
45
|
+
if (!raw) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
const state = parseServerState(raw);
|
|
49
|
+
if (!state || !isProcessAlive(state.pid)) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
return state;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function createHeaders(token) {
|
|
59
|
+
const headers = new Headers();
|
|
60
|
+
headers.set('content-type', 'application/json');
|
|
61
|
+
if (token && token.trim().length > 0) {
|
|
62
|
+
headers.set('authorization', `Bearer ${token.trim()}`);
|
|
63
|
+
}
|
|
64
|
+
return headers;
|
|
65
|
+
}
|
|
66
|
+
function ensureServerBaseUrl(state) {
|
|
67
|
+
if (!state) {
|
|
68
|
+
throw new Error('start server first');
|
|
69
|
+
}
|
|
70
|
+
return `http://${DEFAULT_HOST}:${state.port}`;
|
|
71
|
+
}
|
|
72
|
+
async function parseJsonResponse(response) {
|
|
73
|
+
const text = await response.text();
|
|
74
|
+
if (!text.trim()) {
|
|
75
|
+
throw new Error(`Server returned HTTP ${response.status} ${response.statusText} with empty response body.`);
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
return JSON.parse(text);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
throw new Error(`Server returned HTTP ${response.status} ${response.statusText} with invalid JSON response.`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
export async function restGet(route, authToken) {
|
|
85
|
+
const baseUrl = ensureServerBaseUrl(await readRunningState());
|
|
86
|
+
const response = await fetch(`${baseUrl}${route}`, {
|
|
87
|
+
method: 'GET',
|
|
88
|
+
headers: createHeaders(authToken),
|
|
89
|
+
});
|
|
90
|
+
const payload = await parseJsonResponse(response);
|
|
91
|
+
if (!response.ok) {
|
|
92
|
+
const message = payload.error;
|
|
93
|
+
throw new Error(message && message.trim().length > 0 ? message : `Server request failed: GET ${route} (${response.status}).`);
|
|
94
|
+
}
|
|
95
|
+
return payload;
|
|
96
|
+
}
|
|
97
|
+
export async function restPost(route, body, authToken) {
|
|
98
|
+
const baseUrl = ensureServerBaseUrl(await readRunningState());
|
|
99
|
+
const response = await fetch(`${baseUrl}${route}`, {
|
|
100
|
+
method: 'POST',
|
|
101
|
+
headers: createHeaders(authToken),
|
|
102
|
+
body: JSON.stringify(body),
|
|
103
|
+
});
|
|
104
|
+
const payload = await parseJsonResponse(response);
|
|
105
|
+
if (!response.ok) {
|
|
106
|
+
const message = payload.error;
|
|
107
|
+
throw new Error(message && message.trim().length > 0 ? message : `Server request failed: POST ${route} (${response.status}).`);
|
|
108
|
+
}
|
|
109
|
+
if (payload.ok === false) {
|
|
110
|
+
throw new Error(payload.error?.trim() || `Server request failed: POST ${route}.`);
|
|
111
|
+
}
|
|
112
|
+
if (payload.result === undefined) {
|
|
113
|
+
throw new Error(`Server request failed: POST ${route} did not return a result.`);
|
|
114
|
+
}
|
|
115
|
+
return payload.result;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=rest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest.js","sourceRoot":"","sources":["../../../src/commands/server/rest.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export type ValidateOptions = {
|
|
2
|
+
only?: boolean;
|
|
3
|
+
authToken?: string;
|
|
4
4
|
};
|
|
5
5
|
export declare const validateAction: (opts: ValidateOptions) => Promise<void>;
|
package/out/commands/validate.js
CHANGED
|
@@ -1,186 +1,50 @@
|
|
|
1
1
|
// Copyright (c) 2026 Modelware. All rights reserved.
|
|
2
|
-
import { normalizeNamespace } from '@oml/language';
|
|
3
|
-
import { createDefaultShaclService, createOwlServices } from '@oml/owl';
|
|
4
|
-
import { MarkdownPreviewRuntime, MarkdownHandlerRegistry } from '@oml/markdown';
|
|
5
2
|
import chalk from 'chalk';
|
|
6
|
-
import { URI } from 'langium';
|
|
7
|
-
import { NodeFileSystem } from 'langium/node';
|
|
8
|
-
import * as fs from 'node:fs/promises';
|
|
9
|
-
import * as path from 'node:path';
|
|
10
|
-
import * as url from 'node:url';
|
|
11
|
-
import { loadPreparedDatasetFromOutput, normalizeFormatExtension } from '../backend/reasoned-output.js';
|
|
12
3
|
import { failCli } from '../cli-error.js';
|
|
13
4
|
import { formatDuration } from '../util.js';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
const markdownRuntime = new MarkdownPreviewRuntime(new MarkdownHandlerRegistry());
|
|
5
|
+
import { restPost } from './server/rest.js';
|
|
6
|
+
import { formatLintSummary, printLintDiagnostics } from './lint.js';
|
|
17
7
|
export const validateAction = async (opts) => {
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (!opts.only) {
|
|
27
|
-
await reasonAction({
|
|
28
|
-
workspace: workspaceRoot,
|
|
29
|
-
owl: owlOutputRoot,
|
|
30
|
-
format: rdfFormat,
|
|
31
|
-
clean: opts.clean,
|
|
32
|
-
pretty: opts.pretty,
|
|
33
|
-
only: false,
|
|
34
|
-
checkOnly: false,
|
|
35
|
-
uniqueNamesAssumption: opts.uniqueNamesAssumption,
|
|
36
|
-
explanations: opts.explanations,
|
|
37
|
-
profile: opts.profile,
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
const servicesBundle = createOwlServices(NodeFileSystem);
|
|
41
|
-
await servicesBundle.Oml.shared.workspace.WorkspaceManager.initializeWorkspace([
|
|
42
|
-
{ uri: URI.file(workspaceRoot).toString(), name: path.basename(workspaceRoot) }
|
|
43
|
-
]);
|
|
44
|
-
const preparedDataset = await loadPreparedDatasetFromOutput(workspaceRoot, owlOutputRoot, rdfFormat);
|
|
45
|
-
servicesBundle.Oml.reasoning.ReasoningService.loadPreparedDataset(preparedDataset);
|
|
46
|
-
const shaclService = createDefaultShaclService(servicesBundle.Oml.reasoning.ReasoningService.getSparqlService(), (modelUri) => servicesBundle.Oml.reasoning.ReasoningService.ensureQueryContext(modelUri), (modelUri) => servicesBundle.Oml.reasoning.ReasoningService.getContextIri(modelUri));
|
|
47
|
-
const validationStartedAt = Date.now();
|
|
48
|
-
const markdownFiles = await discoverMarkdownFiles(markdownRoot);
|
|
49
|
-
const results = [];
|
|
50
|
-
for (const markdownFile of markdownFiles) {
|
|
51
|
-
const markdown = await fs.readFile(markdownFile, 'utf-8');
|
|
52
|
-
const prepared = markdownRuntime.prepare(markdown);
|
|
53
|
-
const contextModelUri = resolveContextModelUri(markdownFile, prepared.contextUri, workspaceRoot);
|
|
54
|
-
for (const block of prepared.codeBlocks) {
|
|
55
|
-
if (block.language !== 'table-editor') {
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
const validation = await shaclService.validateShacl(contextModelUri, block.content);
|
|
59
|
-
results.push({
|
|
60
|
-
markdownFile,
|
|
61
|
-
blockId: block.id,
|
|
62
|
-
lineStart: block.lineStart,
|
|
63
|
-
lineEnd: block.lineEnd,
|
|
64
|
-
contextModelUri,
|
|
65
|
-
conforms: validation.conforms,
|
|
66
|
-
issues: validation.issues,
|
|
67
|
-
error: validation.error,
|
|
68
|
-
});
|
|
8
|
+
const startedAt = Date.now();
|
|
9
|
+
const result = await restPost('/v0/validate', {
|
|
10
|
+
only: opts.only === true,
|
|
11
|
+
}, opts.authToken);
|
|
12
|
+
if (result.lint) {
|
|
13
|
+
const lint = result.lint;
|
|
14
|
+
if (lint.filesChecked <= 0) {
|
|
15
|
+
console.log(chalk.yellow('No .oml files found in server workspace.'));
|
|
69
16
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const markdownFiles = [];
|
|
79
|
-
for (const entry of entries) {
|
|
80
|
-
const fullPath = path.join(root, entry.name);
|
|
81
|
-
if (entry.isDirectory()) {
|
|
82
|
-
if (entry.name === 'node_modules' || entry.name.startsWith('.')) {
|
|
83
|
-
continue;
|
|
17
|
+
else {
|
|
18
|
+
printLintDiagnostics(lint);
|
|
19
|
+
const lintElapsedMs = typeof lint.elapsedMs === 'number' && Number.isFinite(lint.elapsedMs) && lint.elapsedMs >= 0
|
|
20
|
+
? lint.elapsedMs
|
|
21
|
+
: Date.now() - startedAt;
|
|
22
|
+
const lintSummary = formatLintSummary(lint, lintElapsedMs);
|
|
23
|
+
if (lint.errors > 0) {
|
|
24
|
+
failCli(chalk.red(lintSummary));
|
|
84
25
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
markdownFiles.push(fullPath);
|
|
26
|
+
if (lint.warnings > 0) {
|
|
27
|
+
failCli(chalk.yellow(lintSummary));
|
|
28
|
+
}
|
|
29
|
+
console.log(chalk.green(lintSummary));
|
|
90
30
|
}
|
|
91
31
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
function resolveContextModelUri(documentFile, contextUri, workspaceRoot) {
|
|
95
|
-
if (!contextUri) {
|
|
96
|
-
return undefined;
|
|
97
|
-
}
|
|
98
|
-
const trimmed = contextUri.trim();
|
|
99
|
-
if (!trimmed) {
|
|
100
|
-
return undefined;
|
|
101
|
-
}
|
|
102
|
-
if (trimmed.startsWith('workspace:/')) {
|
|
103
|
-
const resolved = resolveWorkspacePath(workspaceRoot, trimmed);
|
|
104
|
-
return resolved ? url.pathToFileURL(resolved).toString() : undefined;
|
|
105
|
-
}
|
|
106
|
-
if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed)) {
|
|
107
|
-
return trimmed;
|
|
108
|
-
}
|
|
109
|
-
if (trimmed.startsWith('/')) {
|
|
110
|
-
return url.pathToFileURL(path.resolve(workspaceRoot, trimmed.replace(/^\/+/, ''))).toString();
|
|
32
|
+
if (!result.success) {
|
|
33
|
+
failCli(chalk.red(result.error?.trim() || 'validate failed.'));
|
|
111
34
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
function resolveWorkspacePath(workspaceRoot, href) {
|
|
115
|
-
const trimmed = href.trim();
|
|
116
|
-
if (!trimmed.startsWith('workspace:/')) {
|
|
117
|
-
return undefined;
|
|
118
|
-
}
|
|
119
|
-
return path.resolve(workspaceRoot, trimmed.slice('workspace:/'.length));
|
|
120
|
-
}
|
|
121
|
-
function reportValidationResults(results, workspaceRoot, markdownRoot, startedAt) {
|
|
122
|
-
if (results.length === 0) {
|
|
123
|
-
console.log(chalk.yellow(`No table-editor blocks found under ${path.relative(workspaceRoot, markdownRoot) || markdownRoot}.`));
|
|
35
|
+
if (result.filesChecked === 0) {
|
|
36
|
+
console.log(chalk.yellow('No markdown/table-editor targets found in server workspace.'));
|
|
124
37
|
return;
|
|
125
38
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const location = relativeFile;
|
|
132
|
-
if (result.error) {
|
|
133
|
-
failingBlockCount += 1;
|
|
134
|
-
errorCount += 1;
|
|
135
|
-
console.log(chalk.red(`Violation: ${location}: ${result.error}`));
|
|
136
|
-
continue;
|
|
137
|
-
}
|
|
138
|
-
const hasIssues = result.issues.length > 0 || !result.conforms;
|
|
139
|
-
if (!hasIssues) {
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
failingBlockCount += 1;
|
|
143
|
-
for (const issue of result.issues) {
|
|
144
|
-
issueCount += 1;
|
|
145
|
-
const elementLabel = issue.focusNode ? shortIri(issue.focusNode) : '-';
|
|
146
|
-
const propertyLabel = issue.propertyName ?? (issue.path ? shortIri(issue.path) : '-');
|
|
147
|
-
const severityLabel = shortIri(issue.severity || 'Violation');
|
|
148
|
-
console.log(chalk.red(`${severityLabel}: ${location} element=${elementLabel} property=${propertyLabel}: ${describeIssue(issue)}`));
|
|
149
|
-
}
|
|
150
|
-
if (!result.conforms && result.issues.length === 0) {
|
|
151
|
-
issueCount += 1;
|
|
152
|
-
console.log(chalk.red(`Violation: ${location}: SHACL validation failed without detailed issues.`));
|
|
153
|
-
}
|
|
39
|
+
const validateElapsedMs = typeof result.elapsedMs === 'number' && Number.isFinite(result.elapsedMs) && result.elapsedMs >= 0
|
|
40
|
+
? result.elapsedMs
|
|
41
|
+
: Date.now() - startedAt;
|
|
42
|
+
if (result.errors > 0) {
|
|
43
|
+
failCli(chalk.red(`validate: ${result.filesChecked} item(s) checked with ${result.errors} error(s) and ${result.warnings} warning(s). [${formatDuration(validateElapsedMs)}]`));
|
|
154
44
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (issueCount === 0 && errorCount === 0) {
|
|
158
|
-
console.log(chalk.green(`validate: ${summary}`));
|
|
159
|
-
return;
|
|
45
|
+
if (result.warnings > 0) {
|
|
46
|
+
failCli(chalk.yellow(`validate: ${result.filesChecked} item(s) checked with ${result.warnings} warning(s). [${formatDuration(validateElapsedMs)}]`));
|
|
160
47
|
}
|
|
161
|
-
console.log(chalk.
|
|
162
|
-
}
|
|
163
|
-
function shortIri(value) {
|
|
164
|
-
const normalized = normalizeNamespace(value);
|
|
165
|
-
const hashIndex = normalized.lastIndexOf('#');
|
|
166
|
-
if (hashIndex >= 0 && hashIndex < normalized.length - 1) {
|
|
167
|
-
return normalized.slice(hashIndex + 1);
|
|
168
|
-
}
|
|
169
|
-
const slashIndex = normalized.lastIndexOf('/');
|
|
170
|
-
if (slashIndex >= 0 && slashIndex < normalized.length - 1) {
|
|
171
|
-
return normalized.slice(slashIndex + 1);
|
|
172
|
-
}
|
|
173
|
-
return normalized;
|
|
174
|
-
}
|
|
175
|
-
function describeIssue(issue) {
|
|
176
|
-
const message = issue.message.trim();
|
|
177
|
-
if (message && message !== 'Validation issue.') {
|
|
178
|
-
return message;
|
|
179
|
-
}
|
|
180
|
-
const source = issue.source ? shortIri(issue.source) : undefined;
|
|
181
|
-
if (source) {
|
|
182
|
-
return source;
|
|
183
|
-
}
|
|
184
|
-
return 'Validation issue.';
|
|
185
|
-
}
|
|
48
|
+
console.log(chalk.green(`validate: ${result.filesChecked} item(s) checked. [${formatDuration(validateElapsedMs)}]`));
|
|
49
|
+
};
|
|
186
50
|
//# sourceMappingURL=validate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA,qDAAqD;AAErD,OAAO,
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oml/cli",
|
|
3
3
|
"description": "The cli specific package",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.14.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=20.10.0",
|
|
@@ -21,14 +21,12 @@
|
|
|
21
21
|
"build:clean": "npm run clean && npm run build"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@oml/
|
|
25
|
-
"@oml/
|
|
26
|
-
"@oml/owl": "0.12.0",
|
|
27
|
-
"@oml/platform": "^0.4.0",
|
|
28
|
-
"@oml/reasoner": "^0.3.0",
|
|
24
|
+
"@oml/platform": "^0.5.0",
|
|
25
|
+
"@oml/server": "0.14.0",
|
|
29
26
|
"chalk": "~5.3.0",
|
|
30
|
-
"chevrotain": "
|
|
27
|
+
"chevrotain": "^12.0.0",
|
|
31
28
|
"commander": "~11.1.0",
|
|
29
|
+
"langium-cli": "^4.2.0",
|
|
32
30
|
"n3": "^2.0.1"
|
|
33
31
|
},
|
|
34
32
|
"volta": {
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
DEFAULT_API_BASE_URL,
|
|
10
10
|
DEFAULT_SUPABASE_ANON_KEY,
|
|
11
11
|
DEFAULT_SUPABASE_URL
|
|
12
|
-
} from './
|
|
12
|
+
} from './constants.js';
|
|
13
13
|
const GITHUB_DEVICE_CODE_URL = 'https://github.com/login/device/code';
|
|
14
14
|
const GITHUB_TOKEN_URL = 'https://github.com/login/oauth/access_token';
|
|
15
15
|
const GITHUB_USER_URL = 'https://api.github.com/user';
|
|
@@ -36,11 +36,17 @@ type StoredSession = {
|
|
|
36
36
|
type LoginOptions = {
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
+
export type OmlCliServerAuthSnapshot = {
|
|
40
|
+
accessToken: string;
|
|
41
|
+
refreshToken?: string;
|
|
42
|
+
expiresAtMs?: number;
|
|
43
|
+
};
|
|
44
|
+
|
|
39
45
|
export class OmlCliAuthService {
|
|
40
46
|
|
|
41
47
|
async login(options: LoginOptions): Promise<void> {
|
|
42
48
|
const session = await this.authenticate();
|
|
43
|
-
await writeSession(session);
|
|
49
|
+
await writeSession(session, true);
|
|
44
50
|
const summary = session.userLabel ?? session.email ?? 'signed-in user';
|
|
45
51
|
console.error(chalk.green(`Signed in as ${summary} via ${session.provider}.`));
|
|
46
52
|
}
|
|
@@ -103,12 +109,49 @@ export class OmlCliAuthService {
|
|
|
103
109
|
tokenType: refreshed.token_type,
|
|
104
110
|
expiresIn: refreshed.expires_in,
|
|
105
111
|
email: refreshed.email ?? session.email,
|
|
112
|
+
signedInAt: new Date().toISOString(),
|
|
106
113
|
};
|
|
107
114
|
|
|
108
115
|
await writeSession(updatedSession);
|
|
109
116
|
return updatedSession.accessToken;
|
|
110
117
|
}
|
|
111
118
|
|
|
119
|
+
async getServerAuthSnapshot(): Promise<OmlCliServerAuthSnapshot> {
|
|
120
|
+
const session = await readSession();
|
|
121
|
+
if (!session?.accessToken) {
|
|
122
|
+
throw new Error('OML CLI authentication is required. Run \'oml login\' first.');
|
|
123
|
+
}
|
|
124
|
+
const signedInAtMs = Date.parse(session.signedInAt);
|
|
125
|
+
const expiresAtMs = Number.isFinite(signedInAtMs)
|
|
126
|
+
? signedInAtMs + (session.expiresIn * 1000)
|
|
127
|
+
: undefined;
|
|
128
|
+
if (expiresAtMs !== undefined && Date.now() + 20_000 >= expiresAtMs) {
|
|
129
|
+
await this.refreshAccessToken();
|
|
130
|
+
return await this.getServerAuthSnapshot();
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
accessToken: session.accessToken,
|
|
134
|
+
refreshToken: session.refreshToken,
|
|
135
|
+
expiresAtMs,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async storeRefreshedTokens(accessToken: string, refreshToken: string, expiresAtMs: number): Promise<void> {
|
|
140
|
+
const session = await readSession();
|
|
141
|
+
if (!session) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const expiresIn = Math.max(0, Math.round((expiresAtMs - Date.now()) / 1000));
|
|
145
|
+
const updatedSession: StoredSession = {
|
|
146
|
+
...session,
|
|
147
|
+
accessToken,
|
|
148
|
+
refreshToken,
|
|
149
|
+
expiresIn,
|
|
150
|
+
signedInAt: new Date().toISOString(),
|
|
151
|
+
};
|
|
152
|
+
await writeSession(updatedSession);
|
|
153
|
+
}
|
|
154
|
+
|
|
112
155
|
private async authenticate(): Promise<StoredSession> {
|
|
113
156
|
return authenticateWithGitHub();
|
|
114
157
|
}
|
|
@@ -147,10 +190,18 @@ async function readSession(): Promise<StoredSession | undefined> {
|
|
|
147
190
|
}
|
|
148
191
|
}
|
|
149
192
|
|
|
150
|
-
async function writeSession(session: StoredSession): Promise<void> {
|
|
193
|
+
async function writeSession(session: StoredSession, warnAboutPlaintext = false): Promise<void> {
|
|
151
194
|
const sessionPath = getSessionPath();
|
|
152
195
|
await fs.mkdir(path.dirname(sessionPath), { recursive: true });
|
|
153
196
|
await fs.writeFile(sessionPath, `${JSON.stringify(session, null, 2)}\n`, 'utf-8');
|
|
197
|
+
if (warnAboutPlaintext) {
|
|
198
|
+
process.stderr.write(
|
|
199
|
+
chalk.yellow(
|
|
200
|
+
`[oml] Warning: credentials stored in plaintext at ${sessionPath}. ` +
|
|
201
|
+
`A system keychain is not available in this environment.\n`
|
|
202
|
+
)
|
|
203
|
+
);
|
|
204
|
+
}
|
|
154
205
|
}
|
|
155
206
|
|
|
156
207
|
async function deleteSession(): Promise<void> {
|
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* OML Platform integration for the CLI.
|
|
5
5
|
*
|
|
6
|
-
* The platform is the sole authorization mechanism. Users must
|
|
7
|
-
*
|
|
8
|
-
* commands to execute.
|
|
6
|
+
* The platform is the sole authorization mechanism. Users must be
|
|
7
|
+
* authenticated via oml login and the platform must be reachable for
|
|
8
|
+
* commands to execute.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { OmlClient, FileStorageAdapter, installNodeShutdownHandlers } from '@oml/platform';
|
|
12
12
|
import type { OmlClientConfig } from '@oml/platform';
|
|
13
13
|
import type { NodeShutdownHandle } from '@oml/platform';
|
|
14
14
|
import chalk from 'chalk';
|
|
15
|
-
import { DEFAULT_API_BASE_URL } from './
|
|
15
|
+
import { DEFAULT_API_BASE_URL } from './constants.js';
|
|
16
16
|
import { OmlCliAuthService } from './auth.js';
|
|
17
17
|
const API_BASE_URL_ENV = 'OML_PLATFORM_API_URL';
|
|
18
18
|
|
|
@@ -23,10 +23,8 @@ export type CommandInvocationTracker = ReturnType<OmlClient['trackInvocation']>;
|
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Initialize the platform client. Call once during CLI startup.
|
|
26
|
-
* Uses
|
|
27
|
-
*
|
|
28
|
-
* Throws if the platform is unreachable or the chosen auth mode
|
|
29
|
-
* is not configured.
|
|
26
|
+
* Uses the stored OAuth session from oml login.
|
|
27
|
+
* Throws if the platform is unreachable or the user is not authenticated.
|
|
30
28
|
*/
|
|
31
29
|
export async function initializePlatform(
|
|
32
30
|
authService: OmlCliAuthService,
|
|
@@ -34,20 +32,17 @@ export async function initializePlatform(
|
|
|
34
32
|
): Promise<void> {
|
|
35
33
|
await disposePlatform();
|
|
36
34
|
|
|
37
|
-
const key = process.env.OML_PLATFORM_API_KEY;
|
|
38
35
|
const resolvedApiBaseUrl = process.env[API_BASE_URL_ENV]?.trim() || apiBaseUrl;
|
|
39
36
|
|
|
40
37
|
const config: OmlClientConfig = {
|
|
41
38
|
apiBaseUrl: resolvedApiBaseUrl,
|
|
42
39
|
tool: 'oml-cli',
|
|
43
40
|
storage: new FileStorageAdapter(),
|
|
44
|
-
auth:
|
|
45
|
-
|
|
46
|
-
:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
refreshToken: () => authService.refreshAccessToken(),
|
|
50
|
-
},
|
|
41
|
+
auth: {
|
|
42
|
+
method: 'oauth',
|
|
43
|
+
getToken: () => authService.getAccessToken(),
|
|
44
|
+
refreshToken: () => authService.refreshAccessToken(),
|
|
45
|
+
},
|
|
51
46
|
onConcurrencyLimit: (info) => {
|
|
52
47
|
console.error(chalk.yellow(
|
|
53
48
|
`OML Platform: concurrent session limit reached `
|
|
@@ -60,7 +55,7 @@ export async function initializePlatform(
|
|
|
60
55
|
`OML Platform: authentication error — ${toGenericPlatformErrorMessage(error)}`
|
|
61
56
|
));
|
|
62
57
|
},
|
|
63
|
-
debug:
|
|
58
|
+
debug: isDebugEnabled(),
|
|
64
59
|
};
|
|
65
60
|
|
|
66
61
|
const platformClient = new OmlClient(config);
|
|
@@ -105,7 +100,36 @@ export function trackCommand(
|
|
|
105
100
|
function toGenericPlatformErrorMessage(error: unknown): string {
|
|
106
101
|
const message = error instanceof Error ? error.message.trim() : String(error).trim();
|
|
107
102
|
if (!message || message === 'fetch failed') {
|
|
103
|
+
if (isDebugEnabled()) {
|
|
104
|
+
const detailed = formatErrorChain(error);
|
|
105
|
+
if (detailed) {
|
|
106
|
+
return detailed;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
108
109
|
return 'Check your network connection or sign in again with \'oml login\'.';
|
|
109
110
|
}
|
|
110
111
|
return message;
|
|
111
112
|
}
|
|
113
|
+
|
|
114
|
+
function isDebugEnabled(): boolean {
|
|
115
|
+
return process.env.OML_PLATFORM_DEBUG === '1';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function formatErrorChain(error: unknown): string {
|
|
119
|
+
if (!(error instanceof Error)) {
|
|
120
|
+
return String(error);
|
|
121
|
+
}
|
|
122
|
+
const parts: string[] = [];
|
|
123
|
+
let current: unknown = error;
|
|
124
|
+
let depth = 0;
|
|
125
|
+
while (current instanceof Error && depth < 8) {
|
|
126
|
+
const code = (current as Error & { code?: unknown }).code;
|
|
127
|
+
parts.push(code ? `${current.name}[${String(code)}]: ${current.message}` : `${current.name}: ${current.message}`);
|
|
128
|
+
current = (current as Error & { cause?: unknown }).cause;
|
|
129
|
+
depth += 1;
|
|
130
|
+
}
|
|
131
|
+
if (current !== undefined && current !== null) {
|
|
132
|
+
parts.push(String(current));
|
|
133
|
+
}
|
|
134
|
+
return parts.join(' | ');
|
|
135
|
+
}
|