deepclause-sdk 0.0.89 → 0.1.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 +417 -948
- package/dist/agent.d.ts +18 -2
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +74 -21
- package/dist/agent.js.map +1 -1
- package/dist/cli/config.d.ts +323 -176
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +146 -188
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/index.d.ts +3 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +61 -425
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/login.d.ts +29 -0
- package/dist/cli/login.d.ts.map +1 -0
- package/dist/cli/login.js +184 -0
- package/dist/cli/login.js.map +1 -0
- package/dist/cli/readline.d.ts +6 -0
- package/dist/cli/readline.d.ts.map +1 -0
- package/dist/cli/readline.js +15 -0
- package/dist/cli/readline.js.map +1 -0
- package/dist/cli/repl-bin.d.ts +9 -0
- package/dist/cli/repl-bin.d.ts.map +1 -0
- package/dist/cli/repl-bin.js +16 -0
- package/dist/cli/repl-bin.js.map +1 -0
- package/dist/cli/repl.d.ts +191 -0
- package/dist/cli/repl.d.ts.map +1 -0
- package/dist/cli/repl.js +1232 -0
- package/dist/cli/repl.js.map +1 -0
- package/dist/cli/run.d.ts +17 -18
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +196 -183
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/set-backend.d.ts +53 -0
- package/dist/cli/set-backend.d.ts.map +1 -0
- package/dist/cli/set-backend.js +259 -0
- package/dist/cli/set-backend.js.map +1 -0
- package/dist/cli/visualize.d.ts +38 -0
- package/dist/cli/visualize.d.ts.map +1 -0
- package/dist/cli/visualize.js +125 -0
- package/dist/cli/visualize.js.map +1 -0
- package/dist/compiler.d.ts +5 -52
- package/dist/compiler.d.ts.map +1 -1
- package/dist/compiler.js +4 -768
- package/dist/compiler.js.map +1 -1
- package/dist/index.d.ts +27 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -2
- package/dist/index.js.map +1 -1
- package/dist/prolog/bridge.d.ts +3 -1
- package/dist/prolog/bridge.d.ts.map +1 -1
- package/dist/prolog/bridge.js +8 -1
- package/dist/prolog/bridge.js.map +1 -1
- package/dist/prolog-src/deepclause_analysis.pl +10 -2
- package/dist/prolog-src/deepclause_mi.pl +2245 -41
- package/dist/repl/agent.d.ts +72 -0
- package/dist/repl/agent.d.ts.map +1 -0
- package/dist/repl/agent.js +366 -0
- package/dist/repl/agent.js.map +1 -0
- package/dist/repl/auth.d.ts +45 -0
- package/dist/repl/auth.d.ts.map +1 -0
- package/dist/repl/auth.js +116 -0
- package/dist/repl/auth.js.map +1 -0
- package/dist/repl/backend.d.ts +290 -0
- package/dist/repl/backend.d.ts.map +1 -0
- package/dist/repl/backend.js +370 -0
- package/dist/repl/backend.js.map +1 -0
- package/dist/repl/compaction.d.ts +122 -0
- package/dist/repl/compaction.d.ts.map +1 -0
- package/dist/repl/compaction.js +318 -0
- package/dist/repl/compaction.js.map +1 -0
- package/dist/repl/export.d.ts +30 -0
- package/dist/repl/export.d.ts.map +1 -0
- package/dist/repl/export.js +23 -0
- package/dist/repl/export.js.map +1 -0
- package/dist/repl/frames.d.ts +21 -0
- package/dist/repl/frames.d.ts.map +1 -0
- package/dist/repl/frames.js +79 -0
- package/dist/repl/frames.js.map +1 -0
- package/dist/repl/harness-tools.d.ts +74 -0
- package/dist/repl/harness-tools.d.ts.map +1 -0
- package/dist/repl/harness-tools.js +121 -0
- package/dist/repl/harness-tools.js.map +1 -0
- package/dist/repl/highlight.d.ts +30 -0
- package/dist/repl/highlight.d.ts.map +1 -0
- package/dist/repl/highlight.js +285 -0
- package/dist/repl/highlight.js.map +1 -0
- package/dist/repl/history.d.ts +234 -0
- package/dist/repl/history.d.ts.map +1 -0
- package/dist/repl/history.js +661 -0
- package/dist/repl/history.js.map +1 -0
- package/dist/repl/index.d.ts +120 -0
- package/dist/repl/index.d.ts.map +1 -0
- package/dist/repl/index.js +107 -0
- package/dist/repl/index.js.map +1 -0
- package/dist/repl/judge.d.ts +51 -0
- package/dist/repl/judge.d.ts.map +1 -0
- package/dist/repl/judge.js +58 -0
- package/dist/repl/judge.js.map +1 -0
- package/dist/repl/markdown.d.ts +25 -0
- package/dist/repl/markdown.d.ts.map +1 -0
- package/dist/repl/markdown.js +103 -0
- package/dist/repl/markdown.js.map +1 -0
- package/dist/repl/picker.d.ts +34 -0
- package/dist/repl/picker.d.ts.map +1 -0
- package/dist/repl/picker.js +81 -0
- package/dist/repl/picker.js.map +1 -0
- package/dist/repl/project-context.d.ts +16 -0
- package/dist/repl/project-context.d.ts.map +1 -0
- package/dist/repl/project-context.js +23 -0
- package/dist/repl/project-context.js.map +1 -0
- package/dist/repl/render.d.ts +160 -0
- package/dist/repl/render.d.ts.map +1 -0
- package/dist/repl/render.js +715 -0
- package/dist/repl/render.js.map +1 -0
- package/dist/repl/session.d.ts +356 -0
- package/dist/repl/session.d.ts.map +1 -0
- package/dist/repl/session.js +1275 -0
- package/dist/repl/session.js.map +1 -0
- package/dist/repl/status.d.ts +100 -0
- package/dist/repl/status.d.ts.map +1 -0
- package/dist/repl/status.js +218 -0
- package/dist/repl/status.js.map +1 -0
- package/dist/repl/tools.d.ts +53 -0
- package/dist/repl/tools.d.ts.map +1 -0
- package/dist/repl/tools.js +307 -0
- package/dist/repl/tools.js.map +1 -0
- package/dist/repl/toolset.d.ts +32 -0
- package/dist/repl/toolset.d.ts.map +1 -0
- package/dist/repl/toolset.js +82 -0
- package/dist/repl/toolset.js.map +1 -0
- package/dist/repl/tui/editor.d.ts +17 -0
- package/dist/repl/tui/editor.d.ts.map +1 -0
- package/dist/repl/tui/editor.js +39 -0
- package/dist/repl/tui/editor.js.map +1 -0
- package/dist/repl/tui/status-bar.d.ts +26 -0
- package/dist/repl/tui/status-bar.d.ts.map +1 -0
- package/dist/repl/tui/status-bar.js +47 -0
- package/dist/repl/tui/status-bar.js.map +1 -0
- package/dist/repl/tui/theme.d.ts +30 -0
- package/dist/repl/tui/theme.d.ts.map +1 -0
- package/dist/repl/tui/theme.js +81 -0
- package/dist/repl/tui/theme.js.map +1 -0
- package/dist/repl/tui/transcript.d.ts +39 -0
- package/dist/repl/tui/transcript.d.ts.map +1 -0
- package/dist/repl/tui/transcript.js +123 -0
- package/dist/repl/tui/transcript.js.map +1 -0
- package/dist/runner.d.ts +132 -13
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +434 -277
- package/dist/runner.js.map +1 -1
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +0 -32
- package/dist/sdk.js.map +1 -1
- package/dist/system/assets/docs/AGENT_PROMPT.md +1373 -0
- package/dist/system/assets/docs/DML_AUTHORING.md +195 -0
- package/dist/system/assets/docs/DML_REFERENCE.md +312 -72
- package/dist/system/assets/docs/HARNESS_EXAMPLES.md +172 -0
- package/dist/system/assets/docs/HARNESS_PATTERNS.md +562 -0
- package/dist/system/assets/docs/META_PROMPT.md +68 -0
- package/dist/system/assets/docs/PROLOG_SNIPPETS.md +117 -0
- package/dist/system/assets/index.d.ts +9 -17
- package/dist/system/assets/index.d.ts.map +1 -1
- package/dist/system/assets/index.js +26 -85
- package/dist/system/assets/index.js.map +1 -1
- package/dist/system/runtime/agentvm-manager.d.ts +9 -2
- package/dist/system/runtime/agentvm-manager.d.ts.map +1 -1
- package/dist/system/runtime/agentvm-manager.js +70 -44
- package/dist/system/runtime/agentvm-manager.js.map +1 -1
- package/dist/system/runtime/media.d.ts +23 -0
- package/dist/system/runtime/media.d.ts.map +1 -0
- package/dist/system/runtime/media.js +55 -0
- package/dist/system/runtime/media.js.map +1 -0
- package/dist/system/runtime/shell-limits.d.ts +21 -0
- package/dist/system/runtime/shell-limits.d.ts.map +1 -0
- package/dist/system/runtime/shell-limits.js +39 -0
- package/dist/system/runtime/shell-limits.js.map +1 -0
- package/dist/system/runtime/shell-manager.d.ts +8 -3
- package/dist/system/runtime/shell-manager.d.ts.map +1 -1
- package/dist/system/runtime/shell-manager.js +56 -39
- package/dist/system/runtime/shell-manager.js.map +1 -1
- package/dist/system/runtime/shell-tool-events.js +5 -0
- package/dist/system/runtime/shell-tool-events.js.map +1 -1
- package/dist/system/runtime/token-usage.d.ts +2 -0
- package/dist/system/runtime/token-usage.d.ts.map +1 -1
- package/dist/system/runtime/token-usage.js +7 -0
- package/dist/system/runtime/token-usage.js.map +1 -1
- package/dist/tools.d.ts +3 -21
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +14 -168
- package/dist/tools.js.map +1 -1
- package/dist/types.d.ts +80 -118
- package/dist/types.d.ts.map +1 -1
- package/dist/validate.d.ts +19 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +338 -0
- package/dist/validate.js.map +1 -0
- package/dist/visualize/index.d.ts +52 -0
- package/dist/visualize/index.d.ts.map +1 -0
- package/dist/visualize/index.js +189 -0
- package/dist/visualize/index.js.map +1 -0
- package/package.json +17 -15
- package/src/prolog-src/deepclause_analysis.pl +10 -2
- package/src/prolog-src/deepclause_mi.pl +2245 -41
- package/dist/cli/commands.d.ts +0 -42
- package/dist/cli/commands.d.ts.map +0 -1
- package/dist/cli/commands.js +0 -246
- package/dist/cli/commands.js.map +0 -1
- package/dist/cli/compile.d.ts +0 -99
- package/dist/cli/compile.d.ts.map +0 -1
- package/dist/cli/compile.js +0 -363
- package/dist/cli/compile.js.map +0 -1
- package/dist/cli/default-skills.d.ts +0 -10
- package/dist/cli/default-skills.d.ts.map +0 -1
- package/dist/cli/default-skills.js +0 -206
- package/dist/cli/default-skills.js.map +0 -1
- package/dist/cli/interactive.d.ts +0 -2
- package/dist/cli/interactive.d.ts.map +0 -1
- package/dist/cli/interactive.js +0 -20
- package/dist/cli/interactive.js.map +0 -1
- package/dist/cli/mcp.d.ts +0 -56
- package/dist/cli/mcp.d.ts.map +0 -1
- package/dist/cli/mcp.js +0 -138
- package/dist/cli/mcp.js.map +0 -1
- package/dist/cli/prompt.d.ts +0 -2
- package/dist/cli/prompt.d.ts.map +0 -1
- package/dist/cli/prompt.js +0 -2
- package/dist/cli/prompt.js.map +0 -1
- package/dist/cli/search.d.ts +0 -19
- package/dist/cli/search.d.ts.map +0 -1
- package/dist/cli/search.js +0 -189
- package/dist/cli/search.js.map +0 -1
- package/dist/cli/tool-args.d.ts +0 -2
- package/dist/cli/tool-args.d.ts.map +0 -1
- package/dist/cli/tool-args.js +0 -39
- package/dist/cli/tool-args.js.map +0 -1
- package/dist/cli/tools.d.ts +0 -36
- package/dist/cli/tools.d.ts.map +0 -1
- package/dist/cli/tools.js +0 -229
- package/dist/cli/tools.js.map +0 -1
- package/dist/cli/tui/index.d.ts +0 -22
- package/dist/cli/tui/index.d.ts.map +0 -1
- package/dist/cli/tui/index.js +0 -29
- package/dist/cli/tui/index.js.map +0 -1
- package/dist/cli/tui.d.ts +0 -167
- package/dist/cli/tui.d.ts.map +0 -1
- package/dist/cli/tui.js +0 -5228
- package/dist/cli/tui.js.map +0 -1
- package/dist/compiler_prompt.d.ts +0 -20
- package/dist/compiler_prompt.d.ts.map +0 -1
- package/dist/compiler_prompt.js +0 -870
- package/dist/compiler_prompt.js.map +0 -1
- package/dist/deepclause-cli.skill +0 -0
- package/dist/prolog-src/deepclause_mi.pl.bak +0 -570
- package/dist/system/assets/docs/CONDUCTOR_PROMPT.md +0 -105
- package/dist/system/assets/docs/DML_COMPILER_PROMPT.md +0 -700
- package/dist/system/assets/docs/TUI.md +0 -150
- package/dist/system/assets/recipes/deepclause-coding-workflow/SKILL.md +0 -100
- package/dist/system/assets/skills/conductor.dml +0 -76
- package/dist/system/assets/skills/deep-planner.dml +0 -412
- package/dist/system/assets/skills/plan.dml +0 -429
- package/dist/system/assets/skills/security-planner.dml +0 -337
- package/dist/system/assets/skills/skill-creator.dml +0 -187
- package/dist/system/runtime/catalog-recipes.d.ts +0 -24
- package/dist/system/runtime/catalog-recipes.d.ts.map +0 -1
- package/dist/system/runtime/catalog-recipes.js +0 -273
- package/dist/system/runtime/catalog-recipes.js.map +0 -1
- package/dist/system/runtime/catalog-skills.d.ts +0 -50
- package/dist/system/runtime/catalog-skills.d.ts.map +0 -1
- package/dist/system/runtime/catalog-skills.js +0 -152
- package/dist/system/runtime/catalog-skills.js.map +0 -1
- package/dist/system/runtime/conductor.d.ts +0 -105
- package/dist/system/runtime/conductor.d.ts.map +0 -1
- package/dist/system/runtime/conductor.js +0 -732
- package/dist/system/runtime/conductor.js.map +0 -1
- package/dist/system/runtime/console-capture.d.ts +0 -9
- package/dist/system/runtime/console-capture.d.ts.map +0 -1
- package/dist/system/runtime/console-capture.js +0 -67
- package/dist/system/runtime/console-capture.js.map +0 -1
- package/dist/system/runtime/dml-executor.d.ts +0 -52
- package/dist/system/runtime/dml-executor.d.ts.map +0 -1
- package/dist/system/runtime/dml-executor.js +0 -203
- package/dist/system/runtime/dml-executor.js.map +0 -1
- package/dist/system/runtime/runtime-tools.d.ts +0 -31
- package/dist/system/runtime/runtime-tools.d.ts.map +0 -1
- package/dist/system/runtime/runtime-tools.js +0 -312
- package/dist/system/runtime/runtime-tools.js.map +0 -1
- package/dist/system/runtime/skill-creator.d.ts +0 -38
- package/dist/system/runtime/skill-creator.d.ts.map +0 -1
- package/dist/system/runtime/skill-creator.js +0 -763
- package/dist/system/runtime/skill-creator.js.map +0 -1
- package/src/prolog-src/deepclause_mi.pl.bak +0 -570
package/dist/validate.js
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DML validation and linting.
|
|
3
|
+
*
|
|
4
|
+
* Parses DML with the real Prolog reader and applies structural/lint checks.
|
|
5
|
+
* This is the surviving part of the old compiler module (the Markdown->DML
|
|
6
|
+
* generator was removed); it is exported as `deepclause-sdk/validate` and used
|
|
7
|
+
* by the CLI's `validate_dml` runtime tool and by downstream apps
|
|
8
|
+
* (`deepclause-pi`, `sop2harness`).
|
|
9
|
+
*/
|
|
10
|
+
import { loadProlog } from './prolog/loader.js';
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// Prolog Validation
|
|
13
|
+
// =============================================================================
|
|
14
|
+
let prologInstance = null;
|
|
15
|
+
/**
|
|
16
|
+
* Get or initialize Prolog instance for validation
|
|
17
|
+
*/
|
|
18
|
+
async function getProlog() {
|
|
19
|
+
if (!prologInstance) {
|
|
20
|
+
prologInstance = await loadProlog();
|
|
21
|
+
}
|
|
22
|
+
return prologInstance;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Validate DML code using the actual Prolog parser
|
|
26
|
+
*/
|
|
27
|
+
export async function validateWithProlog(dml) {
|
|
28
|
+
const errors = [];
|
|
29
|
+
const warnings = [];
|
|
30
|
+
try {
|
|
31
|
+
const swipl = await getProlog();
|
|
32
|
+
// Write code to temp file
|
|
33
|
+
const tempPath = `/tmp/validate_${Date.now()}_${Math.random().toString(36).substring(7)}.pl`;
|
|
34
|
+
swipl.FS.writeFile(tempPath, dml);
|
|
35
|
+
// Try to parse the file using read_term which will catch syntax errors
|
|
36
|
+
try {
|
|
37
|
+
swipl.prolog.query(`catch(
|
|
38
|
+
(
|
|
39
|
+
open('${tempPath}', read, Stream, []),
|
|
40
|
+
call_cleanup(
|
|
41
|
+
read_all_terms(Stream),
|
|
42
|
+
close(Stream)
|
|
43
|
+
)
|
|
44
|
+
),
|
|
45
|
+
Error,
|
|
46
|
+
(
|
|
47
|
+
Error = error(syntax_error(Message), _) ->
|
|
48
|
+
true
|
|
49
|
+
;
|
|
50
|
+
(term_to_atom(Error, Message), true)
|
|
51
|
+
)
|
|
52
|
+
),
|
|
53
|
+
read_all_terms(S) :-
|
|
54
|
+
repeat,
|
|
55
|
+
read_term(S, T, [syntax_errors(error)]),
|
|
56
|
+
(T == end_of_file -> ! ; fail)`);
|
|
57
|
+
// Simple approach: try to consult the file
|
|
58
|
+
try {
|
|
59
|
+
swipl.prolog.call(`consult('${tempPath}')`);
|
|
60
|
+
}
|
|
61
|
+
catch (consultError) {
|
|
62
|
+
const errMsg = consultError instanceof Error ? consultError.message : String(consultError);
|
|
63
|
+
if (errMsg.includes('syntax') || errMsg.includes('error')) {
|
|
64
|
+
// Extract meaningful error message
|
|
65
|
+
const match = errMsg.match(/(?:syntax_error|error)\s*\(\s*['"]?([^'")\]]+)/i);
|
|
66
|
+
if (match) {
|
|
67
|
+
errors.push(`Syntax error: ${match[1]}`);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
errors.push(`Parse error: ${errMsg.substring(0, 200)}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
const errMsg = e instanceof Error ? e.message : String(e);
|
|
77
|
+
if (errMsg.includes('syntax') || errMsg.includes('error')) {
|
|
78
|
+
errors.push(errMsg.substring(0, 200));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Check for required elements
|
|
82
|
+
if (!dml.includes('agent_main')) {
|
|
83
|
+
errors.push('Missing agent_main predicate - every DML program must define agent_main');
|
|
84
|
+
}
|
|
85
|
+
// Check for balanced delimiters
|
|
86
|
+
const delimiterCheck = checkBalancedDelimiters(dml);
|
|
87
|
+
errors.push(...delimiterCheck.errors);
|
|
88
|
+
// Check for common mistakes
|
|
89
|
+
const lintResult = lintDML(dml);
|
|
90
|
+
errors.push(...lintResult.errors);
|
|
91
|
+
warnings.push(...lintResult.warnings);
|
|
92
|
+
// Cleanup temp file
|
|
93
|
+
try {
|
|
94
|
+
swipl.FS.unlink(tempPath);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// Ignore cleanup errors
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
// If Prolog itself fails, fall back to basic validation
|
|
102
|
+
return validateDMLSyntaxBasic(dml);
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
valid: errors.length === 0,
|
|
106
|
+
errors,
|
|
107
|
+
warnings: warnings.length > 0 ? warnings : undefined
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Check balanced delimiters
|
|
112
|
+
*/
|
|
113
|
+
function checkBalancedDelimiters(dml) {
|
|
114
|
+
const errors = [];
|
|
115
|
+
// Remove strings and comments for delimiter checking
|
|
116
|
+
const stripped = dml
|
|
117
|
+
.replace(/"(?:[^"\\]|\\.)*"/g, '""') // Remove string contents
|
|
118
|
+
.replace(/%.*$/gm, '') // Remove line comments
|
|
119
|
+
.replace(/\/\*[\s\S]*?\*\//g, ''); // Remove block comments
|
|
120
|
+
let parenCount = 0;
|
|
121
|
+
let bracketCount = 0;
|
|
122
|
+
let braceCount = 0;
|
|
123
|
+
for (const char of stripped) {
|
|
124
|
+
if (char === '(')
|
|
125
|
+
parenCount++;
|
|
126
|
+
if (char === ')')
|
|
127
|
+
parenCount--;
|
|
128
|
+
if (char === '[')
|
|
129
|
+
bracketCount++;
|
|
130
|
+
if (char === ']')
|
|
131
|
+
bracketCount--;
|
|
132
|
+
if (char === '{')
|
|
133
|
+
braceCount++;
|
|
134
|
+
if (char === '}')
|
|
135
|
+
braceCount--;
|
|
136
|
+
if (parenCount < 0) {
|
|
137
|
+
errors.push('Unbalanced parentheses: extra closing )');
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
if (bracketCount < 0) {
|
|
141
|
+
errors.push('Unbalanced brackets: extra closing ]');
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
if (braceCount < 0) {
|
|
145
|
+
errors.push('Unbalanced braces: extra closing }');
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (parenCount > 0)
|
|
150
|
+
errors.push(`Unbalanced parentheses: ${parenCount} unclosed (`);
|
|
151
|
+
if (bracketCount > 0)
|
|
152
|
+
errors.push(`Unbalanced brackets: ${bracketCount} unclosed [`);
|
|
153
|
+
if (braceCount > 0)
|
|
154
|
+
errors.push(`Unbalanced braces: ${braceCount} unclosed {`);
|
|
155
|
+
return { errors };
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Extract all string literals from DML code (both single and double quoted)
|
|
159
|
+
*/
|
|
160
|
+
function extractStringLiterals(dml) {
|
|
161
|
+
const doubleQuoted = [];
|
|
162
|
+
const singleQuoted = [];
|
|
163
|
+
// Double-quoted strings
|
|
164
|
+
for (const m of dml.matchAll(/"((?:[^"\\]|\\.)*)"/g)) {
|
|
165
|
+
doubleQuoted.push(m[1]);
|
|
166
|
+
}
|
|
167
|
+
// Single-quoted atoms
|
|
168
|
+
for (const m of dml.matchAll(/'((?:[^'\\]|\\.)*)'/g)) {
|
|
169
|
+
singleQuoted.push(m[1]);
|
|
170
|
+
}
|
|
171
|
+
return { doubleQuoted, singleQuoted };
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Strip comments and string contents for structural analysis
|
|
175
|
+
*/
|
|
176
|
+
function stripForAnalysis(dml) {
|
|
177
|
+
return dml
|
|
178
|
+
.replace(/%.*$/gm, '') // line comments
|
|
179
|
+
.replace(/\/\*[\s\S]*?\*\//g, '') // block comments
|
|
180
|
+
.replace(/"(?:[^"\\]|\\.)*"/g, '""') // double-quoted string contents
|
|
181
|
+
.replace(/'(?:[^'\\]|\\.)*'/g, "''"); // single-quoted atom contents
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Lint DML for common issues — focused on string handling and structural errors.
|
|
185
|
+
* Returns errors (will crash at runtime) and warnings (likely wrong).
|
|
186
|
+
*/
|
|
187
|
+
function lintDML(dml) {
|
|
188
|
+
const errors = [];
|
|
189
|
+
const warnings = [];
|
|
190
|
+
const stripped = stripForAnalysis(dml);
|
|
191
|
+
const { doubleQuoted, singleQuoted } = extractStringLiterals(dml);
|
|
192
|
+
const allStrings = [...doubleQuoted, ...singleQuoted];
|
|
193
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
194
|
+
// STRING HANDLING ERRORS — these WILL crash or produce wrong output
|
|
195
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
196
|
+
// E1: format() passed directly to output() or answer()
|
|
197
|
+
// format/3 binds its first arg, it does NOT return a value.
|
|
198
|
+
// output(format("...", [...])) is always wrong.
|
|
199
|
+
if (/output\s*\(\s*format\s*\(/.test(dml)) {
|
|
200
|
+
errors.push('ERROR: format/3 does not return a value. `output(format(...))` will crash. Fix: format(string(S), "...", [...]), output(S).');
|
|
201
|
+
}
|
|
202
|
+
if (/answer\s*\(\s*format\s*\(/.test(dml)) {
|
|
203
|
+
errors.push('ERROR: format/3 does not return a value. `answer(format(...))` will crash. Fix: format(string(S), "...", [...]), answer(S).');
|
|
204
|
+
}
|
|
205
|
+
// E2: ~Variable in task/prompt description strings (only ~w, ~d, ~a, ~s work with format)
|
|
206
|
+
// task("Analyze ~Topic", R) does NOT interpolate. Use {Topic}.
|
|
207
|
+
for (const s of doubleQuoted) {
|
|
208
|
+
if (/~[A-Z][a-zA-Z0-9_]*/.test(s)) {
|
|
209
|
+
errors.push(`ERROR: ~Variable interpolation does not work in DML. Found in: "...${s.substring(0, 60)}...". Use {Variable} syntax instead (e.g. {Topic} not ~Topic).`);
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// E3: {Variable} inside format/3 template string
|
|
214
|
+
// format(string(S), "Hello {Name}", []) — the {Name} won't be interpolated by format.
|
|
215
|
+
// This is a style-mixing bug.
|
|
216
|
+
const formatCalls = dml.matchAll(/format\s*\(\s*(?:string|atom)\s*\([^)]*\)\s*,\s*"([^"]*)"/g);
|
|
217
|
+
for (const m of formatCalls) {
|
|
218
|
+
const tmpl = m[1];
|
|
219
|
+
if (/\{[A-Z][a-zA-Z0-9_]*\}/.test(tmpl)) {
|
|
220
|
+
errors.push(`ERROR: {Variable} inside format() template does nothing — format uses ~w placeholders. Found: "${tmpl.substring(0, 60)}". Use EITHER {Variable} in task() strings OR ~w in format() strings, never both in the same string.`);
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// E4: String concatenation with + operator
|
|
225
|
+
// "hello" + "world" or Var + Var — Prolog's + is arithmetic only.
|
|
226
|
+
if (/"\s*\+\s*"/.test(dml) || /"\s*\+\s*[A-Z]/.test(dml) || /[A-Z][a-zA-Z_0-9]*\s*\+\s*"/.test(dml)) {
|
|
227
|
+
errors.push('ERROR: The + operator is arithmetic only in Prolog, not string concatenation. Use {Variable} interpolation in task() strings, or atom_concat/3, or format/3 for building strings.');
|
|
228
|
+
}
|
|
229
|
+
// E5: task() with non-string first arg — task(llm(...)) or task(prompt(...))
|
|
230
|
+
if (/task\s*\(\s*(?:llm|prompt)\s*\(/.test(stripped)) {
|
|
231
|
+
errors.push('ERROR: task() takes a plain string as first argument. task(llm(...)) and task(prompt(...)) are wrong. Use: task("description string", Var).');
|
|
232
|
+
}
|
|
233
|
+
// E6: Hallucinated predicates — these do NOT exist in DML runtime
|
|
234
|
+
// But skip if user defines the predicate themselves (pred(...) :- ...).
|
|
235
|
+
const hallucinated = [
|
|
236
|
+
['json_parse', 'json_parse/2 does not exist. Use task() to extract data from JSON via LLM.'],
|
|
237
|
+
['http_get', 'http_get does not exist. Use exec(url_fetch(url: URL), R).'],
|
|
238
|
+
['string_format', 'string_format does not exist. Use format(string(R), FormatStr, Args).'],
|
|
239
|
+
['get_field', 'get_field does not exist. Use get_dict(Key, Dict, Value) — note: Key comes first.'],
|
|
240
|
+
['string_join', 'string_join does not exist. Use atomic_list_concat(List, Sep, Atom).'],
|
|
241
|
+
['string_lower', 'string_lower does not exist. Use downcase_atom(Atom, Lower).'],
|
|
242
|
+
['string_trim', 'string_trim does not exist. Use normalize_space(string(Out), In).'],
|
|
243
|
+
['contains', 'contains/2 does not exist. Use sub_atom/5 or sub_string/5.'],
|
|
244
|
+
];
|
|
245
|
+
for (const [name, msg] of hallucinated) {
|
|
246
|
+
const usePattern = new RegExp(`(?<!\\w)${name}\\s*\\(`, 'g');
|
|
247
|
+
if (usePattern.test(stripped)) {
|
|
248
|
+
// Check if user defines this predicate (name(...) :- or name(...) .)
|
|
249
|
+
const defPattern = new RegExp(`^${name}\\s*\\([^)]*\\)\\s*(?::-|\\.)`, 'm');
|
|
250
|
+
if (!defPattern.test(stripped)) {
|
|
251
|
+
errors.push(`ERROR: ${msg}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
// E7: url_fetch used as a bare predicate (not wrapped in exec)
|
|
256
|
+
// url_fetch("url", R) is wrong. Must be exec(url_fetch(url: "..."), R).
|
|
257
|
+
if (/(?<!exec\s*\(\s*)url_fetch\s*\(\s*"/.test(stripped)) {
|
|
258
|
+
errors.push('ERROR: url_fetch is not a predicate. Must use exec/2 wrapper: exec(url_fetch(url: URL), R).');
|
|
259
|
+
}
|
|
260
|
+
// E8: curl/wget in bash command strings
|
|
261
|
+
for (const s of allStrings) {
|
|
262
|
+
if (/\b(?:curl|wget)\s/.test(s)) {
|
|
263
|
+
errors.push('ERROR: curl and wget are banned — the VM has no direct internet. Use exec(url_fetch(url: URL), R) to fetch web content.');
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// E9: writeln() used for user output — not a DML predicate
|
|
268
|
+
if (/(?<!\w)writeln\s*\(/.test(stripped)) {
|
|
269
|
+
// Check it's not inside an open/close file I/O block (write to stream is OK)
|
|
270
|
+
// Simple heuristic: if there's no open() call, writeln is definitely wrong
|
|
271
|
+
if (!/\bopen\s*\(/.test(stripped) || /writeln\s*\(\s*['"]/.test(dml)) {
|
|
272
|
+
errors.push('ERROR: writeln() is not a DML output predicate. Use output() for progress messages and answer() for final results.');
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
276
|
+
// STRING HANDLING WARNINGS — likely wrong, should fix
|
|
277
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
278
|
+
// W1: Mixing {Variable} interpolation and format/3 in the same clause
|
|
279
|
+
// Not always wrong (different strings), but a code smell with small models
|
|
280
|
+
const hasInterpolation = /\{[A-Z][a-zA-Z0-9_]*\}/.test(dml);
|
|
281
|
+
const hasFormat = /format\s*\(/.test(stripped);
|
|
282
|
+
if (hasInterpolation && hasFormat) {
|
|
283
|
+
warnings.push('WARNING: Code mixes {Variable} interpolation and format/3. This is allowed but can confuse the runtime if mixed in the same string. Ensure {Variable} is only in task()/output()/answer() strings and ~w is only in format() strings.');
|
|
284
|
+
}
|
|
285
|
+
// W2: No tool definitions — model probably wrote pure Prolog
|
|
286
|
+
if (!/\btool\s*\(/.test(dml)) {
|
|
287
|
+
warnings.push('WARNING: No tool() definitions found. This is fine for pure Prolog or direct exec()-only skills, but LLM-driven skills usually need tool()/3 wrappers for task() calls.');
|
|
288
|
+
}
|
|
289
|
+
// W3: No task() call — model probably wrote pure Prolog logic
|
|
290
|
+
if (!/\btask\s*\(/.test(stripped)) {
|
|
291
|
+
warnings.push('WARNING: No task() call found. This is fine for deterministic or simple skills. Skills that need open-ended reasoning, summarization, extraction, or classification should usually use task().');
|
|
292
|
+
}
|
|
293
|
+
// W4: No system() call — LLM has no instructions
|
|
294
|
+
if (!/\bsystem\s*\(/.test(stripped)) {
|
|
295
|
+
warnings.push('WARNING: No system() call found. Add system() when the skill uses task()/prompt() and the LLM needs instructions on how to use tools.');
|
|
296
|
+
}
|
|
297
|
+
// W5: No answer() call — skill completes silently
|
|
298
|
+
if (!/\banswer\s*\(/.test(stripped)) {
|
|
299
|
+
warnings.push('WARNING: No answer() call found. The skill will complete without returning a result to the user.');
|
|
300
|
+
}
|
|
301
|
+
// W6: No output() before task/exec — skill appears frozen
|
|
302
|
+
if (/\btask\s*\(/.test(stripped) && !/\boutput\s*\(/.test(stripped)) {
|
|
303
|
+
warnings.push('WARNING: No output() calls found. Add output() before long-running task() or exec() calls so the skill doesn\'t appear frozen.');
|
|
304
|
+
}
|
|
305
|
+
// W7: Single agent_main clause — no fallback
|
|
306
|
+
const mainMatches = stripped.match(/agent_main\s*[\(\.]/g);
|
|
307
|
+
if (mainMatches && mainMatches.length === 1) {
|
|
308
|
+
warnings.push('WARNING: Only one agent_main clause. Add a fallback clause with a static error message (no LLM calls) as required by Rule 7.');
|
|
309
|
+
}
|
|
310
|
+
// W8: Dict dot notation — Result.field etc.
|
|
311
|
+
// Only check outside strings — match Var.key pattern in code
|
|
312
|
+
if (/[A-Z][a-zA-Z_0-9]*\.[a-z][a-z_]+(?!\s*\()/.test(stripped)) {
|
|
313
|
+
warnings.push('WARNING: Possible dict dot notation (e.g. Result.stdout). This may not work — use get_dict(Key, Dict, Value) instead.');
|
|
314
|
+
}
|
|
315
|
+
return { errors, warnings };
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Basic syntax validation (fallback when Prolog fails)
|
|
319
|
+
*/
|
|
320
|
+
function validateDMLSyntaxBasic(dml) {
|
|
321
|
+
const errors = [];
|
|
322
|
+
if (!dml.includes('agent_main')) {
|
|
323
|
+
errors.push('Missing agent_main predicate');
|
|
324
|
+
}
|
|
325
|
+
const delimiterCheck = checkBalancedDelimiters(dml);
|
|
326
|
+
errors.push(...delimiterCheck.errors);
|
|
327
|
+
// Check for unclosed strings
|
|
328
|
+
const stringPattern = /"(?:[^"\\]|\\.)*"/g;
|
|
329
|
+
const cleanedDml = dml.replace(stringPattern, '""');
|
|
330
|
+
if ((cleanedDml.match(/"/g) || []).length % 2 !== 0) {
|
|
331
|
+
errors.push('Unclosed string literal');
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
valid: errors.length === 0,
|
|
335
|
+
errors: [...new Set(errors)]
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `deepclause visualize` — turn a harness (its `listing`, including `doc/2` and
|
|
3
|
+
* `module_doc/1`) into a Mermaid diagram.
|
|
4
|
+
*
|
|
5
|
+
* Two granularities, mirroring sop2harness:
|
|
6
|
+
* - `presentation`: a general-audience overview (inputs, steps, answer).
|
|
7
|
+
* - `spec`: engineering detail (decisions, thresholds, task/exec calls,
|
|
8
|
+
* branches, fallbacks).
|
|
9
|
+
*
|
|
10
|
+
* The Mermaid source is always the deliverable; PNG/SVG rendering is best
|
|
11
|
+
* effort via `@mermaid-js/mermaid-cli` (`mmdc`) when it is available.
|
|
12
|
+
*/
|
|
13
|
+
export type DiagramMode = 'presentation' | 'spec';
|
|
14
|
+
export interface DiagramPromptInput {
|
|
15
|
+
/** Entry predicate, e.g. `router/2`. */
|
|
16
|
+
entry: string;
|
|
17
|
+
mode: DiagramMode;
|
|
18
|
+
/** The harness `listing` text (source + `doc/2` annotations + manifest). */
|
|
19
|
+
listing: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Build the diagram-generation prompt. The model only sees the harness listing
|
|
23
|
+
* (source + docs) and the entry point, and must return Mermaid only.
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildDiagramPrompt(input: DiagramPromptInput): string;
|
|
26
|
+
/** Extract Mermaid source from a model reply (strips fences and leading prose). */
|
|
27
|
+
export declare function extractMermaid(text: string): string;
|
|
28
|
+
/** Light structural validation (same spirit as sop2harness). */
|
|
29
|
+
export declare function validateMermaid(source: string): string[];
|
|
30
|
+
/** A mermaid renderer command, if one is available. */
|
|
31
|
+
export declare function findMermaidRenderer(): {
|
|
32
|
+
command: string;
|
|
33
|
+
args: string[];
|
|
34
|
+
} | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Render a `.mmd` file to an image. Returns the renderer used, or throws with a
|
|
37
|
+
* helpful message when no renderer is available.
|
|
38
|
+
*/
|
|
39
|
+
export declare function renderMermaidFile(mmdPath: string, outputPath: string): Promise<string>;
|
|
40
|
+
/** Split `name/arity` (or `name`) into a predicate name and arity. */
|
|
41
|
+
export declare function parseEntry(entry: string): {
|
|
42
|
+
name: string;
|
|
43
|
+
arity?: number;
|
|
44
|
+
};
|
|
45
|
+
/** Resolve the `.mmd` path and the optional image path from `--output`. */
|
|
46
|
+
export declare function resolveOutputPaths(output: string | undefined, entry: string): {
|
|
47
|
+
mmdPath: string;
|
|
48
|
+
imagePath?: string;
|
|
49
|
+
};
|
|
50
|
+
/** Write the Mermaid source (creating directories as needed). */
|
|
51
|
+
export declare function writeMermaid(mmdPath: string, source: string): Promise<void>;
|
|
52
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/visualize/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,MAAM,MAAM,WAAW,GAAG,cAAc,GAAG,MAAM,CAAC;AAIlD,MAAM,WAAW,kBAAkB;IACjC,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,WAAW,CAAC;IAClB,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAuCpE;AAED,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYnD;AAED,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAoBxD;AAED,uDAAuD;AACvD,wBAAgB,mBAAmB,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,SAAS,CAQrF;AAiBD;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsC5F;AAED,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAU1E;AAED,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CASrH;AAED,iEAAiE;AACjE,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGjF"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `deepclause visualize` — turn a harness (its `listing`, including `doc/2` and
|
|
3
|
+
* `module_doc/1`) into a Mermaid diagram.
|
|
4
|
+
*
|
|
5
|
+
* Two granularities, mirroring sop2harness:
|
|
6
|
+
* - `presentation`: a general-audience overview (inputs, steps, answer).
|
|
7
|
+
* - `spec`: engineering detail (decisions, thresholds, task/exec calls,
|
|
8
|
+
* branches, fallbacks).
|
|
9
|
+
*
|
|
10
|
+
* The Mermaid source is always the deliverable; PNG/SVG rendering is best
|
|
11
|
+
* effort via `@mermaid-js/mermaid-cli` (`mmdc`) when it is available.
|
|
12
|
+
*/
|
|
13
|
+
import { spawnSync } from 'child_process';
|
|
14
|
+
import * as fs from 'fs/promises';
|
|
15
|
+
import * as os from 'os';
|
|
16
|
+
import * as path from 'path';
|
|
17
|
+
const DIAGRAM_TYPE = /^\s*(flowchart|graph|sequenceDiagram|classDiagram|stateDiagram|erDiagram|journey|gantt|pie)\b/i;
|
|
18
|
+
/**
|
|
19
|
+
* Build the diagram-generation prompt. The model only sees the harness listing
|
|
20
|
+
* (source + docs) and the entry point, and must return Mermaid only.
|
|
21
|
+
*/
|
|
22
|
+
export function buildDiagramPrompt(input) {
|
|
23
|
+
const kind = input.mode === 'presentation'
|
|
24
|
+
? [
|
|
25
|
+
'KIND: presentation — a general-audience overview.',
|
|
26
|
+
'- Show the skill name, its inputs, the main steps in order, and the final answer.',
|
|
27
|
+
'- Read like a process a stakeholder could follow. Avoid Prolog syntax and predicate names in labels.',
|
|
28
|
+
].join('\n')
|
|
29
|
+
: [
|
|
30
|
+
'KIND: specification — engineering detail.',
|
|
31
|
+
'- Show every decision (choose/verify/rate/probability, holds), threshold, and rule fact.',
|
|
32
|
+
'- Show task/N and prompt/N model calls (with their typed outputs), exec/2 tool calls, branches,',
|
|
33
|
+
' backtracking, and explicit fallback paths.',
|
|
34
|
+
].join('\n');
|
|
35
|
+
return [
|
|
36
|
+
'You are a technical writer who turns DeepClause (Prolog/DML) agent harnesses into Mermaid diagrams.',
|
|
37
|
+
'',
|
|
38
|
+
`Produce ONE Mermaid diagram for the skill \`${input.entry}\` in the harness below.`,
|
|
39
|
+
'',
|
|
40
|
+
'OUTPUT RULES',
|
|
41
|
+
'- Return ONLY Mermaid source. No prose, no explanation, no ``` code fences.',
|
|
42
|
+
'- The first line must be `flowchart TD` or `flowchart LR`.',
|
|
43
|
+
'- Quote any node label containing spaces or punctuation: A["text"], B["x = 1"].',
|
|
44
|
+
'- Plain flowchart syntax only (nodes, edges, subgraphs). No `classDef`/`style`/`click` directives.',
|
|
45
|
+
'- Keep it readable: at most about 20 nodes.',
|
|
46
|
+
'',
|
|
47
|
+
'HARNESS SEMANTICS',
|
|
48
|
+
'- task/N, prompt/N: a model call (prompt/N has fresh context).',
|
|
49
|
+
'- exec(Tool(...)): a host tool call (usually bash).',
|
|
50
|
+
'- choose/verify/rate/probability, holds: a semantic judgment (a decision).',
|
|
51
|
+
'- Multiple clauses / `;` / `->`: alternative paths; show the "else"/fallback.',
|
|
52
|
+
'',
|
|
53
|
+
kind,
|
|
54
|
+
'',
|
|
55
|
+
`HARNESS (focus: ${input.entry}; the listing includes each predicate and its doc/2 annotation)`,
|
|
56
|
+
'```',
|
|
57
|
+
input.listing.trim() || '(empty harness)',
|
|
58
|
+
'```',
|
|
59
|
+
].join('\n');
|
|
60
|
+
}
|
|
61
|
+
/** Extract Mermaid source from a model reply (strips fences and leading prose). */
|
|
62
|
+
export function extractMermaid(text) {
|
|
63
|
+
let out = (text ?? '').trim();
|
|
64
|
+
const fence = out.match(/```(?:mermaid)?\s*\n?([\s\S]*?)```/i);
|
|
65
|
+
if (fence) {
|
|
66
|
+
out = fence[1].trim();
|
|
67
|
+
}
|
|
68
|
+
const lines = out.split('\n');
|
|
69
|
+
const start = lines.findIndex((line) => DIAGRAM_TYPE.test(line));
|
|
70
|
+
if (start > 0) {
|
|
71
|
+
out = lines.slice(start).join('\n').trim();
|
|
72
|
+
}
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
/** Light structural validation (same spirit as sop2harness). */
|
|
76
|
+
export function validateMermaid(source) {
|
|
77
|
+
const issues = [];
|
|
78
|
+
const lines = source.split('\n').map((line) => line.trim()).filter(Boolean);
|
|
79
|
+
if (lines.length === 0) {
|
|
80
|
+
return ['the diagram is empty'];
|
|
81
|
+
}
|
|
82
|
+
const first = lines.find((line) => !line.startsWith('%%'));
|
|
83
|
+
if (!first) {
|
|
84
|
+
issues.push('no diagram body (only comments)');
|
|
85
|
+
}
|
|
86
|
+
else if (!DIAGRAM_TYPE.test(first)) {
|
|
87
|
+
issues.push(`unrecognized diagram type: ${first.split(/\s+/)[0]}`);
|
|
88
|
+
}
|
|
89
|
+
for (const [open, close] of [['{', '}'], ['[', ']'], ['(', ')']]) {
|
|
90
|
+
const opens = (source.match(new RegExp(`\\${open}`, 'g')) ?? []).length;
|
|
91
|
+
const closes = (source.match(new RegExp(`\\${close}`, 'g')) ?? []).length;
|
|
92
|
+
if (opens !== closes) {
|
|
93
|
+
issues.push(`unbalanced ${open}${close} (${opens}/${closes})`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return issues;
|
|
97
|
+
}
|
|
98
|
+
/** A mermaid renderer command, if one is available. */
|
|
99
|
+
export function findMermaidRenderer() {
|
|
100
|
+
const which = process.platform === 'win32' ? 'where' : 'which';
|
|
101
|
+
for (const candidate of ['mmdc', 'mmdc.cmd']) {
|
|
102
|
+
if (spawnSync(which, [candidate], { stdio: 'ignore' }).status === 0) {
|
|
103
|
+
return { command: candidate, args: [] };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
/** Absolute path to a system Chromium/Chrome, for puppeteer to launch. */
|
|
109
|
+
function findChrome() {
|
|
110
|
+
const which = process.platform === 'win32' ? 'where' : 'which';
|
|
111
|
+
for (const candidate of ['google-chrome', 'chromium', 'chromium-browser', 'chrome']) {
|
|
112
|
+
const result = spawnSync(which, [candidate], { encoding: 'utf8' });
|
|
113
|
+
if (result.status === 0) {
|
|
114
|
+
const first = (result.stdout ?? '').trim().split('\n')[0].trim();
|
|
115
|
+
if (first) {
|
|
116
|
+
return first;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Render a `.mmd` file to an image. Returns the renderer used, or throws with a
|
|
124
|
+
* helpful message when no renderer is available.
|
|
125
|
+
*/
|
|
126
|
+
export async function renderMermaidFile(mmdPath, outputPath) {
|
|
127
|
+
const renderer = findMermaidRenderer();
|
|
128
|
+
const command = renderer ? renderer.command : 'npx';
|
|
129
|
+
const args = renderer ? [...renderer.args] : ['--yes', '@mermaid-js/mermaid-cli'];
|
|
130
|
+
args.push('-i', mmdPath, '-o', outputPath, '-b', 'white');
|
|
131
|
+
const env = { ...process.env };
|
|
132
|
+
if (!env.PUPPETEER_EXECUTABLE_PATH) {
|
|
133
|
+
const chrome = findChrome();
|
|
134
|
+
if (chrome) {
|
|
135
|
+
env.PUPPETEER_EXECUTABLE_PATH = chrome;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Reuse the system browser instead of downloading Chromium for puppeteer.
|
|
139
|
+
if (env.PUPPETEER_EXECUTABLE_PATH && env.PUPPETEER_SKIP_DOWNLOAD == null) {
|
|
140
|
+
env.PUPPETEER_SKIP_DOWNLOAD = 'true';
|
|
141
|
+
}
|
|
142
|
+
// Chrome sandbox flags (mirrors sop2harness's `mmdc -p <config>` usage).
|
|
143
|
+
const configPath = path.join(os.tmpdir(), `deepclause-mermaid-${process.pid}.json`);
|
|
144
|
+
await fs.writeFile(configPath, JSON.stringify({
|
|
145
|
+
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
|
|
146
|
+
}));
|
|
147
|
+
args.push('-p', configPath);
|
|
148
|
+
try {
|
|
149
|
+
const result = spawnSync(command, args, { env, encoding: 'utf8' });
|
|
150
|
+
if (result.status !== 0) {
|
|
151
|
+
const reason = (result.stderr || result.stdout || '').trim().split('\n').slice(-3).join(' ');
|
|
152
|
+
throw new Error(`Mermaid renderer failed${reason ? `: ${reason}` : ''}. `
|
|
153
|
+
+ 'Install it with `npm i -g @mermaid-js/mermaid-cli` (or use `--output <file>.mmd`).');
|
|
154
|
+
}
|
|
155
|
+
return renderer ? renderer.command : 'npx @mermaid-js/mermaid-cli';
|
|
156
|
+
}
|
|
157
|
+
finally {
|
|
158
|
+
await fs.rm(configPath, { force: true });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/** Split `name/arity` (or `name`) into a predicate name and arity. */
|
|
162
|
+
export function parseEntry(entry) {
|
|
163
|
+
const match = entry.trim().match(/^([A-Za-z_][A-Za-z0-9_]*)\s*\/\s*(\d+)$/);
|
|
164
|
+
if (match) {
|
|
165
|
+
return { name: match[1], arity: Number(match[2]) };
|
|
166
|
+
}
|
|
167
|
+
const bare = entry.trim().match(/^([A-Za-z_][A-Za-z0-9_]*)$/);
|
|
168
|
+
if (bare) {
|
|
169
|
+
return { name: bare[1] };
|
|
170
|
+
}
|
|
171
|
+
throw new Error(`invalid entry '${entry}': expected Name/Arity (e.g. router/2)`);
|
|
172
|
+
}
|
|
173
|
+
/** Resolve the `.mmd` path and the optional image path from `--output`. */
|
|
174
|
+
export function resolveOutputPaths(output, entry) {
|
|
175
|
+
const fallback = `${entry.replace(/[^A-Za-z0-9_.-]/g, '_') || 'diagram'}.mmd`;
|
|
176
|
+
const target = output ?? fallback;
|
|
177
|
+
if (target.toLowerCase().endsWith('.mmd')) {
|
|
178
|
+
return { mmdPath: target };
|
|
179
|
+
}
|
|
180
|
+
const ext = path.extname(target);
|
|
181
|
+
const mmdPath = ext ? `${target.slice(0, -ext.length)}.mmd` : `${target}.mmd`;
|
|
182
|
+
return { mmdPath, imagePath: target };
|
|
183
|
+
}
|
|
184
|
+
/** Write the Mermaid source (creating directories as needed). */
|
|
185
|
+
export async function writeMermaid(mmdPath, source) {
|
|
186
|
+
await fs.mkdir(path.dirname(path.resolve(mmdPath)), { recursive: true });
|
|
187
|
+
await fs.writeFile(mmdPath, `${source.trim()}\n`, 'utf8');
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/visualize/index.ts"],"names":[],"mappings":"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"}
|