@cleocode/cant 2026.4.5 → 2026.4.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/document.d.ts +103 -0
- package/dist/document.js +117 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +13 -1
- package/dist/native-loader.d.ts +139 -11
- package/dist/native-loader.js +92 -27
- package/napi/cant.linux-x64-gnu.node +0 -0
- package/package.json +19 -7
- package/dist/wasm-loader.d.ts +0 -27
- package/dist/wasm-loader.js +0 -100
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* High-level CANT document API.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Replaces the standalone `cant-cli` Rust binary that was previously
|
|
6
|
+
* spawned by `cleo cant`. All operations now run in-process via the
|
|
7
|
+
* cant-napi binding, avoiding subprocess overhead and shared-binary
|
|
8
|
+
* lookup logic.
|
|
9
|
+
*
|
|
10
|
+
* The functions here return plain TypeScript values (no LAFS envelope)
|
|
11
|
+
* so that callers can wrap them in whatever response shape they need.
|
|
12
|
+
* The CLEO CLI uses `cliOutput` for envelope formatting.
|
|
13
|
+
*/
|
|
14
|
+
import { type NativeDiagnostic, type NativeParseError, type NativePipelineResult } from './native-loader';
|
|
15
|
+
/** The kind of section to enumerate via {@link listSections}. */
|
|
16
|
+
export type SectionKind = 'agent' | 'pipeline' | 'workflow';
|
|
17
|
+
/** Result of {@link parseDocument}. */
|
|
18
|
+
export interface CantDocumentResult {
|
|
19
|
+
/** The file path that was parsed. */
|
|
20
|
+
file: string;
|
|
21
|
+
/** Whether parsing succeeded. */
|
|
22
|
+
success: boolean;
|
|
23
|
+
/** The parsed document AST as a JSON-compatible object (null on failure). */
|
|
24
|
+
document: unknown;
|
|
25
|
+
/** Parse errors (empty when `success` is true). */
|
|
26
|
+
errors: NativeParseError[];
|
|
27
|
+
}
|
|
28
|
+
/** Result of {@link validateDocument}. */
|
|
29
|
+
export interface CantValidationResult {
|
|
30
|
+
/** The file path that was validated. */
|
|
31
|
+
file: string;
|
|
32
|
+
/** Whether validation passed (no errors; warnings allowed). */
|
|
33
|
+
valid: boolean;
|
|
34
|
+
/** Total diagnostic count. */
|
|
35
|
+
total: number;
|
|
36
|
+
/** Number of error-severity diagnostics. */
|
|
37
|
+
errorCount: number;
|
|
38
|
+
/** Number of warning-severity diagnostics. */
|
|
39
|
+
warningCount: number;
|
|
40
|
+
/** All diagnostics emitted by the 42-rule validator. */
|
|
41
|
+
diagnostics: NativeDiagnostic[];
|
|
42
|
+
}
|
|
43
|
+
/** Result of {@link listSections}. */
|
|
44
|
+
export interface CantListResult {
|
|
45
|
+
/** The file path that was inspected. */
|
|
46
|
+
file: string;
|
|
47
|
+
/** The section filter that was applied. */
|
|
48
|
+
filter: SectionKind;
|
|
49
|
+
/** Number of matching sections. */
|
|
50
|
+
count: number;
|
|
51
|
+
/** Names of the matching sections (in source order). */
|
|
52
|
+
names: string[];
|
|
53
|
+
}
|
|
54
|
+
/** Result of {@link executePipeline}. */
|
|
55
|
+
export interface CantPipelineResult {
|
|
56
|
+
/** The file path that was executed. */
|
|
57
|
+
file: string;
|
|
58
|
+
/** The pipeline name that was requested. */
|
|
59
|
+
pipeline: string;
|
|
60
|
+
/** Whether the pipeline ran to completion with all steps succeeding. */
|
|
61
|
+
success: boolean;
|
|
62
|
+
/** Total wall-clock duration in milliseconds. */
|
|
63
|
+
durationMs: number;
|
|
64
|
+
/** Per-step results in execution order. */
|
|
65
|
+
steps: NativePipelineResult['steps'];
|
|
66
|
+
/** Optional error message describing why the pipeline did not run. */
|
|
67
|
+
error?: string | null;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Parse a `.cant` file and return its AST.
|
|
71
|
+
*
|
|
72
|
+
* @param filePath - Absolute path to the `.cant` file.
|
|
73
|
+
* @returns A {@link CantDocumentResult} with either the AST or parse errors.
|
|
74
|
+
*/
|
|
75
|
+
export declare function parseDocument(filePath: string): Promise<CantDocumentResult>;
|
|
76
|
+
/**
|
|
77
|
+
* Validate a `.cant` file using the 42-rule validation engine.
|
|
78
|
+
*
|
|
79
|
+
* @param filePath - Absolute path to the `.cant` file.
|
|
80
|
+
* @returns A {@link CantValidationResult} with all diagnostics.
|
|
81
|
+
*/
|
|
82
|
+
export declare function validateDocument(filePath: string): Promise<CantValidationResult>;
|
|
83
|
+
/**
|
|
84
|
+
* Enumerate the agents, pipelines, or workflows defined in a `.cant` file.
|
|
85
|
+
*
|
|
86
|
+
* @param filePath - Absolute path to the `.cant` file.
|
|
87
|
+
* @param kind - Which section type to enumerate (default: `"agent"`).
|
|
88
|
+
* @returns A {@link CantListResult} with the matching section names.
|
|
89
|
+
*/
|
|
90
|
+
export declare function listSections(filePath: string, kind?: SectionKind): Promise<CantListResult>;
|
|
91
|
+
/**
|
|
92
|
+
* Execute a deterministic pipeline from a `.cant` file via the Rust runtime.
|
|
93
|
+
*
|
|
94
|
+
* @remarks
|
|
95
|
+
* Wraps the napi-rs `cantExecutePipeline` async export. Logical failures
|
|
96
|
+
* (file not found, parse errors, missing pipeline, runtime errors) are
|
|
97
|
+
* surfaced via the `success: false` + `error` fields rather than thrown.
|
|
98
|
+
*
|
|
99
|
+
* @param filePath - Absolute path to the `.cant` file.
|
|
100
|
+
* @param pipelineName - The name of the `pipeline { ... }` block to execute.
|
|
101
|
+
* @returns A {@link CantPipelineResult} describing the pipeline outcome.
|
|
102
|
+
*/
|
|
103
|
+
export declare function executePipeline(filePath: string, pipelineName: string): Promise<CantPipelineResult>;
|
package/dist/document.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* High-level CANT document API.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* Replaces the standalone `cant-cli` Rust binary that was previously
|
|
7
|
+
* spawned by `cleo cant`. All operations now run in-process via the
|
|
8
|
+
* cant-napi binding, avoiding subprocess overhead and shared-binary
|
|
9
|
+
* lookup logic.
|
|
10
|
+
*
|
|
11
|
+
* The functions here return plain TypeScript values (no LAFS envelope)
|
|
12
|
+
* so that callers can wrap them in whatever response shape they need.
|
|
13
|
+
* The CLEO CLI uses `cliOutput` for envelope formatting.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.parseDocument = parseDocument;
|
|
17
|
+
exports.validateDocument = validateDocument;
|
|
18
|
+
exports.listSections = listSections;
|
|
19
|
+
exports.executePipeline = executePipeline;
|
|
20
|
+
const promises_1 = require("node:fs/promises");
|
|
21
|
+
const native_loader_1 = require("./native-loader");
|
|
22
|
+
/**
|
|
23
|
+
* Parse a `.cant` file and return its AST.
|
|
24
|
+
*
|
|
25
|
+
* @param filePath - Absolute path to the `.cant` file.
|
|
26
|
+
* @returns A {@link CantDocumentResult} with either the AST or parse errors.
|
|
27
|
+
*/
|
|
28
|
+
async function parseDocument(filePath) {
|
|
29
|
+
const content = await (0, promises_1.readFile)(filePath, 'utf-8');
|
|
30
|
+
const result = (0, native_loader_1.cantParseDocumentNative)(content);
|
|
31
|
+
return {
|
|
32
|
+
file: filePath,
|
|
33
|
+
success: result.success,
|
|
34
|
+
document: result.document ?? null,
|
|
35
|
+
errors: result.errors,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Validate a `.cant` file using the 42-rule validation engine.
|
|
40
|
+
*
|
|
41
|
+
* @param filePath - Absolute path to the `.cant` file.
|
|
42
|
+
* @returns A {@link CantValidationResult} with all diagnostics.
|
|
43
|
+
*/
|
|
44
|
+
async function validateDocument(filePath) {
|
|
45
|
+
const content = await (0, promises_1.readFile)(filePath, 'utf-8');
|
|
46
|
+
const result = (0, native_loader_1.cantValidateDocumentNative)(content);
|
|
47
|
+
return {
|
|
48
|
+
file: filePath,
|
|
49
|
+
valid: result.valid,
|
|
50
|
+
total: result.total,
|
|
51
|
+
errorCount: result.errorCount,
|
|
52
|
+
warningCount: result.warningCount,
|
|
53
|
+
diagnostics: result.diagnostics,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Enumerate the agents, pipelines, or workflows defined in a `.cant` file.
|
|
58
|
+
*
|
|
59
|
+
* @param filePath - Absolute path to the `.cant` file.
|
|
60
|
+
* @param kind - Which section type to enumerate (default: `"agent"`).
|
|
61
|
+
* @returns A {@link CantListResult} with the matching section names.
|
|
62
|
+
*/
|
|
63
|
+
async function listSections(filePath, kind = 'agent') {
|
|
64
|
+
const content = await (0, promises_1.readFile)(filePath, 'utf-8');
|
|
65
|
+
const parsed = (0, native_loader_1.cantParseDocumentNative)(content);
|
|
66
|
+
if (!parsed.success || parsed.document == null) {
|
|
67
|
+
return { file: filePath, filter: kind, count: 0, names: [] };
|
|
68
|
+
}
|
|
69
|
+
const doc = parsed.document;
|
|
70
|
+
const sections = Array.isArray(doc.sections) ? doc.sections : [];
|
|
71
|
+
const names = [];
|
|
72
|
+
for (const section of sections) {
|
|
73
|
+
if (typeof section !== 'object' || section === null)
|
|
74
|
+
continue;
|
|
75
|
+
const wrapper = section;
|
|
76
|
+
const inner = wrapper[capitalize(kind)];
|
|
77
|
+
if (!inner)
|
|
78
|
+
continue;
|
|
79
|
+
const nameField = inner['name'];
|
|
80
|
+
if (typeof nameField === 'object' && nameField !== null) {
|
|
81
|
+
const value = nameField['value'];
|
|
82
|
+
if (typeof value === 'string')
|
|
83
|
+
names.push(value);
|
|
84
|
+
}
|
|
85
|
+
else if (typeof nameField === 'string') {
|
|
86
|
+
names.push(nameField);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return { file: filePath, filter: kind, count: names.length, names };
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Execute a deterministic pipeline from a `.cant` file via the Rust runtime.
|
|
93
|
+
*
|
|
94
|
+
* @remarks
|
|
95
|
+
* Wraps the napi-rs `cantExecutePipeline` async export. Logical failures
|
|
96
|
+
* (file not found, parse errors, missing pipeline, runtime errors) are
|
|
97
|
+
* surfaced via the `success: false` + `error` fields rather than thrown.
|
|
98
|
+
*
|
|
99
|
+
* @param filePath - Absolute path to the `.cant` file.
|
|
100
|
+
* @param pipelineName - The name of the `pipeline { ... }` block to execute.
|
|
101
|
+
* @returns A {@link CantPipelineResult} describing the pipeline outcome.
|
|
102
|
+
*/
|
|
103
|
+
async function executePipeline(filePath, pipelineName) {
|
|
104
|
+
const result = await (0, native_loader_1.cantExecutePipelineNative)(filePath, pipelineName);
|
|
105
|
+
return {
|
|
106
|
+
file: filePath,
|
|
107
|
+
pipeline: pipelineName,
|
|
108
|
+
success: result.success,
|
|
109
|
+
durationMs: result.durationMs,
|
|
110
|
+
steps: result.steps,
|
|
111
|
+
error: result.error ?? null,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/** Capitalize the first character of a string (used for AST section keys). */
|
|
115
|
+
function capitalize(s) {
|
|
116
|
+
return s.length === 0 ? s : s[0].toUpperCase() + s.slice(1);
|
|
117
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
export type { LAFSEnvelope, LAFSError, LAFSMeta, MVILevel
|
|
1
|
+
export type { LAFSEnvelope, LAFSError, LAFSMeta, MVILevel } from '@cleocode/lafs';
|
|
2
|
+
export type { CantDocumentResult, CantListResult, CantPipelineResult, CantValidationResult, SectionKind, } from './document';
|
|
3
|
+
export { executePipeline, listSections, parseDocument, validateDocument, } from './document';
|
|
2
4
|
export type { ConvertedFile, MigrationOptions, MigrationResult, UnconvertedSection, } from './migrate/index';
|
|
3
5
|
export { migrateMarkdown, serializeCantDocument, showDiff, showSummary } from './migrate/index';
|
|
4
|
-
export {
|
|
6
|
+
export type { NativeDiagnostic, NativeParseDocumentResult, NativeParseError, NativeParseResult, NativePipelineResult, NativePipelineStep, NativeValidateResult, } from './native-loader';
|
|
7
|
+
export { cantClassifyDirectiveNative, cantExecutePipelineNative, cantExtractAgentProfilesNative, cantParseDocumentNative, cantParseNative, cantValidateDocumentNative, initWasm, isNativeAvailable, isWasmAvailable, } from './native-loader';
|
|
5
8
|
export type { ParsedCANTMessage } from './parse';
|
|
6
9
|
export { initCantParser, parseCANTMessage } from './parse';
|
|
7
10
|
export type { DirectiveType } from './types';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseCANTMessage = exports.initCantParser = exports.isWasmAvailable = exports.isNativeAvailable = exports.initWasm = exports.showSummary = exports.showDiff = exports.serializeCantDocument = exports.migrateMarkdown = void 0;
|
|
3
|
+
exports.parseCANTMessage = exports.initCantParser = exports.isWasmAvailable = exports.isNativeAvailable = exports.initWasm = exports.cantValidateDocumentNative = exports.cantParseNative = exports.cantParseDocumentNative = exports.cantExtractAgentProfilesNative = exports.cantExecutePipelineNative = exports.cantClassifyDirectiveNative = exports.showSummary = exports.showDiff = exports.serializeCantDocument = exports.migrateMarkdown = exports.validateDocument = exports.parseDocument = exports.listSections = exports.executePipeline = void 0;
|
|
4
|
+
// High-level API (replaces standalone cant-cli binary)
|
|
5
|
+
var document_1 = require("./document");
|
|
6
|
+
Object.defineProperty(exports, "executePipeline", { enumerable: true, get: function () { return document_1.executePipeline; } });
|
|
7
|
+
Object.defineProperty(exports, "listSections", { enumerable: true, get: function () { return document_1.listSections; } });
|
|
8
|
+
Object.defineProperty(exports, "parseDocument", { enumerable: true, get: function () { return document_1.parseDocument; } });
|
|
9
|
+
Object.defineProperty(exports, "validateDocument", { enumerable: true, get: function () { return document_1.validateDocument; } });
|
|
4
10
|
// Migration engine
|
|
5
11
|
var index_1 = require("./migrate/index");
|
|
6
12
|
Object.defineProperty(exports, "migrateMarkdown", { enumerable: true, get: function () { return index_1.migrateMarkdown; } });
|
|
@@ -9,6 +15,12 @@ Object.defineProperty(exports, "showDiff", { enumerable: true, get: function ()
|
|
|
9
15
|
Object.defineProperty(exports, "showSummary", { enumerable: true, get: function () { return index_1.showSummary; } });
|
|
10
16
|
// Native loader (replaces wasm-loader)
|
|
11
17
|
var native_loader_1 = require("./native-loader");
|
|
18
|
+
Object.defineProperty(exports, "cantClassifyDirectiveNative", { enumerable: true, get: function () { return native_loader_1.cantClassifyDirectiveNative; } });
|
|
19
|
+
Object.defineProperty(exports, "cantExecutePipelineNative", { enumerable: true, get: function () { return native_loader_1.cantExecutePipelineNative; } });
|
|
20
|
+
Object.defineProperty(exports, "cantExtractAgentProfilesNative", { enumerable: true, get: function () { return native_loader_1.cantExtractAgentProfilesNative; } });
|
|
21
|
+
Object.defineProperty(exports, "cantParseDocumentNative", { enumerable: true, get: function () { return native_loader_1.cantParseDocumentNative; } });
|
|
22
|
+
Object.defineProperty(exports, "cantParseNative", { enumerable: true, get: function () { return native_loader_1.cantParseNative; } });
|
|
23
|
+
Object.defineProperty(exports, "cantValidateDocumentNative", { enumerable: true, get: function () { return native_loader_1.cantValidateDocumentNative; } });
|
|
12
24
|
Object.defineProperty(exports, "initWasm", { enumerable: true, get: function () { return native_loader_1.initWasm; } });
|
|
13
25
|
Object.defineProperty(exports, "isNativeAvailable", { enumerable: true, get: function () { return native_loader_1.isNativeAvailable; } });
|
|
14
26
|
Object.defineProperty(exports, "isWasmAvailable", { enumerable: true, get: function () { return native_loader_1.isWasmAvailable; } });
|
package/dist/native-loader.d.ts
CHANGED
|
@@ -1,32 +1,160 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Native addon loader for cant-core via napi-rs
|
|
2
|
+
* Native addon loader for cant-core via napi-rs.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Loads the napi-rs native addon synchronously on first use. Tries the
|
|
6
|
+
* package-local binary first (`packages/cant/napi/cant.linux-x64-gnu.node`),
|
|
7
|
+
* then falls back to the workspace `cant-napi` crate's `index.cjs` for
|
|
8
|
+
* dev-mode builds where the package binary may not be present yet.
|
|
6
9
|
*
|
|
7
|
-
* Replaces the previous
|
|
10
|
+
* Replaces the previous WASM loader. Follows the same pattern as
|
|
11
|
+
* `packages/lafs/src/native-loader.ts`.
|
|
8
12
|
*/
|
|
9
|
-
/**
|
|
10
|
-
* Check if the native addon is available
|
|
11
|
-
*/
|
|
12
|
-
export declare function isNativeAvailable(): boolean;
|
|
13
|
-
/** Shape returned by the native Rust WASM cantParse function. */
|
|
13
|
+
/** Shape of a parsed CANT message returned by the native binding. */
|
|
14
14
|
export interface NativeParseResult {
|
|
15
|
+
/** The directive verb if present (e.g., `"done"`), or `undefined`. */
|
|
15
16
|
directive?: string;
|
|
17
|
+
/** The classification of the directive as a lowercase string. */
|
|
16
18
|
directiveType?: string;
|
|
19
|
+
/** All `@`-addresses found in the message, without the `@` prefix. */
|
|
17
20
|
addresses?: string[];
|
|
21
|
+
/** All task references found in the message, including the `T` prefix. */
|
|
18
22
|
taskRefs?: string[];
|
|
23
|
+
/** All `#`-tags found in the message, without the `#` prefix. */
|
|
19
24
|
tags?: string[];
|
|
25
|
+
/** The raw text of the first line (the header). */
|
|
20
26
|
headerRaw?: string;
|
|
27
|
+
/** Everything after the first newline (the body). */
|
|
21
28
|
body?: string;
|
|
22
29
|
}
|
|
30
|
+
/** A parse error from document parsing, exposed by the native binding. */
|
|
31
|
+
export interface NativeParseError {
|
|
32
|
+
/** Human-readable error message. */
|
|
33
|
+
message: string;
|
|
34
|
+
/** Line number (1-based) where the error occurred. */
|
|
35
|
+
line: number;
|
|
36
|
+
/** Column number (1-based) where the error occurred. */
|
|
37
|
+
col: number;
|
|
38
|
+
/** Byte offset of the error start. */
|
|
39
|
+
start: number;
|
|
40
|
+
/** Byte offset of the error end. */
|
|
41
|
+
end: number;
|
|
42
|
+
/** Severity: "error" or "warning". */
|
|
43
|
+
severity: string;
|
|
44
|
+
}
|
|
45
|
+
/** Result of parsing a `.cant` document via the native binding. */
|
|
46
|
+
export interface NativeParseDocumentResult {
|
|
47
|
+
/** Whether parsing succeeded. */
|
|
48
|
+
success: boolean;
|
|
49
|
+
/** Parsed AST as a JSON-compatible object (null if parsing failed). */
|
|
50
|
+
document: unknown;
|
|
51
|
+
/** Parse errors (empty if parsing succeeded). */
|
|
52
|
+
errors: NativeParseError[];
|
|
53
|
+
}
|
|
54
|
+
/** A validation diagnostic from the 42-rule validation engine. */
|
|
55
|
+
export interface NativeDiagnostic {
|
|
56
|
+
/** The rule ID (e.g., "S01", "P06", "W08"). */
|
|
57
|
+
ruleId: string;
|
|
58
|
+
/** Human-readable diagnostic message. */
|
|
59
|
+
message: string;
|
|
60
|
+
/** Severity: "error", "warning", "info", or "hint". */
|
|
61
|
+
severity: string;
|
|
62
|
+
/** Line number (1-based). */
|
|
63
|
+
line: number;
|
|
64
|
+
/** Column number (1-based). */
|
|
65
|
+
col: number;
|
|
66
|
+
}
|
|
67
|
+
/** Result of validating a `.cant` document via the native binding. */
|
|
68
|
+
export interface NativeValidateResult {
|
|
69
|
+
/** Whether validation passed (no errors; warnings allowed). */
|
|
70
|
+
valid: boolean;
|
|
71
|
+
/** Total number of diagnostics. */
|
|
72
|
+
total: number;
|
|
73
|
+
/** Number of errors. */
|
|
74
|
+
errorCount: number;
|
|
75
|
+
/** Number of warnings. */
|
|
76
|
+
warningCount: number;
|
|
77
|
+
/** All diagnostics from the validation engine. */
|
|
78
|
+
diagnostics: NativeDiagnostic[];
|
|
79
|
+
}
|
|
80
|
+
/** A single step result from a pipeline run via the native binding. */
|
|
81
|
+
export interface NativePipelineStep {
|
|
82
|
+
/** The step name from the pipeline definition. */
|
|
83
|
+
name: string;
|
|
84
|
+
/** Subprocess exit code (0 = success). */
|
|
85
|
+
exitCode: number;
|
|
86
|
+
/** Length in bytes of captured stdout. */
|
|
87
|
+
stdoutLen: number;
|
|
88
|
+
/** Length in bytes of captured stderr. */
|
|
89
|
+
stderrLen: number;
|
|
90
|
+
/** Wall-clock duration of the step in milliseconds. */
|
|
91
|
+
durationMs: number;
|
|
92
|
+
/** Whether the step was skipped due to a condition. */
|
|
93
|
+
skipped: boolean;
|
|
94
|
+
}
|
|
95
|
+
/** The aggregate result of a pipeline run via the native binding. */
|
|
96
|
+
export interface NativePipelineResult {
|
|
97
|
+
/** The pipeline name. */
|
|
98
|
+
name: string;
|
|
99
|
+
/** Whether all steps completed with exit code 0. */
|
|
100
|
+
success: boolean;
|
|
101
|
+
/** Total wall-clock duration in milliseconds. */
|
|
102
|
+
durationMs: number;
|
|
103
|
+
/** Per-step results in execution order. */
|
|
104
|
+
steps: NativePipelineStep[];
|
|
105
|
+
/** Optional error message describing why the pipeline did not run. */
|
|
106
|
+
error?: string | null;
|
|
107
|
+
}
|
|
23
108
|
/**
|
|
24
|
-
*
|
|
109
|
+
* Check if the native addon is available.
|
|
110
|
+
*
|
|
111
|
+
* @returns `true` if the native Rust binding loaded successfully.
|
|
112
|
+
*/
|
|
113
|
+
export declare function isNativeAvailable(): boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Parse a CANT message using the native addon.
|
|
116
|
+
*
|
|
117
|
+
* @param content - The CANT message content to parse.
|
|
25
118
|
*/
|
|
26
119
|
export declare function cantParseNative(content: string): NativeParseResult;
|
|
27
120
|
/**
|
|
28
|
-
* Classify a directive using the native addon
|
|
121
|
+
* Classify a directive verb using the native addon.
|
|
122
|
+
*
|
|
123
|
+
* @param verb - The directive verb to classify.
|
|
29
124
|
*/
|
|
30
125
|
export declare function cantClassifyDirectiveNative(verb: string): string;
|
|
126
|
+
/**
|
|
127
|
+
* Parse a `.cant` document via the native addon (Layer 2/3).
|
|
128
|
+
*
|
|
129
|
+
* @param content - The raw `.cant` file content to parse.
|
|
130
|
+
*/
|
|
131
|
+
export declare function cantParseDocumentNative(content: string): NativeParseDocumentResult;
|
|
132
|
+
/**
|
|
133
|
+
* Parse and validate a `.cant` document via the native addon (42 rules).
|
|
134
|
+
*
|
|
135
|
+
* @param content - The raw `.cant` file content to parse and validate.
|
|
136
|
+
*/
|
|
137
|
+
export declare function cantValidateDocumentNative(content: string): NativeValidateResult;
|
|
138
|
+
/**
|
|
139
|
+
* Extract agent profiles from a `.cant` document via the native addon.
|
|
140
|
+
*
|
|
141
|
+
* @param content - The raw `.cant` file content.
|
|
142
|
+
*/
|
|
143
|
+
export declare function cantExtractAgentProfilesNative(content: string): unknown[];
|
|
144
|
+
/**
|
|
145
|
+
* Execute a deterministic pipeline from a `.cant` file via the native addon.
|
|
146
|
+
*
|
|
147
|
+
* @param filePath - Absolute or relative path to a `.cant` file.
|
|
148
|
+
* @param pipelineName - The name of the `pipeline { ... }` block to run.
|
|
149
|
+
*/
|
|
150
|
+
export declare function cantExecutePipelineNative(filePath: string, pipelineName: string): Promise<NativePipelineResult>;
|
|
31
151
|
export declare const isWasmAvailable: typeof isNativeAvailable;
|
|
152
|
+
/**
|
|
153
|
+
* Backward-compatible no-op initializer.
|
|
154
|
+
*
|
|
155
|
+
* @remarks
|
|
156
|
+
* The previous WASM loader required an async `init()` call. With napi-rs
|
|
157
|
+
* the binding loads synchronously, so this exists only to keep older
|
|
158
|
+
* callers (e.g. test fixtures) compiling without changes.
|
|
159
|
+
*/
|
|
32
160
|
export declare const initWasm: () => Promise<void>;
|
package/dist/native-loader.js
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Native addon loader for cant-core via napi-rs
|
|
3
|
+
* Native addon loader for cant-core via napi-rs.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* Loads the napi-rs native addon synchronously on first use. Tries the
|
|
7
|
+
* package-local binary first (`packages/cant/napi/cant.linux-x64-gnu.node`),
|
|
8
|
+
* then falls back to the workspace `cant-napi` crate's `index.cjs` for
|
|
9
|
+
* dev-mode builds where the package binary may not be present yet.
|
|
7
10
|
*
|
|
8
|
-
* Replaces the previous
|
|
11
|
+
* Replaces the previous WASM loader. Follows the same pattern as
|
|
12
|
+
* `packages/lafs/src/native-loader.ts`.
|
|
9
13
|
*/
|
|
10
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
15
|
exports.initWasm = exports.isWasmAvailable = void 0;
|
|
12
16
|
exports.isNativeAvailable = isNativeAvailable;
|
|
13
17
|
exports.cantParseNative = cantParseNative;
|
|
14
18
|
exports.cantClassifyDirectiveNative = cantClassifyDirectiveNative;
|
|
19
|
+
exports.cantParseDocumentNative = cantParseDocumentNative;
|
|
20
|
+
exports.cantValidateDocumentNative = cantValidateDocumentNative;
|
|
21
|
+
exports.cantExtractAgentProfilesNative = cantExtractAgentProfilesNative;
|
|
22
|
+
exports.cantExecutePipelineNative = cantExecutePipelineNative;
|
|
23
|
+
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
24
|
+
const node_path_1 = require("node:path");
|
|
15
25
|
let nativeModule = null;
|
|
16
26
|
let loadAttempted = false;
|
|
17
27
|
/**
|
|
@@ -22,51 +32,106 @@ function ensureLoaded() {
|
|
|
22
32
|
if (loadAttempted)
|
|
23
33
|
return;
|
|
24
34
|
loadAttempted = true;
|
|
35
|
+
// The compiled file lives at packages/cant/dist/native-loader.js, so
|
|
36
|
+
// ../napi resolves to packages/cant/napi/cant.linux-x64-gnu.node.
|
|
37
|
+
const packageBinary = (0, node_path_1.join)(__dirname, '..', 'napi', 'cant.linux-x64-gnu.node');
|
|
25
38
|
try {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
39
|
+
nativeModule = require(packageBinary);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Fall through to workspace dev fallback.
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
// Development fallback: load via the cant-napi crate's index.cjs.
|
|
47
|
+
// From packages/cant/dist/ -> ../../../crates/cant-napi/index.cjs.
|
|
48
|
+
nativeModule = require('../../../crates/cant-napi/index.cjs');
|
|
29
49
|
}
|
|
30
50
|
catch {
|
|
31
|
-
|
|
32
|
-
// Development fallback: try loading from the crate build output
|
|
33
|
-
nativeModule = require('../../crates/cant-napi');
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
// Native addon not available — JS fallback will be used
|
|
37
|
-
nativeModule = null;
|
|
38
|
-
}
|
|
51
|
+
nativeModule = null;
|
|
39
52
|
}
|
|
40
53
|
}
|
|
41
54
|
/**
|
|
42
|
-
* Check if the native addon is available
|
|
55
|
+
* Check if the native addon is available.
|
|
56
|
+
*
|
|
57
|
+
* @returns `true` if the native Rust binding loaded successfully.
|
|
43
58
|
*/
|
|
44
59
|
function isNativeAvailable() {
|
|
45
60
|
ensureLoaded();
|
|
46
61
|
return nativeModule !== null;
|
|
47
62
|
}
|
|
48
63
|
/**
|
|
49
|
-
*
|
|
64
|
+
* Get the native module, throwing if it failed to load.
|
|
65
|
+
*
|
|
66
|
+
* @internal
|
|
67
|
+
* @throws Error when the native addon could not be loaded.
|
|
50
68
|
*/
|
|
51
|
-
function
|
|
69
|
+
function requireNative() {
|
|
52
70
|
ensureLoaded();
|
|
53
71
|
if (!nativeModule) {
|
|
54
|
-
throw new Error('
|
|
72
|
+
throw new Error('cant-napi native addon not available. Build it with: cargo build --release -p cant-napi');
|
|
55
73
|
}
|
|
56
|
-
return nativeModule
|
|
74
|
+
return nativeModule;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Parse a CANT message using the native addon.
|
|
78
|
+
*
|
|
79
|
+
* @param content - The CANT message content to parse.
|
|
80
|
+
*/
|
|
81
|
+
function cantParseNative(content) {
|
|
82
|
+
return requireNative().cantParse(content);
|
|
57
83
|
}
|
|
58
84
|
/**
|
|
59
|
-
* Classify a directive using the native addon
|
|
85
|
+
* Classify a directive verb using the native addon.
|
|
86
|
+
*
|
|
87
|
+
* @param verb - The directive verb to classify.
|
|
60
88
|
*/
|
|
61
89
|
function cantClassifyDirectiveNative(verb) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
90
|
+
return requireNative().cantClassifyDirective(verb);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Parse a `.cant` document via the native addon (Layer 2/3).
|
|
94
|
+
*
|
|
95
|
+
* @param content - The raw `.cant` file content to parse.
|
|
96
|
+
*/
|
|
97
|
+
function cantParseDocumentNative(content) {
|
|
98
|
+
return requireNative().cantParseDocument(content);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Parse and validate a `.cant` document via the native addon (42 rules).
|
|
102
|
+
*
|
|
103
|
+
* @param content - The raw `.cant` file content to parse and validate.
|
|
104
|
+
*/
|
|
105
|
+
function cantValidateDocumentNative(content) {
|
|
106
|
+
return requireNative().cantValidateDocument(content);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Extract agent profiles from a `.cant` document via the native addon.
|
|
110
|
+
*
|
|
111
|
+
* @param content - The raw `.cant` file content.
|
|
112
|
+
*/
|
|
113
|
+
function cantExtractAgentProfilesNative(content) {
|
|
114
|
+
return requireNative().cantExtractAgentProfiles(content);
|
|
67
115
|
}
|
|
68
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Execute a deterministic pipeline from a `.cant` file via the native addon.
|
|
118
|
+
*
|
|
119
|
+
* @param filePath - Absolute or relative path to a `.cant` file.
|
|
120
|
+
* @param pipelineName - The name of the `pipeline { ... }` block to run.
|
|
121
|
+
*/
|
|
122
|
+
function cantExecutePipelineNative(filePath, pipelineName) {
|
|
123
|
+
return requireNative().cantExecutePipeline(filePath, pipelineName);
|
|
124
|
+
}
|
|
125
|
+
// Backward compatibility aliases (kept so existing callers compile).
|
|
69
126
|
exports.isWasmAvailable = isNativeAvailable;
|
|
127
|
+
/**
|
|
128
|
+
* Backward-compatible no-op initializer.
|
|
129
|
+
*
|
|
130
|
+
* @remarks
|
|
131
|
+
* The previous WASM loader required an async `init()` call. With napi-rs
|
|
132
|
+
* the binding loads synchronously, so this exists only to keep older
|
|
133
|
+
* callers (e.g. test fixtures) compiling without changes.
|
|
134
|
+
*/
|
|
70
135
|
const initWasm = async () => {
|
|
71
136
|
ensureLoaded();
|
|
72
137
|
};
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,27 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cleocode/cant",
|
|
3
|
-
"version": "2026.4.
|
|
4
|
-
"description": "CANT protocol parser and
|
|
3
|
+
"version": "2026.4.6",
|
|
4
|
+
"description": "CANT protocol parser and runtime for CLEO — wraps cant-core via napi-rs",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist/",
|
|
9
|
-
"
|
|
9
|
+
"napi/"
|
|
10
10
|
],
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@cleocode/contracts": "2026.4.
|
|
13
|
-
"@cleocode/lafs": "2026.4.
|
|
12
|
+
"@cleocode/contracts": "2026.4.6",
|
|
13
|
+
"@cleocode/lafs": "2026.4.6"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"typescript": "^5.0.0",
|
|
17
17
|
"vitest": "^1.0.0"
|
|
18
18
|
},
|
|
19
|
+
"napi": {
|
|
20
|
+
"name": "cant",
|
|
21
|
+
"package": {
|
|
22
|
+
"name": "@cleocode/cant"
|
|
23
|
+
},
|
|
24
|
+
"triples": {
|
|
25
|
+
"defaults": false,
|
|
26
|
+
"additional": [
|
|
27
|
+
"x86_64-unknown-linux-gnu"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
},
|
|
19
31
|
"keywords": [
|
|
20
32
|
"cleo",
|
|
21
33
|
"cant",
|
|
22
34
|
"agent",
|
|
23
35
|
"parser",
|
|
24
|
-
"
|
|
36
|
+
"napi-rs"
|
|
25
37
|
],
|
|
26
38
|
"license": "MIT",
|
|
27
39
|
"repository": {
|
|
@@ -34,7 +46,7 @@
|
|
|
34
46
|
},
|
|
35
47
|
"scripts": {
|
|
36
48
|
"build": "tsc",
|
|
37
|
-
"build:
|
|
49
|
+
"build:napi": "cargo build --release -p cant-napi && mkdir -p napi && cp ../../target/release/libcant_napi.so napi/cant.linux-x64-gnu.node",
|
|
38
50
|
"test": "vitest run",
|
|
39
51
|
"test:watch": "vitest"
|
|
40
52
|
}
|
package/dist/wasm-loader.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WASM loader for cant-core
|
|
3
|
-
*
|
|
4
|
-
* Loads the WASM module and provides access to CANT parsing functions
|
|
5
|
-
*/
|
|
6
|
-
/** Shape of the CANT WASM module exports. */
|
|
7
|
-
type CantWasmModule = typeof import('../wasm/cant_core');
|
|
8
|
-
declare let wasmModule: CantWasmModule | null;
|
|
9
|
-
/**
|
|
10
|
-
* Initialize the WASM module
|
|
11
|
-
* Must be called before using any WASM functions
|
|
12
|
-
*/
|
|
13
|
-
export declare function initWasm(): Promise<void>;
|
|
14
|
-
/**
|
|
15
|
-
* Check if WASM is available
|
|
16
|
-
*/
|
|
17
|
-
export declare function isWasmAvailable(): boolean;
|
|
18
|
-
/**
|
|
19
|
-
* Parse a CANT message using WASM
|
|
20
|
-
*/
|
|
21
|
-
export declare function cantParseWASM(content: string): unknown;
|
|
22
|
-
/**
|
|
23
|
-
* Classify a directive using WASM
|
|
24
|
-
*/
|
|
25
|
-
export declare function cantClassifyDirectiveWASM(verb: string): string;
|
|
26
|
-
export type { CantWasmModule };
|
|
27
|
-
export { wasmModule };
|
package/dist/wasm-loader.js
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* WASM loader for cant-core
|
|
4
|
-
*
|
|
5
|
-
* Loads the WASM module and provides access to CANT parsing functions
|
|
6
|
-
*/
|
|
7
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
-
if (k2 === undefined) k2 = k;
|
|
9
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
-
}
|
|
13
|
-
Object.defineProperty(o, k2, desc);
|
|
14
|
-
}) : (function(o, m, k, k2) {
|
|
15
|
-
if (k2 === undefined) k2 = k;
|
|
16
|
-
o[k2] = m[k];
|
|
17
|
-
}));
|
|
18
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
-
}) : function(o, v) {
|
|
21
|
-
o["default"] = v;
|
|
22
|
-
});
|
|
23
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
-
var ownKeys = function(o) {
|
|
25
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
-
var ar = [];
|
|
27
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
-
return ar;
|
|
29
|
-
};
|
|
30
|
-
return ownKeys(o);
|
|
31
|
-
};
|
|
32
|
-
return function (mod) {
|
|
33
|
-
if (mod && mod.__esModule) return mod;
|
|
34
|
-
var result = {};
|
|
35
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
-
__setModuleDefault(result, mod);
|
|
37
|
-
return result;
|
|
38
|
-
};
|
|
39
|
-
})();
|
|
40
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
-
exports.wasmModule = void 0;
|
|
42
|
-
exports.initWasm = initWasm;
|
|
43
|
-
exports.isWasmAvailable = isWasmAvailable;
|
|
44
|
-
exports.cantParseWASM = cantParseWASM;
|
|
45
|
-
exports.cantClassifyDirectiveWASM = cantClassifyDirectiveWASM;
|
|
46
|
-
// Dynamic import of the WASM module
|
|
47
|
-
let wasmModule = null;
|
|
48
|
-
exports.wasmModule = wasmModule;
|
|
49
|
-
let isInitializing = false;
|
|
50
|
-
let initPromise = null;
|
|
51
|
-
/**
|
|
52
|
-
* Initialize the WASM module
|
|
53
|
-
* Must be called before using any WASM functions
|
|
54
|
-
*/
|
|
55
|
-
async function initWasm() {
|
|
56
|
-
if (wasmModule)
|
|
57
|
-
return;
|
|
58
|
-
if (isInitializing) {
|
|
59
|
-
return initPromise;
|
|
60
|
-
}
|
|
61
|
-
isInitializing = true;
|
|
62
|
-
initPromise = (async () => {
|
|
63
|
-
try {
|
|
64
|
-
// Try to load the WASM module
|
|
65
|
-
const wasm = await Promise.resolve().then(() => __importStar(require('../wasm/cant_core.js')));
|
|
66
|
-
await wasm.default();
|
|
67
|
-
exports.wasmModule = wasmModule = wasm;
|
|
68
|
-
}
|
|
69
|
-
catch (_error) {
|
|
70
|
-
console.warn('WASM module not available, falling back to stub implementation');
|
|
71
|
-
exports.wasmModule = wasmModule = null;
|
|
72
|
-
}
|
|
73
|
-
})();
|
|
74
|
-
await initPromise;
|
|
75
|
-
isInitializing = false;
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Check if WASM is available
|
|
79
|
-
*/
|
|
80
|
-
function isWasmAvailable() {
|
|
81
|
-
return wasmModule !== null;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Parse a CANT message using WASM
|
|
85
|
-
*/
|
|
86
|
-
function cantParseWASM(content) {
|
|
87
|
-
if (!wasmModule) {
|
|
88
|
-
throw new Error('WASM not initialized. Call initWasm() first.');
|
|
89
|
-
}
|
|
90
|
-
return wasmModule.cant_parse(content);
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Classify a directive using WASM
|
|
94
|
-
*/
|
|
95
|
-
function cantClassifyDirectiveWASM(verb) {
|
|
96
|
-
if (!wasmModule) {
|
|
97
|
-
throw new Error('WASM not initialized. Call initWasm() first.');
|
|
98
|
-
}
|
|
99
|
-
return wasmModule.cant_classify_directive(verb);
|
|
100
|
-
}
|