noteconnection 1.7.0 → 1.8.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/LICENSE +674 -21
- package/README.md +242 -62
- package/dist/src/agent_workspace.contract.parity.test.js +475 -0
- package/dist/src/agent_workspace.frontend.test.js +9989 -0
- package/dist/src/agent_workspace.locale.contract.test.js +95 -0
- package/dist/src/agent_workspace.runtime.behavior.test.js +5072 -0
- package/dist/src/copy.assets.contract.test.js +130 -0
- package/dist/src/core/PathBridge.js +28 -3
- package/dist/src/export/WorkspaceExportBundle.js +1130 -0
- package/dist/src/export/WorkspaceExportBundle.test.js +1480 -0
- package/dist/src/export/index.js +18 -0
- package/dist/src/export/types.js +2 -0
- package/dist/src/fixrisk.issue.verifier.contract.test.js +3 -1
- package/dist/src/foundation.ann.runtime.contract.test.js +81 -0
- package/dist/src/foundation.release.evidence.contract.test.js +406 -0
- package/dist/src/foundation.sqlite.runtime.contract.test.js +82 -0
- package/dist/src/frontend/README.md +242 -62
- package/dist/src/frontend/agent_workspace.js +5353 -0
- package/dist/src/frontend/agent_workspace_runtime.js +4434 -0
- package/dist/src/frontend/analysis.js +31 -4
- package/dist/src/frontend/app.js +2178 -62
- package/dist/src/frontend/focus_mode_interactions.js +33 -0
- package/dist/src/frontend/godot_future_path_renderer.js +540 -0
- package/dist/src/frontend/godot_tree_interactions.js +178 -0
- package/dist/src/frontend/graph_state.mjs +105 -0
- package/dist/src/frontend/hosted_future_path_runtime.js +157 -0
- package/dist/src/frontend/i18n.mjs +186 -0
- package/dist/src/frontend/index.html +641 -266
- package/dist/src/frontend/layout_gpu.js +12 -4
- package/dist/src/frontend/locales/en.json +721 -5
- package/dist/src/frontend/locales/zh.json +721 -5
- package/dist/src/frontend/main.mjs +60 -0
- package/dist/src/frontend/markdown_runtime.js +827 -0
- package/dist/src/frontend/notemd.css +49 -0
- package/dist/src/frontend/notemd.html +7 -1
- package/dist/src/frontend/notemd.js +64 -0
- package/dist/src/frontend/path.html +107 -0
- package/dist/src/frontend/path_app.js +2108 -130
- package/dist/src/frontend/path_layout.mjs +143 -0
- package/dist/src/frontend/path_mermaid_utils.mjs +108 -0
- package/dist/src/frontend/path_modules_bridge.js +486 -0
- package/dist/src/frontend/path_state.mjs +118 -0
- package/dist/src/frontend/path_styles.css +146 -0
- package/dist/src/frontend/path_worker_bridge.mjs +85 -0
- package/dist/src/frontend/reader.js +393 -33
- package/dist/src/frontend/runtime_bridge.js +67 -54
- package/dist/src/frontend/runtime_bridge.mjs +279 -0
- package/dist/src/frontend/settings.js +130 -12
- package/dist/src/frontend/source_manager.js +190 -21
- package/dist/src/frontend/styles.css +2720 -72
- package/dist/src/frontend/workbench_state.mjs +101 -0
- package/dist/src/frontend/workspace_panes.js +10168 -0
- package/dist/src/frontend.locale.contract.test.js +62 -0
- package/dist/src/godot.sidecar.bootstrap.contract.test.js +244 -0
- package/dist/src/indexing/IndexLifecycle.js +195 -0
- package/dist/src/indexing/IndexLifecycle.test.js +49 -0
- package/dist/src/indexing/SegmentBuilder.js +64 -0
- package/dist/src/indexing/UnitBuilder.js +48 -0
- package/dist/src/indexing/types.js +2 -0
- package/dist/src/knowledge.api.contract.test.js +170 -0
- package/dist/src/learning/KnowledgeLearningPlatform.js +10386 -0
- package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +327 -0
- package/dist/src/learning/KnowledgeLearningPlatform.program-f.test.js +99 -0
- package/dist/src/learning/KnowledgeLearningPlatform.test.js +2971 -0
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +2974 -0
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +3928 -0
- package/dist/src/learning/answerReleaseReview.js +4319 -0
- package/dist/src/learning/answerReleaseReview.test.js +2888 -0
- package/dist/src/learning/api.js +2 -0
- package/dist/src/learning/conversationComposer.js +1480 -0
- package/dist/src/learning/conversationComposer.test.js +1817 -0
- package/dist/src/learning/domains/ConversationManager.js +53 -0
- package/dist/src/learning/domains/KnowledgeIngestor.js +238 -0
- package/dist/src/learning/domains/KnowledgeQuerier.js +187 -0
- package/dist/src/learning/domains/MasteryEngine.js +387 -0
- package/dist/src/learning/domains/MemoryPolicyManager.js +408 -0
- package/dist/src/learning/domains/QualityEvaluator.js +307 -0
- package/dist/src/learning/domains/TutorRouter.js +313 -0
- package/dist/src/learning/domains/index.js +33 -0
- package/dist/src/learning/domains/types.js +7 -0
- package/dist/src/learning/errors.js +29 -0
- package/dist/src/learning/evidenceContextAssembler.js +1176 -0
- package/dist/src/learning/evidenceContextAssembler.test.js +6332 -0
- package/dist/src/learning/graphContextAssembler.js +870 -0
- package/dist/src/learning/graphContextAssembler.test.js +1033 -0
- package/dist/src/learning/index.js +28 -0
- package/dist/src/learning/queryBackend.js +1898 -0
- package/dist/src/learning/queryBackend.test.js +955 -0
- package/dist/src/learning/ragContextPack.js +257 -0
- package/dist/src/learning/ragContextPack.test.js +160 -0
- package/dist/src/learning/ragPublicText.js +38 -0
- package/dist/src/learning/ragSufficiencyJudge.js +161 -0
- package/dist/src/learning/ragSufficiencyJudge.test.js +177 -0
- package/dist/src/learning/ragSufficiencyProviderJudge.js +227 -0
- package/dist/src/learning/ragSufficiencyProviderJudge.test.js +156 -0
- package/dist/src/learning/requestNormalization.js +198 -0
- package/dist/src/learning/runtimeCapability.js +4677 -0
- package/dist/src/learning/runtimeCapability.test.js +3635 -0
- package/dist/src/learning/store.js +1240 -0
- package/dist/src/learning/store.test.js +1126 -0
- package/dist/src/learning/tutorAdapter.js +2 -0
- package/dist/src/learning/types.js +2 -0
- package/dist/src/learning/vectorAccelerationAdapter.js +942 -0
- package/dist/src/learning/vectorAccelerationAdapter.test.js +382 -0
- package/dist/src/lfs.asset.policy.contract.test.js +153 -0
- package/dist/src/license.policy.contract.test.js +66 -0
- package/dist/src/memory/MemoryGovernance.js +74 -0
- package/dist/src/memory/MemoryGovernance.test.js +46 -0
- package/dist/src/memory/types.js +2 -0
- package/dist/src/mermaid.frontend.guard.contract.test.js +77 -0
- package/dist/src/middleware/auth.js +17 -0
- package/dist/src/middleware/body-parser.js +45 -0
- package/dist/src/middleware/cors.js +44 -0
- package/dist/src/middleware/index.js +21 -0
- package/dist/src/middleware/request-trace.js +96 -0
- package/dist/src/notemd/AppConfigToml.js +6 -4
- package/dist/src/notemd/MermaidProcessor.js +400 -50
- package/dist/src/notemd/NotemdService.js +498 -13
- package/dist/src/notemd/PromptManager.js +15 -0
- package/dist/src/notemd/cli/commands.js +357 -0
- package/dist/src/notemd/cli/dispatcher.js +225 -0
- package/dist/src/notemd/cli/index.js +169 -0
- package/dist/src/notemd/cli/parser.js +68 -0
- package/dist/src/notemd/cli/types.js +2 -0
- package/dist/src/notemd/constants.js +43 -0
- package/dist/src/notemd/diagram/diagramGenerationService.js +78 -0
- package/dist/src/notemd/diagram/diagramSpec.js +79 -0
- package/dist/src/notemd/diagram/diagramSpecResponseParser.js +131 -0
- package/dist/src/notemd/diagram/intent.js +95 -0
- package/dist/src/notemd/diagram/planner.js +71 -0
- package/dist/src/notemd/diagram/prompts/diagramSpecPrompt.js +42 -0
- package/dist/src/notemd/diagram/types.js +18 -0
- package/dist/src/notemd/index.js +26 -0
- package/dist/src/notemd/operations/capabilityManifest.js +23 -0
- package/dist/src/notemd/operations/cliContracts.js +17 -0
- package/dist/src/notemd/operations/configProfileCommands.js +85 -0
- package/dist/src/notemd/operations/registry.contract.test.js +95 -0
- package/dist/src/notemd/operations/registry.js +991 -0
- package/dist/src/notemd/operations/types.js +2 -0
- package/dist/src/notemd/providerDiagnostics.js +220 -0
- package/dist/src/notemd/providerProfiles.js +42 -0
- package/dist/src/notemd/providerTemplates.js +231 -0
- package/dist/src/notemd/search/DuckDuckGoProvider.js +39 -0
- package/dist/src/notemd/search/SearchManager.js +13 -0
- package/dist/src/notemd/search/SearchProvider.js +2 -0
- package/dist/src/notemd/search/TavilyProvider.js +44 -0
- package/dist/src/notemd.agent.manifest.test.js +85 -0
- package/dist/src/notemd.api.contract.test.js +14 -1
- package/dist/src/notemd.app_config_toml.test.js +2 -1
- package/dist/src/notemd.batch.workflow.test.js +117 -0
- package/dist/src/notemd.cli.e2e.test.js +136 -0
- package/dist/src/notemd.core.test.js +51 -0
- package/dist/src/notemd.diagram.pipeline.test.js +233 -0
- package/dist/src/notemd.providerTemplates.test.js +34 -0
- package/dist/src/notemd.server.integration.test.js +143 -35
- package/dist/src/notemd.workflow.pipeline.test.js +162 -0
- package/dist/src/pathbridge.handshake.contract.test.js +16 -2
- package/dist/src/pathmode.background.contract.test.js +69 -0
- package/dist/src/pathmode.settings.api.contract.test.js +9 -0
- package/dist/src/pkg.sidecar.contract.test.js +9 -3
- package/dist/src/platform/ExportProfile.js +58 -0
- package/dist/src/platform/PlatformCapabilities.js +45 -0
- package/dist/src/platform/PlatformCapabilities.test.js +30 -0
- package/dist/src/platform/RenderMaterializer.js +33 -0
- package/dist/src/platform/RenderMaterializer.test.js +32 -0
- package/dist/src/query_backend.external_http.integration.test.js +410 -0
- package/dist/src/reader_renderer.js +404 -3
- package/dist/src/reader_renderer.test.js +87 -0
- package/dist/src/release.godot.mirror.contract.test.js +73 -0
- package/dist/src/resources/ResourceRegistry.js +223 -0
- package/dist/src/resources/ResourceRegistry.test.js +61 -0
- package/dist/src/resources/types.js +2 -0
- package/dist/src/routes/agentWorkspaceDiagnostics.js +173 -0
- package/dist/src/routes/data.js +267 -0
- package/dist/src/routes/diagnostics.js +51 -0
- package/dist/src/routes/index.js +23 -0
- package/dist/src/routes/knowledge.js +968 -0
- package/dist/src/routes/markdown.js +287 -0
- package/dist/src/routes/notemd.js +565 -0
- package/dist/src/routes/registry.contract.test.js +130 -0
- package/dist/src/routes/render.js +285 -0
- package/dist/src/routes/runtimeRunbookRouteOps.js +149 -0
- package/dist/src/routes/runtimeRunbookRouteOps.test.js +194 -0
- package/dist/src/routes/settings.js +6 -0
- package/dist/src/routes/staticFiles.js +94 -0
- package/dist/src/routes/types.js +2 -0
- package/dist/src/runtime.transport.adapter.contract.test.js +81 -0
- package/dist/src/server.js +11090 -1549
- package/dist/src/server.migration.test.js +193 -21
- package/dist/src/server.port.fallback.contract.test.js +63 -0
- package/dist/src/session/SessionStateStore.js +81 -0
- package/dist/src/session/SessionStateStore.test.js +58 -0
- package/dist/src/session/types.js +2 -0
- package/dist/src/settings.runtime.contract.test.js +50 -0
- package/dist/src/shared/types.contract.test.js +107 -0
- package/dist/src/shared/types.js +22 -0
- package/dist/src/sidecar.replacement.boundary.contract.test.js +128 -0
- package/dist/src/sidecar.supply.readiness.contract.test.js +144 -0
- package/dist/src/source_manager.loadflow.test.js +46 -0
- package/dist/src/startup.layout.snapshot.contract.test.js +57 -0
- package/dist/src/tauri.frontend.build.contract.test.js +60 -0
- package/dist/src/tauri.sidecar.cleanup.contract.test.js +21 -0
- package/dist/src/utils/RuntimePaths.js +4 -13
- package/dist/src/utils/platform.js +153 -0
- package/dist/src/workflows/WorkflowArtifactStore.js +96 -0
- package/dist/src/workflows/WorkflowArtifactStore.test.js +80 -0
- package/dist/src/workflows/types.js +2 -0
- package/dist/src/workspace/WorkspaceRegistry.js +122 -0
- package/dist/src/workspace/WorkspaceRegistry.test.js +29 -0
- package/dist/src/workspace/types.js +2 -0
- package/package.json +53 -10
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Notemd CLI Entry Point
|
|
5
|
+
*
|
|
6
|
+
* Usage: npx notemd <command> [options]
|
|
7
|
+
* or: node src/notemd/cli/index.ts <command> [options]
|
|
8
|
+
*
|
|
9
|
+
* Examples:
|
|
10
|
+
* notemd process-file --path=notes/my_note.md
|
|
11
|
+
* notemd search --query="machine learning"
|
|
12
|
+
* notemd generate-diagram --path=notes/arch.md --intent=mermaid
|
|
13
|
+
* notemd translate --path=notes/doc.md --language=zh
|
|
14
|
+
* notemd manifest
|
|
15
|
+
* notemd help
|
|
16
|
+
*/
|
|
17
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
20
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
21
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
22
|
+
}
|
|
23
|
+
Object.defineProperty(o, k2, desc);
|
|
24
|
+
}) : (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
o[k2] = m[k];
|
|
27
|
+
}));
|
|
28
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
+
}) : function(o, v) {
|
|
31
|
+
o["default"] = v;
|
|
32
|
+
});
|
|
33
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
34
|
+
var ownKeys = function(o) {
|
|
35
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
36
|
+
var ar = [];
|
|
37
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
38
|
+
return ar;
|
|
39
|
+
};
|
|
40
|
+
return ownKeys(o);
|
|
41
|
+
};
|
|
42
|
+
return function (mod) {
|
|
43
|
+
if (mod && mod.__esModule) return mod;
|
|
44
|
+
var result = {};
|
|
45
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
46
|
+
__setModuleDefault(result, mod);
|
|
47
|
+
return result;
|
|
48
|
+
};
|
|
49
|
+
})();
|
|
50
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
+
const fs = __importStar(require("fs"));
|
|
52
|
+
const path = __importStar(require("path"));
|
|
53
|
+
const commands_1 = require("./commands");
|
|
54
|
+
const NotemdService_1 = require("../NotemdService");
|
|
55
|
+
const dispatcher_1 = require("./dispatcher");
|
|
56
|
+
function createExecutionContext(workingDir) {
|
|
57
|
+
return {
|
|
58
|
+
workingDir,
|
|
59
|
+
getSetting: async (_key) => undefined,
|
|
60
|
+
callLlm: async (_prompt, _content) => { throw new Error('LLM not configured for CLI'); },
|
|
61
|
+
readFile: async (filePath) => {
|
|
62
|
+
const resolved = path.isAbsolute(filePath) ? filePath : path.resolve(workingDir, filePath);
|
|
63
|
+
return fs.promises.readFile(resolved, 'utf8');
|
|
64
|
+
},
|
|
65
|
+
writeFile: async (filePath, content) => {
|
|
66
|
+
const resolved = path.isAbsolute(filePath) ? filePath : path.resolve(workingDir, filePath);
|
|
67
|
+
await fs.promises.mkdir(path.dirname(resolved), { recursive: true });
|
|
68
|
+
await fs.promises.writeFile(resolved, content, 'utf8');
|
|
69
|
+
},
|
|
70
|
+
fileExists: async (filePath) => {
|
|
71
|
+
const resolved = path.isAbsolute(filePath) ? filePath : path.resolve(workingDir, filePath);
|
|
72
|
+
try {
|
|
73
|
+
await fs.promises.access(resolved);
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
mkdir: async (dirPath) => {
|
|
81
|
+
const resolved = path.isAbsolute(dirPath) ? dirPath : path.resolve(workingDir, dirPath);
|
|
82
|
+
await fs.promises.mkdir(resolved, { recursive: true });
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function printHelp() {
|
|
87
|
+
console.log('Notemd CLI - LLM-powered note enhancement toolkit\n');
|
|
88
|
+
console.log('Usage: npx notemd <command> [options]\n');
|
|
89
|
+
console.log('Commands:');
|
|
90
|
+
const commands = (0, commands_1.listCommands)();
|
|
91
|
+
const maxLen = Math.max(...commands.map(c => c.name.length));
|
|
92
|
+
for (const cmd of commands) {
|
|
93
|
+
const pads = ' '.repeat(maxLen - cmd.name.length + 2);
|
|
94
|
+
console.log(` ${cmd.name}${pads}${cmd.description}`);
|
|
95
|
+
}
|
|
96
|
+
console.log('\nRun "npx notemd <command> --help" for detailed options.');
|
|
97
|
+
}
|
|
98
|
+
async function main() {
|
|
99
|
+
const cliArgs = process.argv.slice(2);
|
|
100
|
+
if (cliArgs.length === 0 || cliArgs[0] === 'help' || cliArgs[0] === '--help' || cliArgs[0] === '-h') {
|
|
101
|
+
printHelp();
|
|
102
|
+
process.exit(0);
|
|
103
|
+
}
|
|
104
|
+
// Check for help on a specific command
|
|
105
|
+
if (cliArgs.includes('--help') || cliArgs.includes('-h')) {
|
|
106
|
+
const cmdName = cliArgs[0];
|
|
107
|
+
const cmd = (0, commands_1.findCommand)(cmdName);
|
|
108
|
+
if (cmd) {
|
|
109
|
+
console.log(`${cmd.name} — ${cmd.description}\n`);
|
|
110
|
+
console.log(`Operation: ${cmd.operationId}`);
|
|
111
|
+
console.log(`Automation: ${cmd.automationLevel} | Context: ${cmd.requiredContext} | Side Effects: ${cmd.sideEffectClass}\n`);
|
|
112
|
+
if (cmd.params.length > 0) {
|
|
113
|
+
console.log('Parameters:');
|
|
114
|
+
for (const p of cmd.params) {
|
|
115
|
+
const req = p.required ? ' (required)' : '';
|
|
116
|
+
const def = p.defaultValue ? ` [default: ${p.defaultValue}]` : '';
|
|
117
|
+
console.log(` --${p.name}${req}${def}`);
|
|
118
|
+
console.log(` ${p.description}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (cmd.flags.length > 0) {
|
|
122
|
+
console.log('Flags:');
|
|
123
|
+
for (const f of cmd.flags) {
|
|
124
|
+
console.log(` --${f.name}`);
|
|
125
|
+
console.log(` ${f.description}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
console.log(`Unknown command: ${cmdName}`);
|
|
131
|
+
}
|
|
132
|
+
process.exit(0);
|
|
133
|
+
}
|
|
134
|
+
const workingDir = process.cwd();
|
|
135
|
+
const ctx = createExecutionContext(workingDir);
|
|
136
|
+
const service = new NotemdService_1.NotemdService();
|
|
137
|
+
// Load settings from notemd.toml if it exists, else use defaults
|
|
138
|
+
const settings = { providers: [], activeProvider: 'OpenAI', searchProvider: 'duckduckgo' };
|
|
139
|
+
const configPath = path.resolve(workingDir, 'notemd.toml');
|
|
140
|
+
try {
|
|
141
|
+
await fs.promises.access(configPath);
|
|
142
|
+
const configContent = await fs.promises.readFile(configPath, 'utf8');
|
|
143
|
+
// Parse TOML settings (basic: just use JSON format for CLI)
|
|
144
|
+
const config = JSON.parse(configContent);
|
|
145
|
+
Object.assign(settings, config);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// Use defaults
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
const result = await (0, dispatcher_1.dispatchCommand)(cliArgs, ctx, service, settings);
|
|
152
|
+
if (result.success) {
|
|
153
|
+
console.log(JSON.stringify(result.data, null, 2));
|
|
154
|
+
process.exit(0);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
console.error(`Error: ${result.error}`);
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
console.error('Fatal error:', error instanceof Error ? error.message : String(error));
|
|
163
|
+
process.exit(2);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
main().catch((error) => {
|
|
167
|
+
console.error('Unhandled error:', error);
|
|
168
|
+
process.exit(2);
|
|
169
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseCliArgs = parseCliArgs;
|
|
4
|
+
exports.resolveParam = resolveParam;
|
|
5
|
+
exports.resolveBool = resolveBool;
|
|
6
|
+
function parseCliArgs(args) {
|
|
7
|
+
const params = {};
|
|
8
|
+
const flags = new Set();
|
|
9
|
+
const positional = [];
|
|
10
|
+
let command = '';
|
|
11
|
+
for (let i = 0; i < args.length; i++) {
|
|
12
|
+
const arg = args[i];
|
|
13
|
+
if (arg.startsWith('--')) {
|
|
14
|
+
const eqIdx = arg.indexOf('=');
|
|
15
|
+
if (eqIdx !== -1) {
|
|
16
|
+
const key = arg.slice(2, eqIdx);
|
|
17
|
+
const value = arg.slice(eqIdx + 1);
|
|
18
|
+
params[key] = value;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
const key = arg.slice(2);
|
|
22
|
+
// Check if next arg is a value
|
|
23
|
+
if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
|
|
24
|
+
params[key] = args[i + 1];
|
|
25
|
+
i++;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
flags.add(key);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else if (arg.startsWith('-')) {
|
|
33
|
+
const key = arg.slice(1);
|
|
34
|
+
if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
|
|
35
|
+
params[key] = args[i + 1];
|
|
36
|
+
i++;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
flags.add(key);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else if (!command) {
|
|
43
|
+
command = arg;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
positional.push(arg);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return { command, params, flags, positional };
|
|
50
|
+
}
|
|
51
|
+
function resolveParam(params, keys, fallback) {
|
|
52
|
+
for (const key of keys) {
|
|
53
|
+
if (params[key] !== undefined)
|
|
54
|
+
return params[key];
|
|
55
|
+
}
|
|
56
|
+
return fallback;
|
|
57
|
+
}
|
|
58
|
+
function resolveBool(params, flags, keys) {
|
|
59
|
+
for (const key of keys) {
|
|
60
|
+
if (flags.has(key))
|
|
61
|
+
return true;
|
|
62
|
+
if (params[key] !== undefined) {
|
|
63
|
+
const v = params[key].toLowerCase();
|
|
64
|
+
return v === 'true' || v === '1' || v === 'yes';
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
@@ -77,4 +77,47 @@ exports.DEFAULT_SETTINGS = {
|
|
|
77
77
|
disableAutoTranslation: false,
|
|
78
78
|
enableGlobalCustomPrompts: false,
|
|
79
79
|
customPrompts: {},
|
|
80
|
+
// ── Search (obsidian-notemd v1.8.4) ──
|
|
81
|
+
tavilyApiKey: '',
|
|
82
|
+
searchProvider: 'tavily',
|
|
83
|
+
ddgMaxResults: 5,
|
|
84
|
+
ddgFetchTimeout: 10000,
|
|
85
|
+
maxResearchContentTokens: 32000,
|
|
86
|
+
tavilyMaxResults: 5,
|
|
87
|
+
tavilySearchDepth: 'basic',
|
|
88
|
+
// ── Diagram pipeline (obsidian-notemd v1.8.4) ──
|
|
89
|
+
enableExperimentalDiagramPipeline: false,
|
|
90
|
+
experimentalDiagramCompatibilityMode: 'best-fit',
|
|
91
|
+
preferredDiagramIntent: undefined,
|
|
92
|
+
useCustomSummarizeToMermaidSuffix: false,
|
|
93
|
+
summarizeToMermaidCustomSuffix: '',
|
|
94
|
+
useCustomSummarizeToMermaidSavePath: false,
|
|
95
|
+
summarizeToMermaidSavePath: '',
|
|
96
|
+
translateSummarizeToMermaidOutput: false,
|
|
97
|
+
// ── Mermaid error detection (obsidian-notemd v1.8.4) ──
|
|
98
|
+
enableMermaidErrorDetection: false,
|
|
99
|
+
moveMermaidErrorFiles: false,
|
|
100
|
+
mermaidErrorFolderPath: '',
|
|
101
|
+
// ── Extract original text (obsidian-notemd v1.8.4) ──
|
|
102
|
+
extractOriginalTextMergedMode: false,
|
|
103
|
+
extractOriginalTextUseCustomOutput: false,
|
|
104
|
+
extractOriginalTextCustomPath: '',
|
|
105
|
+
extractOriginalTextCustomSuffix: '',
|
|
106
|
+
translateExtractOriginalTextOutput: false,
|
|
107
|
+
// ── Duplicate detection (obsidian-notemd v1.8.4) ──
|
|
108
|
+
duplicateCheckScopeMode: 'vault',
|
|
109
|
+
duplicateCheckScopePaths: '',
|
|
110
|
+
// ── Add links post-processing (obsidian-notemd v1.8.4) ──
|
|
111
|
+
removeCodeFencesOnAddLinks: false,
|
|
112
|
+
// ── Workflow (obsidian-notemd v1.8.4) ──
|
|
113
|
+
extractQuestions: '',
|
|
114
|
+
customWorkflowErrorStrategy: 'stop_on_error',
|
|
115
|
+
customWorkflowButtonsDsl: '',
|
|
116
|
+
// ── Developer diagnostics (obsidian-notemd v1.8.4) ──
|
|
117
|
+
enableDeveloperMode: false,
|
|
118
|
+
developerDiagnosticCallMode: 'single',
|
|
119
|
+
developerDiagnosticStabilityRuns: 5,
|
|
120
|
+
developerDiagnosticTimeoutMs: 10000,
|
|
121
|
+
enableApiErrorDebugMode: false,
|
|
122
|
+
enableStableApiCall: false,
|
|
80
123
|
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateDiagramArtifact = generateDiagramArtifact;
|
|
4
|
+
const planner_1 = require("./planner");
|
|
5
|
+
const diagramSpecPrompt_1 = require("./prompts/diagramSpecPrompt");
|
|
6
|
+
const diagramSpec_1 = require("./diagramSpec");
|
|
7
|
+
const diagramSpecResponseParser_1 = require("./diagramSpecResponseParser");
|
|
8
|
+
function mergeSpecDefaults(spec, plan) {
|
|
9
|
+
const resolvedIntent = plan.legacyCompatibilityMode ? plan.intent : spec.intent;
|
|
10
|
+
const normalizedLayoutHints = { ...(spec.layoutHints ?? {}) };
|
|
11
|
+
if (resolvedIntent !== 'dataChart')
|
|
12
|
+
delete normalizedLayoutHints.chartType;
|
|
13
|
+
else if (normalizedLayoutHints.chartType === undefined && plan.preferredChartType) {
|
|
14
|
+
normalizedLayoutHints.chartType = plan.preferredChartType;
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
...spec,
|
|
18
|
+
intent: resolvedIntent,
|
|
19
|
+
title: spec.title?.trim() || 'Generated Diagram',
|
|
20
|
+
nodes: (spec.nodes ?? []).map(node => ({ ...node, label: node.label?.trim() || node.id || 'Untitled' })),
|
|
21
|
+
edges: (spec.edges ?? []).map(edge => ({ ...edge, label: edge.label?.trim() || undefined })),
|
|
22
|
+
sections: spec.sections ?? [],
|
|
23
|
+
callouts: spec.callouts ?? [],
|
|
24
|
+
dataSeries: spec.dataSeries ?? [],
|
|
25
|
+
layoutHints: Object.keys(normalizedLayoutHints).length > 0 ? normalizedLayoutHints : undefined,
|
|
26
|
+
evidenceRefs: spec.evidenceRefs ?? []
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function specToMermaid(spec) {
|
|
30
|
+
const { intent, nodes, edges } = spec;
|
|
31
|
+
const nodeLines = nodes.map(n => ` ${n.id}[${n.label || n.id}]`);
|
|
32
|
+
const edgeLines = (edges ?? []).map(e => ` ${e.from} --> ${e.to}${e.label ? `: ${e.label}` : ''}`);
|
|
33
|
+
switch (intent) {
|
|
34
|
+
case 'mindmap': return `mindmap\n ${spec.title}\n${nodes.map(n => ` ${n.label || n.id}`).join('\n')}`;
|
|
35
|
+
case 'sequence': return `sequenceDiagram\n${nodes.map(n => ` participant ${n.id} as ${n.label}`).join('\n')}\n${(edges ?? []).map(e => ` ${e.from}->>${e.to}: ${e.label || ''}`).join('\n')}`;
|
|
36
|
+
case 'classDiagram': return `classDiagram\n${nodes.map(n => ` class ${n.id} {\n ${n.label}\n }`).join('\n')}`;
|
|
37
|
+
case 'erDiagram': return `erDiagram\n${nodes.map(n => ` ${n.id} {\n string label "${n.label}"\n }`).join('\n')}\n${(edges ?? []).map(e => ` ${e.from} ||--o{ ${e.to} : "${e.label || ''}"`).join('\n')}`;
|
|
38
|
+
case 'stateDiagram': return `stateDiagram-v2\n${nodes.map(n => ` state "${n.label}" as ${n.id}`).join('\n')}\n${(edges ?? []).map(e => ` ${e.from} --> ${e.to}: ${e.label || ''}`).join('\n')}`;
|
|
39
|
+
default: return `graph TD\n${nodeLines.join('\n')}\n${edgeLines.join('\n')}`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function generateDiagramArtifact(markdown, options) {
|
|
43
|
+
const plan = (0, planner_1.buildDiagramPlan)(markdown, {
|
|
44
|
+
compatibilityMode: options.compatibilityMode,
|
|
45
|
+
requestedIntent: options.requestedIntent
|
|
46
|
+
});
|
|
47
|
+
const prompt = (0, diagramSpecPrompt_1.buildDiagramSpecPrompt)({
|
|
48
|
+
preferredIntent: plan.intent,
|
|
49
|
+
requiredIntent: options.requestedIntent,
|
|
50
|
+
preferredChartType: plan.preferredChartType,
|
|
51
|
+
targetLanguage: options.targetLanguage
|
|
52
|
+
});
|
|
53
|
+
let rawResponse = await options.llmInvoker(prompt, markdown);
|
|
54
|
+
let parsedSpec = (0, diagramSpecResponseParser_1.parseDiagramSpecResponse)(rawResponse);
|
|
55
|
+
let spec = mergeSpecDefaults(parsedSpec, plan);
|
|
56
|
+
(0, diagramSpec_1.assertValidDiagramSpec)(spec);
|
|
57
|
+
// Retry if intent mismatch
|
|
58
|
+
if (options.requestedIntent && spec.intent !== options.requestedIntent) {
|
|
59
|
+
const retryPrompt = (0, diagramSpecPrompt_1.buildDiagramSpecPrompt)({
|
|
60
|
+
preferredIntent: plan.intent,
|
|
61
|
+
requiredIntent: options.requestedIntent,
|
|
62
|
+
preferredChartType: plan.preferredChartType,
|
|
63
|
+
targetLanguage: options.targetLanguage
|
|
64
|
+
}) + `\n\nCRITICAL: Your previous response used intent "${spec.intent}" but the required intent is "${options.requestedIntent}". Regenerate with the correct intent.`;
|
|
65
|
+
rawResponse = await options.llmInvoker(retryPrompt, markdown);
|
|
66
|
+
parsedSpec = (0, diagramSpecResponseParser_1.parseDiagramSpecResponse)(rawResponse);
|
|
67
|
+
spec = mergeSpecDefaults(parsedSpec, plan);
|
|
68
|
+
(0, diagramSpec_1.assertValidDiagramSpec)(spec);
|
|
69
|
+
}
|
|
70
|
+
const mermaidContent = specToMermaid(spec);
|
|
71
|
+
return {
|
|
72
|
+
plan,
|
|
73
|
+
spec,
|
|
74
|
+
mermaidContent,
|
|
75
|
+
artifactTarget: plan.renderTarget,
|
|
76
|
+
renderError: undefined
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateDiagramSpec = validateDiagramSpec;
|
|
4
|
+
exports.assertValidDiagramSpec = assertValidDiagramSpec;
|
|
5
|
+
const types_1 = require("./types");
|
|
6
|
+
const types_2 = require("../types");
|
|
7
|
+
function collectNodeIds(nodes, ids, errors) {
|
|
8
|
+
nodes.forEach(node => {
|
|
9
|
+
const id = node.id?.trim();
|
|
10
|
+
if (!id) {
|
|
11
|
+
errors.push('Diagram node is missing an id.');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (ids.has(id)) {
|
|
15
|
+
errors.push(`Diagram node id "${id}" is duplicated.`);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
ids.add(id);
|
|
19
|
+
}
|
|
20
|
+
if (!node.label?.trim()) {
|
|
21
|
+
errors.push(`Diagram node "${id}" is missing a label.`);
|
|
22
|
+
}
|
|
23
|
+
if (node.children?.length) {
|
|
24
|
+
collectNodeIds(node.children, ids, errors);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function validateDataSeries(dataSeries, errors) {
|
|
29
|
+
if (!dataSeries || dataSeries.length === 0) {
|
|
30
|
+
errors.push('Diagram intent "dataChart" requires at least one data series.');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
dataSeries.forEach(series => {
|
|
34
|
+
if (!series.id?.trim())
|
|
35
|
+
errors.push('Chart data series is missing an id.');
|
|
36
|
+
if (!series.label?.trim())
|
|
37
|
+
errors.push(`Chart data series "${series.id || 'unknown'}" is missing a label.`);
|
|
38
|
+
if (!series.points?.length) {
|
|
39
|
+
errors.push(`Chart data series "${series.id || 'unknown'}" is missing points.`);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
series.points.forEach((point, index) => {
|
|
43
|
+
if (point.x === '' || point.x === null || point.x === undefined) {
|
|
44
|
+
errors.push(`Chart data series "${series.id || 'unknown'}" point ${index + 1} is missing x.`);
|
|
45
|
+
}
|
|
46
|
+
if (typeof point.y !== 'number' || Number.isNaN(point.y)) {
|
|
47
|
+
errors.push(`Chart data series "${series.id || 'unknown'}" point ${index + 1} is missing a numeric y.`);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function validateDiagramSpec(spec) {
|
|
53
|
+
const errors = [];
|
|
54
|
+
if (!(0, types_1.isSupportedDiagramIntent)(spec.intent)) {
|
|
55
|
+
errors.push(`Diagram spec uses unsupported intent "${String(spec.intent)}". Supported: ${types_1.SUPPORTED_DIAGRAM_INTENTS.join(', ')}.`);
|
|
56
|
+
}
|
|
57
|
+
if (!spec.title?.trim())
|
|
58
|
+
errors.push('Diagram spec title is required.');
|
|
59
|
+
const nodeIds = new Set();
|
|
60
|
+
collectNodeIds(spec.nodes ?? [], nodeIds, errors);
|
|
61
|
+
if (spec.intent !== 'dataChart' && nodeIds.size === 0) {
|
|
62
|
+
errors.push(`Diagram intent "${spec.intent}" requires at least one node.`);
|
|
63
|
+
}
|
|
64
|
+
(spec.edges ?? []).forEach((edge, index) => {
|
|
65
|
+
if (!nodeIds.has(edge.from))
|
|
66
|
+
errors.push(`Diagram edge ${index + 1} references missing source node "${edge.from}".`);
|
|
67
|
+
if (!nodeIds.has(edge.to))
|
|
68
|
+
errors.push(`Diagram edge ${index + 1} references missing target node "${edge.to}".`);
|
|
69
|
+
});
|
|
70
|
+
if (spec.intent === 'dataChart')
|
|
71
|
+
validateDataSeries(spec.dataSeries, errors);
|
|
72
|
+
return { valid: errors.length === 0, errors };
|
|
73
|
+
}
|
|
74
|
+
function assertValidDiagramSpec(spec) {
|
|
75
|
+
const result = validateDiagramSpec(spec);
|
|
76
|
+
if (!result.valid)
|
|
77
|
+
throw new types_2.ValidationError(result.errors.join(' '), 'INVALID_INPUT');
|
|
78
|
+
return spec;
|
|
79
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseDiagramSpecResponse = parseDiagramSpecResponse;
|
|
4
|
+
function stripCodeFence(raw) {
|
|
5
|
+
const trimmed = raw.trim();
|
|
6
|
+
const fencedMatch = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
|
|
7
|
+
return fencedMatch ? fencedMatch[1].trim() : trimmed;
|
|
8
|
+
}
|
|
9
|
+
function extractJsonObject(raw) {
|
|
10
|
+
const stripped = stripCodeFence(raw);
|
|
11
|
+
const start = stripped.indexOf('{');
|
|
12
|
+
const end = stripped.lastIndexOf('}');
|
|
13
|
+
if (start === -1 || end === -1 || end < start) {
|
|
14
|
+
throw new Error('Unable to parse DiagramSpec: no JSON object found in LLM response.');
|
|
15
|
+
}
|
|
16
|
+
return stripped.slice(start, end + 1);
|
|
17
|
+
}
|
|
18
|
+
function readTrimmedString(value) {
|
|
19
|
+
if (typeof value !== 'string')
|
|
20
|
+
return undefined;
|
|
21
|
+
const trimmed = value.trim();
|
|
22
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
23
|
+
}
|
|
24
|
+
function readNumericValue(value) {
|
|
25
|
+
if (typeof value === 'number' && !Number.isNaN(value))
|
|
26
|
+
return value;
|
|
27
|
+
if (typeof value !== 'string')
|
|
28
|
+
return undefined;
|
|
29
|
+
const trimmed = value.trim();
|
|
30
|
+
if (!/^-?\d[\d,]*(\.\d+)?%?$/.test(trimmed))
|
|
31
|
+
return undefined;
|
|
32
|
+
const normalized = trimmed.replace(/,/g, '').replace(/%$/, '');
|
|
33
|
+
const parsed = Number(normalized);
|
|
34
|
+
return Number.isNaN(parsed) ? undefined : parsed;
|
|
35
|
+
}
|
|
36
|
+
function slugify(value) {
|
|
37
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
|
38
|
+
}
|
|
39
|
+
function normalizePoint(point, fallbackSeriesLabel) {
|
|
40
|
+
if (Array.isArray(point) && point.length >= 2) {
|
|
41
|
+
const x = point[0];
|
|
42
|
+
const y = readNumericValue(point[1]);
|
|
43
|
+
if ((typeof x === 'string' || typeof x === 'number') && y !== undefined) {
|
|
44
|
+
return { x: typeof x === 'string' ? x.trim() : x, y, series: fallbackSeriesLabel };
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
if (!point || typeof point !== 'object')
|
|
49
|
+
return null;
|
|
50
|
+
const pr = point;
|
|
51
|
+
const explicitX = pr.x;
|
|
52
|
+
const fallbackX = pr.label ?? pr.name ?? pr.category ?? pr.item ?? pr.date ?? pr.key ?? pr.id;
|
|
53
|
+
const xc = explicitX ?? fallbackX;
|
|
54
|
+
const x = typeof xc === 'number' ? xc : readTrimmedString(xc);
|
|
55
|
+
let y = readNumericValue(pr.y);
|
|
56
|
+
if (y === undefined)
|
|
57
|
+
y = readNumericValue(pr.value ?? pr.amount ?? pr.count ?? pr.total ?? pr.metric);
|
|
58
|
+
if ((x === undefined || x === '') && y === undefined) {
|
|
59
|
+
const entries = Object.entries(pr);
|
|
60
|
+
if (entries.length === 1) {
|
|
61
|
+
const [key, value] = entries[0];
|
|
62
|
+
const pv = readNumericValue(value);
|
|
63
|
+
if (pv !== undefined)
|
|
64
|
+
return { x: key, y: pv, series: fallbackSeriesLabel };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if ((typeof x !== 'string' && typeof x !== 'number') || y === undefined)
|
|
68
|
+
return null;
|
|
69
|
+
return { x, y, series: readTrimmedString(pr.series) ?? fallbackSeriesLabel };
|
|
70
|
+
}
|
|
71
|
+
function normalizeSeriesEntries(rawDataSeries) {
|
|
72
|
+
if (Array.isArray(rawDataSeries))
|
|
73
|
+
return rawDataSeries;
|
|
74
|
+
if (!rawDataSeries || typeof rawDataSeries !== 'object')
|
|
75
|
+
return [];
|
|
76
|
+
return Object.entries(rawDataSeries).map(([key, value]) => {
|
|
77
|
+
if (Array.isArray(value))
|
|
78
|
+
return { id: key, label: key, points: value };
|
|
79
|
+
if (value && typeof value === 'object') {
|
|
80
|
+
return { ...value, id: value.id ?? key, label: value.label ?? value.name ?? key };
|
|
81
|
+
}
|
|
82
|
+
return { id: key, label: key, points: [] };
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function normalizeDataSeries(rawDataSeries, title) {
|
|
86
|
+
const seriesEntries = normalizeSeriesEntries(rawDataSeries);
|
|
87
|
+
return seriesEntries.map((series, index) => {
|
|
88
|
+
const labelFallback = title.trim().length > 0
|
|
89
|
+
? (seriesEntries.length === 1 ? title.trim() : `${title.trim()} ${index + 1}`)
|
|
90
|
+
: `Series ${index + 1}`;
|
|
91
|
+
const label = readTrimmedString(series?.label) ?? readTrimmedString(series?.name) ?? readTrimmedString(series?.title) ?? readTrimmedString(series?.series) ?? labelFallback;
|
|
92
|
+
const slugId = slugify(label);
|
|
93
|
+
const id = readTrimmedString(series?.id) ?? readTrimmedString(series?.key) ?? (slugId || `series-${index + 1}`);
|
|
94
|
+
const rawPoints = Array.isArray(series?.points) ? series.points : Array.isArray(series?.values) ? series.values : Array.isArray(series?.data) ? series.data : Array.isArray(series?.items) ? series.items : [];
|
|
95
|
+
const points = rawPoints.map((p) => normalizePoint(p, label)).filter((p) => p !== null);
|
|
96
|
+
return { id, label, points };
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
function normalizeSpec(candidate) {
|
|
100
|
+
const payload = candidate?.diagramSpec ?? candidate;
|
|
101
|
+
const title = typeof payload.title === 'string' ? payload.title : '';
|
|
102
|
+
return {
|
|
103
|
+
intent: payload.intent,
|
|
104
|
+
title,
|
|
105
|
+
summary: typeof payload.summary === 'string' ? payload.summary : undefined,
|
|
106
|
+
nodes: Array.isArray(payload.nodes) ? payload.nodes : [],
|
|
107
|
+
edges: Array.isArray(payload.edges) ? payload.edges.map((e) => ({
|
|
108
|
+
from: e.from ?? e.source ?? e.sourceId ?? e.start,
|
|
109
|
+
to: e.to ?? e.target ?? e.targetId ?? e.end,
|
|
110
|
+
label: e.label,
|
|
111
|
+
relation: e.relation,
|
|
112
|
+
})) : [],
|
|
113
|
+
sections: Array.isArray(payload.sections) ? payload.sections : [],
|
|
114
|
+
callouts: Array.isArray(payload.callouts) ? payload.callouts : [],
|
|
115
|
+
dataSeries: normalizeDataSeries(payload.dataSeries, title),
|
|
116
|
+
layoutHints: payload.layoutHints && typeof payload.layoutHints === 'object' ? payload.layoutHints : undefined,
|
|
117
|
+
sourceLanguage: typeof payload.sourceLanguage === 'string' ? payload.sourceLanguage : undefined,
|
|
118
|
+
outputLanguage: typeof payload.outputLanguage === 'string' ? payload.outputLanguage : undefined,
|
|
119
|
+
evidenceRefs: Array.isArray(payload.evidenceRefs) ? payload.evidenceRefs : []
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function parseDiagramSpecResponse(raw) {
|
|
123
|
+
try {
|
|
124
|
+
const jsonObject = extractJsonObject(raw);
|
|
125
|
+
return normalizeSpec(JSON.parse(jsonObject));
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
129
|
+
throw new Error(`Unable to parse DiagramSpec response: ${message}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.inferDiagramIntent = inferDiagramIntent;
|
|
4
|
+
function countMatches(content, patterns) {
|
|
5
|
+
return patterns.reduce((count, pattern) => count + (content.match(pattern)?.length ?? 0), 0);
|
|
6
|
+
}
|
|
7
|
+
function scoreResult(intent, score, reasons) {
|
|
8
|
+
return { intent, confidence: Math.min(0.99, Math.max(0.2, score)), reasons };
|
|
9
|
+
}
|
|
10
|
+
function inferDiagramIntent(markdown) {
|
|
11
|
+
const normalized = markdown.toLowerCase();
|
|
12
|
+
const trimmed = normalized.trim();
|
|
13
|
+
if (!trimmed) {
|
|
14
|
+
return scoreResult('mindmap', 0.2, ['empty content defaults to hierarchical summary']);
|
|
15
|
+
}
|
|
16
|
+
const chartReasons = [];
|
|
17
|
+
const hasMarkdownTable = /\|.+\|/.test(normalized) && /\|\s*-+\s*\|/.test(normalized);
|
|
18
|
+
const numericCells = (normalized.match(/\|\s*\d+(?:\.\d+)?\s*\|/g) ?? []).length;
|
|
19
|
+
const percentValues = (normalized.match(/\b\d+(?:\.\d+)?%/g) ?? []).length;
|
|
20
|
+
const numericTokens = (normalized.match(/\b\d+(?:\.\d+)?\b/g) ?? []).length;
|
|
21
|
+
const chartKeywords = countMatches(normalized, [
|
|
22
|
+
/\bmetric(s)?\b/g, /\btrend(s)?\b/g, /\bweekly\b/g, /\bmonthly\b/g,
|
|
23
|
+
/\bgrowth\b/g, /\bsignup(s)?\b/g, /\brevenue\b/g, /\bcount\b/g
|
|
24
|
+
]);
|
|
25
|
+
const shareKeywords = countMatches(normalized, [
|
|
26
|
+
/\bshare\b/g, /\bmix\b/g, /\bbreakdown\b/g, /\bdistribution\b/g,
|
|
27
|
+
/\bcomposition\b/g, /\bportion\b/g
|
|
28
|
+
]);
|
|
29
|
+
const comparisonKeywords = countMatches(normalized, [
|
|
30
|
+
/\bvs\.?\b/g, /\bversus\b/g, /\bcompare\b/g, /\bcomparison\b/g,
|
|
31
|
+
/\blatency\b/g, /\bthroughput\b/g, /\bcorrelation\b/g
|
|
32
|
+
]);
|
|
33
|
+
const rankingKeywords = countMatches(normalized, [
|
|
34
|
+
/\btop\b/g, /\brank(?:ed|ing)?\b/g, /\bissue(?:s)?\b/g,
|
|
35
|
+
/\bleaderboard\b/g, /\bhighest\b/g, /\blowest\b/g
|
|
36
|
+
]);
|
|
37
|
+
if (hasMarkdownTable)
|
|
38
|
+
chartReasons.push('markdown table detected');
|
|
39
|
+
if (numericCells >= 2)
|
|
40
|
+
chartReasons.push('numeric table values detected');
|
|
41
|
+
if (chartKeywords > 0)
|
|
42
|
+
chartReasons.push('metric-oriented keywords detected');
|
|
43
|
+
if (shareKeywords > 0)
|
|
44
|
+
chartReasons.push('part-to-whole keywords detected');
|
|
45
|
+
if (percentValues >= 2)
|
|
46
|
+
chartReasons.push('percentage values detected');
|
|
47
|
+
if (comparisonKeywords > 0)
|
|
48
|
+
chartReasons.push('comparison vocabulary detected');
|
|
49
|
+
if (rankingKeywords > 0 && numericTokens >= 4)
|
|
50
|
+
chartReasons.push('ranked numeric items detected');
|
|
51
|
+
if (chartReasons.length >= 2)
|
|
52
|
+
return scoreResult('dataChart', 0.88, chartReasons);
|
|
53
|
+
const sequenceKeywords = countMatches(normalized, [
|
|
54
|
+
/\brequest\b/g, /\bresponse\b/g, /\bsend(s|ing)?\b/g, /\breturn(s|ed|ing)?\b/g,
|
|
55
|
+
/\bclient\b/g, /\bserver\b/g, /\bgateway\b/g, /\bservice\b/g
|
|
56
|
+
]);
|
|
57
|
+
const sequenceReasons = [];
|
|
58
|
+
if (sequenceKeywords >= 4)
|
|
59
|
+
sequenceReasons.push('request-response vocabulary detected');
|
|
60
|
+
if (/->|=>/.test(normalized))
|
|
61
|
+
sequenceReasons.push('directional interaction markers detected');
|
|
62
|
+
if (sequenceReasons.length > 0)
|
|
63
|
+
return scoreResult('sequence', 0.82, sequenceReasons);
|
|
64
|
+
const erKeywords = countMatches(normalized, [
|
|
65
|
+
/\bprimary key\b/g, /\bforeign key\b/g, /\bentity\b/g, /\btable\b/g,
|
|
66
|
+
/\bcolumn\b/g, /\bschema\b/g
|
|
67
|
+
]);
|
|
68
|
+
if (erKeywords >= 2)
|
|
69
|
+
return scoreResult('erDiagram', 0.8, ['data-model vocabulary detected']);
|
|
70
|
+
const stateKeywords = countMatches(normalized, [
|
|
71
|
+
/\bstate\b/g, /\btransition\b/g, /\bpending\b/g, /\brunning\b/g,
|
|
72
|
+
/\bcompleted\b/g, /\bfailed\b/g
|
|
73
|
+
]);
|
|
74
|
+
if (stateKeywords >= 3)
|
|
75
|
+
return scoreResult('stateDiagram', 0.76, ['state-transition vocabulary detected']);
|
|
76
|
+
const canvasKeywords = countMatches(normalized, [
|
|
77
|
+
/\bconcept map\b/g, /\bknowledge graph\b/g, /\bspatial\b/g,
|
|
78
|
+
/\bcluster\b/g, /\bmap the relationships\b/g
|
|
79
|
+
]);
|
|
80
|
+
if (canvasKeywords >= 1)
|
|
81
|
+
return scoreResult('canvasMap', 0.72, ['spatial knowledge mapping vocabulary detected']);
|
|
82
|
+
const flowchartReasons = [];
|
|
83
|
+
const numberedSteps = (normalized.match(/^\s*\d+\./gm) ?? []).length;
|
|
84
|
+
if (numberedSteps >= 2)
|
|
85
|
+
flowchartReasons.push('numbered steps detected');
|
|
86
|
+
const flowKeywords = countMatches(normalized, [
|
|
87
|
+
/\bif\b/g, /\bthen\b/g, /\belse\b/g, /\bstep\b/g, /\bprocess\b/g,
|
|
88
|
+
/\bworkflow\b/g, /\bvalidate\b/g, /\bcontinue\b/g, /\bstop\b/g
|
|
89
|
+
]);
|
|
90
|
+
if (flowKeywords >= 2)
|
|
91
|
+
flowchartReasons.push('workflow/process vocabulary detected');
|
|
92
|
+
if (flowchartReasons.length > 0)
|
|
93
|
+
return scoreResult('flowchart', 0.74, flowchartReasons);
|
|
94
|
+
return scoreResult('mindmap', 0.55, ['defaulted to hierarchical summary structure']);
|
|
95
|
+
}
|