@hyperfixi/mcp-server 2.3.1 → 2.5.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/dist/index.js CHANGED
@@ -1,4 +1,8 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ feedbackTools,
4
+ handleFeedbackTool
5
+ } from "./chunk-P76KH42G.js";
2
6
 
3
7
  // src/index.ts
4
8
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -1164,7 +1168,32 @@ var cachedAnalyzer = null;
1164
1168
  function getSemanticAnalyzer() {
1165
1169
  if (!semanticPackage) return null;
1166
1170
  if (!cachedAnalyzer) {
1167
- cachedAnalyzer = semanticPackage.createSemanticAnalyzer();
1171
+ cachedAnalyzer = {
1172
+ analyze(code, language) {
1173
+ if (!semanticPackage.isLanguageRegistered(language)) {
1174
+ return {
1175
+ confidence: 0,
1176
+ errors: [`Language '${language}' is not supported for semantic parsing`]
1177
+ };
1178
+ }
1179
+ const result = semanticPackage.parseSemantic(code, language);
1180
+ const out = {
1181
+ confidence: result.confidence
1182
+ };
1183
+ if (result.tokensConsumed !== void 0) out.tokensConsumed = result.tokensConsumed;
1184
+ if (result.node) {
1185
+ out.command = { name: result.node.action, roles: result.node.roles };
1186
+ }
1187
+ if (result.error) out.errors = [result.error];
1188
+ return out;
1189
+ },
1190
+ supportsLanguage(language) {
1191
+ return semanticPackage.isLanguageRegistered(language);
1192
+ },
1193
+ supportedLanguages() {
1194
+ return semanticPackage.getRegisteredLanguages();
1195
+ }
1196
+ };
1168
1197
  }
1169
1198
  return cachedAnalyzer;
1170
1199
  }
@@ -1462,7 +1491,7 @@ function getValidCommandsForLanguage(language) {
1462
1491
  return englishCommands;
1463
1492
  }
1464
1493
  try {
1465
- const profile = semanticPackage.getProfile(language);
1494
+ const profile = semanticPackage.tryGetProfile(language);
1466
1495
  if (profile && profile.keywords) {
1467
1496
  const commands = [...englishCommands];
1468
1497
  for (const [, translation] of Object.entries(profile.keywords)) {
@@ -1486,7 +1515,7 @@ function getEventHandlerKeywords(language) {
1486
1515
  return variants;
1487
1516
  }
1488
1517
  try {
1489
- const profile = semanticPackage.getProfile(language);
1518
+ const profile = semanticPackage.tryGetProfile(language);
1490
1519
  if (profile && profile.keywords && profile.keywords["on"]) {
1491
1520
  const trans = profile.keywords["on"];
1492
1521
  if (trans.primary) {
@@ -1619,7 +1648,7 @@ function validateHyperscript(code, language) {
1619
1648
  const endVariants = ["end"];
1620
1649
  if (semanticPackage && language !== "en") {
1621
1650
  try {
1622
- const profile = semanticPackage.getProfile(language);
1651
+ const profile = semanticPackage.tryGetProfile(language);
1623
1652
  if (profile?.keywords?.["if"]?.primary) {
1624
1653
  ifVariants.push(profile.keywords["if"].primary);
1625
1654
  }
@@ -1709,7 +1738,7 @@ function validateHyperscript(code, language) {
1709
1738
  const toggleVariants = ["toggle"];
1710
1739
  if (semanticPackage && language !== "en") {
1711
1740
  try {
1712
- const profile = semanticPackage.getProfile(language);
1741
+ const profile = semanticPackage.tryGetProfile(language);
1713
1742
  if (profile?.keywords?.toggle?.primary) {
1714
1743
  toggleVariants.push(profile.keywords.toggle.primary);
1715
1744
  }
@@ -1902,7 +1931,7 @@ function translateSuggestion(suggestion, language) {
1902
1931
  return suggestion;
1903
1932
  }
1904
1933
  try {
1905
- const profile = semanticPackage.getProfile(language);
1934
+ const profile = semanticPackage.tryGetProfile(language);
1906
1935
  if (profile && profile.keywords && profile.keywords[suggestion.command]) {
1907
1936
  const trans = profile.keywords[suggestion.command];
1908
1937
  if (trans.primary) {
@@ -2457,7 +2486,7 @@ function explainInLanguage(code, sourceLanguage, targetLanguage, includeTranslat
2457
2486
  throw new Error("Semantic analyzer not available");
2458
2487
  }
2459
2488
  const parseResult = analyzer.analyze(code, sourceLanguage);
2460
- const profile = semanticPackage.getProfile(targetLanguage);
2489
+ const profile = semanticPackage.tryGetProfile(targetLanguage);
2461
2490
  const explanation = {
2462
2491
  code,
2463
2492
  sourceLanguage,
@@ -2698,7 +2727,28 @@ var cachedAnalyzer2 = null;
2698
2727
  function getSemanticAnalyzer2() {
2699
2728
  if (!semanticPackage2) return null;
2700
2729
  if (!cachedAnalyzer2) {
2701
- cachedAnalyzer2 = semanticPackage2.createSemanticAnalyzer();
2730
+ cachedAnalyzer2 = {
2731
+ analyze(code, language) {
2732
+ if (!semanticPackage2.isLanguageRegistered(language)) {
2733
+ return {
2734
+ confidence: 0,
2735
+ errors: [`Language '${language}' is not supported for semantic parsing`]
2736
+ };
2737
+ }
2738
+ const result = semanticPackage2.parseSemantic(code, language);
2739
+ const out = {
2740
+ confidence: result.confidence
2741
+ };
2742
+ if (result.node) {
2743
+ out.command = { name: result.node.action, roles: result.node.roles };
2744
+ }
2745
+ if (result.error) out.errors = [result.error];
2746
+ return out;
2747
+ },
2748
+ supportsLanguage(language) {
2749
+ return semanticPackage2.isLanguageRegistered(language);
2750
+ }
2751
+ };
2702
2752
  }
2703
2753
  return cachedAnalyzer2;
2704
2754
  }
@@ -2986,7 +3036,7 @@ function getValidCommandsForLanguage2(language) {
2986
3036
  return englishCommands;
2987
3037
  }
2988
3038
  try {
2989
- const profile = semanticPackage2.getProfile(language);
3039
+ const profile = semanticPackage2.tryGetProfile(language);
2990
3040
  if (profile && profile.keywords) {
2991
3041
  const commands = [...englishCommands];
2992
3042
  for (const [engCommand, translation] of Object.entries(profile.keywords)) {
@@ -3177,7 +3227,7 @@ function getKeywordTranslation(command, language) {
3177
3227
  return { label: command };
3178
3228
  }
3179
3229
  try {
3180
- const profile = semanticPackage2.getProfile(language);
3230
+ const profile = semanticPackage2.tryGetProfile(language);
3181
3231
  if (profile && profile.keywords && profile.keywords[command]) {
3182
3232
  const trans = profile.keywords[command];
3183
3233
  if (trans.primary) {
@@ -3193,7 +3243,7 @@ function getReferenceTranslation(ref, language) {
3193
3243
  return { label: ref };
3194
3244
  }
3195
3245
  try {
3196
- const profile = semanticPackage2.getProfile(language);
3246
+ const profile = semanticPackage2.tryGetProfile(language);
3197
3247
  if (profile && profile.references && profile.references[ref]) {
3198
3248
  return { label: profile.references[ref], englishLabel: ref };
3199
3249
  }
@@ -3378,7 +3428,7 @@ function normalizeToEnglish(word, language) {
3378
3428
  return wordLower;
3379
3429
  }
3380
3430
  try {
3381
- const profile = semanticPackage2.getProfile(language);
3431
+ const profile = semanticPackage2.tryGetProfile(language);
3382
3432
  if (profile && profile.keywords) {
3383
3433
  for (const [engKey, translation] of Object.entries(profile.keywords)) {
3384
3434
  const trans = translation;
@@ -3466,7 +3516,7 @@ function getKeywordVariants(engKeyword, language) {
3466
3516
  return variants;
3467
3517
  }
3468
3518
  try {
3469
- const profile = semanticPackage2.getProfile(language);
3519
+ const profile = semanticPackage2.tryGetProfile(language);
3470
3520
  if (profile && profile.keywords && profile.keywords[engKeyword]) {
3471
3521
  const trans = profile.keywords[engKeyword];
3472
3522
  if (trans.primary) {
@@ -4767,9 +4817,9 @@ function handleSearchLanguageElements(args) {
4767
4817
  }
4768
4818
  }
4769
4819
  }
4770
- if (searchTypes.includes("keyword") && semanticPackage3?.languageProfiles) {
4820
+ if (searchTypes.includes("keyword") && semanticPackage3?.KNOWN_PROFILES) {
4771
4821
  const seenKeywords = /* @__PURE__ */ new Set();
4772
- for (const [lang, profile] of Object.entries(semanticPackage3.languageProfiles)) {
4822
+ for (const [lang, profile] of Object.entries(semanticPackage3.KNOWN_PROFILES)) {
4773
4823
  if (!profile.keywords) continue;
4774
4824
  for (const [keyword, trans] of Object.entries(profile.keywords)) {
4775
4825
  const primary = (trans?.primary || "").toLowerCase();
@@ -5741,159 +5791,7 @@ async function generateServerRoutes(args) {
5741
5791
  }
5742
5792
 
5743
5793
  // src/tools/domain-registry-setup.ts
5744
- import { DomainRegistry } from "@lokascript/framework";
5745
- function createDomainRegistry() {
5746
- const registry2 = new DomainRegistry();
5747
- registry2.register({
5748
- name: "sql",
5749
- description: "natural language SQL",
5750
- languages: ["en", "es", "ja", "ar", "ko", "zh", "tr", "fr"],
5751
- inputLabel: "query",
5752
- inputDescription: 'SQL query in natural language (e.g., "select name from users")',
5753
- outputDescription: "a SQL query string",
5754
- getDSL: () => import("@lokascript/domain-sql").then((m) => m.createSQLDSL()),
5755
- getRenderer: () => import("@lokascript/domain-sql").then((m) => m.renderSQL),
5756
- scanConfig: {
5757
- attributes: ["data-sql", "_sql"],
5758
- scriptTypes: ["text/sql-dsl"],
5759
- defaultLanguage: "en"
5760
- }
5761
- });
5762
- registry2.register({
5763
- name: "bdd",
5764
- description: "BDD scenario",
5765
- languages: ["en", "es", "ja", "ar"],
5766
- inputLabel: "scenario",
5767
- inputDescription: 'BDD scenario text (e.g., "given #button is exists")',
5768
- outputDescription: "Playwright test code with Given/When/Then assertions",
5769
- getDSL: () => import("@lokascript/domain-bdd").then((m) => m.createBDDDSL()),
5770
- getRenderer: () => import("@lokascript/domain-bdd").then((m) => m.renderBDD),
5771
- scanConfig: {
5772
- attributes: ["data-bdd", "_bdd"],
5773
- scriptTypes: ["text/bdd"],
5774
- defaultLanguage: "en"
5775
- }
5776
- });
5777
- registry2.register({
5778
- name: "jsx",
5779
- description: "natural language JSX/React",
5780
- languages: ["en", "es", "ja", "ar", "ko", "zh", "tr", "fr"],
5781
- inputLabel: "code",
5782
- inputDescription: 'JSX description in natural language (e.g., "element div with className app")',
5783
- outputDescription: "JSX/React component markup",
5784
- getDSL: () => import("@lokascript/domain-jsx").then((m) => m.createJSXDSL()),
5785
- getRenderer: () => import("@lokascript/domain-jsx").then((m) => m.renderJSX),
5786
- scanConfig: {
5787
- attributes: ["data-jsx", "_jsx"],
5788
- scriptTypes: ["text/jsx-dsl"],
5789
- defaultLanguage: "en"
5790
- }
5791
- });
5792
- registry2.register({
5793
- name: "todo",
5794
- description: "natural language todo management",
5795
- languages: ["en", "es", "ja", "ar", "ko", "zh", "tr", "fr"],
5796
- inputLabel: "command",
5797
- inputDescription: 'Todo command in natural language (e.g., "add milk to groceries")',
5798
- outputDescription: "a structured todo operation object",
5799
- getDSL: () => import("@lokascript/domain-todo").then((m) => m.createTodoDSL()),
5800
- getRenderer: () => import("@lokascript/domain-todo").then((m) => m.renderTodo),
5801
- scanConfig: {
5802
- attributes: ["data-todo", "_todo"],
5803
- scriptTypes: ["text/todo"],
5804
- defaultLanguage: "en"
5805
- }
5806
- });
5807
- registry2.register({
5808
- name: "behaviorspec",
5809
- description: "interaction testing specification",
5810
- languages: ["en", "es", "ja", "ar", "ko", "zh", "tr", "fr"],
5811
- inputLabel: "scenario",
5812
- inputDescription: 'BehaviorSpec scenario text (e.g., "given page /home")',
5813
- outputDescription: "a Playwright interaction test with page assertions",
5814
- getDSL: () => import("@lokascript/domain-behaviorspec").then((m) => m.createBehaviorSpecDSL()),
5815
- getRenderer: () => import("@lokascript/domain-behaviorspec").then((m) => m.renderBehaviorSpec),
5816
- scanConfig: {
5817
- attributes: ["data-spec", "_spec"],
5818
- scriptTypes: ["text/behaviorspec"],
5819
- defaultLanguage: "en"
5820
- }
5821
- });
5822
- registry2.register({
5823
- name: "llm",
5824
- description: "natural language LLM prompts (ask, summarize, analyze, translate)",
5825
- languages: ["en", "es", "ja", "ar", "ko", "zh", "tr", "fr"],
5826
- inputLabel: "command",
5827
- inputDescription: 'LLM command in natural language (e.g., "ask claude to summarize #article as bullets")',
5828
- outputDescription: "an LLMPromptSpec JSON (action, messages, model preferences)",
5829
- getDSL: () => import("@lokascript/domain-llm").then((m) => m.createLLMDSL()),
5830
- getRenderer: () => import("@lokascript/domain-llm").then((m) => m.renderLLM),
5831
- scanConfig: {
5832
- attributes: ["data-llm", "_llm"],
5833
- scriptTypes: ["text/llm"],
5834
- defaultLanguage: "en"
5835
- }
5836
- });
5837
- registry2.register({
5838
- name: "flow",
5839
- description: "declarative reactive data flow pipelines (fetch, poll, stream, submit)",
5840
- languages: ["en", "es", "ja", "ar", "ko", "zh", "tr", "fr"],
5841
- inputLabel: "pipeline",
5842
- inputDescription: 'FlowScript pipeline (e.g., "fetch /api/users as json into #list")',
5843
- outputDescription: "reactive data flow JavaScript (fetch/poll/stream handlers)",
5844
- getDSL: () => import("@lokascript/domain-flow").then((m) => m.createFlowDSL()),
5845
- getRenderer: () => import("@lokascript/domain-flow").then((m) => m.renderFlow),
5846
- scanConfig: {
5847
- attributes: ["data-flow", "_flow"],
5848
- scriptTypes: ["text/flowscript"],
5849
- defaultLanguage: "en"
5850
- }
5851
- });
5852
- registry2.register({
5853
- name: "voice",
5854
- description: "voice/accessibility commands for speech-controlled web interaction",
5855
- languages: ["en", "es", "ja", "ar", "ko", "zh", "tr", "fr"],
5856
- inputLabel: "command",
5857
- inputDescription: 'Voice command in natural language (e.g., "click the submit button")',
5858
- outputDescription: "a DOM interaction command (click, scroll, type, navigate)",
5859
- getDSL: () => import("@lokascript/domain-voice").then((m) => m.createVoiceDSL()),
5860
- getRenderer: () => import("@lokascript/domain-voice").then((m) => m.renderVoice),
5861
- scanConfig: {
5862
- attributes: ["data-voice", "_voice"],
5863
- scriptTypes: ["text/voice"],
5864
- defaultLanguage: "en"
5865
- }
5866
- });
5867
- loadAllSchemas(registry2);
5868
- return registry2;
5869
- }
5870
- async function loadAllSchemas(registry2) {
5871
- const loaders = [
5872
- { domain: "sql", load: () => import("@lokascript/domain-sql").then((m) => [...m.allSchemas]) },
5873
- { domain: "bdd", load: () => import("@lokascript/domain-bdd").then((m) => [...m.allSchemas]) },
5874
- { domain: "jsx", load: () => import("@lokascript/domain-jsx").then((m) => [...m.allSchemas]) },
5875
- { domain: "todo", load: () => import("@lokascript/domain-todo").then((m) => [...m.allSchemas]) },
5876
- {
5877
- domain: "behaviorspec",
5878
- load: () => import("@lokascript/domain-behaviorspec").then((m) => [...m.allSchemas])
5879
- },
5880
- { domain: "llm", load: () => import("@lokascript/domain-llm").then((m) => [...m.allSchemas]) },
5881
- { domain: "flow", load: () => import("@lokascript/domain-flow").then((m) => [...m.allSchemas]) },
5882
- {
5883
- domain: "voice",
5884
- load: () => import("@lokascript/domain-voice").then((m) => [...m.allSchemas])
5885
- }
5886
- ];
5887
- await Promise.allSettled(
5888
- loaders.map(async ({ domain, load }) => {
5889
- try {
5890
- const schemas = await load();
5891
- registry2.setSchemas(domain, schemas);
5892
- } catch {
5893
- }
5894
- })
5895
- );
5896
- }
5794
+ import { createDomainRegistry } from "@lokascript/domain-config";
5897
5795
 
5898
5796
  // src/tools/bdd-extras.ts
5899
5797
  var bddScenarioParser = null;
@@ -6891,15 +6789,13 @@ async function handleExecuteLLM(args, server2, registry2) {
6891
6789
 
6892
6790
  // src/tools/dispatcher.ts
6893
6791
  import { CrossDomainDispatcher } from "@lokascript/framework";
6792
+ import { DOMAIN_PRIORITY } from "@lokascript/domain-config";
6894
6793
  var dispatcher = null;
6895
6794
  function getDispatcher(registry2) {
6896
6795
  if (!dispatcher) {
6897
6796
  dispatcher = new CrossDomainDispatcher(registry2, {
6898
6797
  minConfidence: 0.5,
6899
- // Domains with more specific schemas should win over generic catch-all domains
6900
- // when confidence scores are close. voice/flow have broad patterns that match
6901
- // inputs intended for sql/bdd/todo/jsx.
6902
- priority: ["sql", "bdd", "behaviorspec", "jsx", "todo", "llm", "flow", "voice"]
6798
+ priority: DOMAIN_PRIORITY
6903
6799
  });
6904
6800
  }
6905
6801
  return dispatcher;
@@ -8077,7 +7973,7 @@ function createInlineExtractor() {
8077
7973
  const fs = await import("fs");
8078
7974
  const path = await import("path");
8079
7975
  const crypto = await import("crypto");
8080
- const { glob } = await import("./esm-UBAMNMQH.js");
7976
+ const { glob } = await import("./esm-RQFF6QRX.js");
8081
7977
  const globs = [
8082
7978
  "**/*.html",
8083
7979
  "**/*.htm",
@@ -8298,245 +8194,6 @@ async function loadDomainSchemas(domain) {
8298
8194
  }
8299
8195
  }
8300
8196
 
8301
- // src/tools/feedback-tools.ts
8302
- var feedbackTools = [
8303
- {
8304
- name: "lse_validate_and_feedback",
8305
- description: "Validate LSE input and return structured feedback with machine-actionable hints, corrected examples, and schema context for LLM self-correction.",
8306
- inputSchema: {
8307
- type: "object",
8308
- properties: {
8309
- input: {
8310
- type: "string",
8311
- description: "The LSE input to validate (bracket syntax, JSON, or natural language)"
8312
- },
8313
- format: {
8314
- type: "string",
8315
- description: "Input format: explicit (default), json, protocol (full-fidelity v1.1/v1.2), envelope (v1.2 multi-node), or natural"
8316
- },
8317
- domain: {
8318
- type: "string",
8319
- description: "Domain to validate against (flow, sql, bdd, llm, jsx, todo, behaviorspec, voice)"
8320
- }
8321
- },
8322
- required: ["input"]
8323
- }
8324
- },
8325
- {
8326
- name: "lse_pattern_stats",
8327
- description: "Return pattern hit-rate statistics: success rates by command and language, top diagnostic failures, and outcome distribution.",
8328
- inputSchema: {
8329
- type: "object",
8330
- properties: {
8331
- domain: {
8332
- type: "string",
8333
- description: "Filter stats by domain (optional)"
8334
- }
8335
- }
8336
- }
8337
- }
8338
- ];
8339
- async function handleFeedbackTool(name, args) {
8340
- switch (name) {
8341
- case "lse_validate_and_feedback":
8342
- return handleValidateAndFeedback(args);
8343
- case "lse_pattern_stats":
8344
- return handlePatternStats();
8345
- default:
8346
- return {
8347
- content: [{ type: "text", text: `Unknown feedback tool: ${name}` }],
8348
- isError: true
8349
- };
8350
- }
8351
- }
8352
- async function handleValidateAndFeedback(args) {
8353
- try {
8354
- const { buildFeedback, parseExplicit: parseExplicit2 } = await import("@lokascript/framework");
8355
- const input = args.input;
8356
- if (!input) {
8357
- return {
8358
- content: [{ type: "text", text: "Missing required parameter: input" }],
8359
- isError: true
8360
- };
8361
- }
8362
- const format = args.format || "explicit";
8363
- const domain = args.domain;
8364
- let action;
8365
- let schemaLookup;
8366
- const diagnostics = [];
8367
- if (domain) {
8368
- const schemas = await loadDomainSchemas2(domain);
8369
- if (schemas) {
8370
- schemaLookup = createSchemaLookup(schemas);
8371
- }
8372
- }
8373
- if (format === "explicit") {
8374
- try {
8375
- const result = parseExplicit2(input, { schemaLookup });
8376
- if (result) {
8377
- action = result.action;
8378
- }
8379
- } catch (e) {
8380
- diagnostics.push({
8381
- severity: "error",
8382
- message: e instanceof Error ? e.message : "Parse error: invalid bracket syntax",
8383
- code: "parse-error"
8384
- });
8385
- }
8386
- } else if (format === "json") {
8387
- try {
8388
- const parsed = JSON.parse(input);
8389
- action = parsed.action;
8390
- if (!action) {
8391
- diagnostics.push({
8392
- severity: "error",
8393
- message: 'JSON missing required "action" field',
8394
- code: "missing-role"
8395
- });
8396
- }
8397
- } catch {
8398
- diagnostics.push({
8399
- severity: "error",
8400
- message: "Invalid JSON syntax",
8401
- code: "parse-error"
8402
- });
8403
- }
8404
- } else if (format === "protocol") {
8405
- try {
8406
- const { validateProtocolJSON: validateProtocolJSON2, fromProtocolJSON: fromProtocolJSON2 } = await import("@lokascript/framework");
8407
- const parsed = JSON.parse(input);
8408
- const protoDiags = validateProtocolJSON2(parsed);
8409
- for (const d of protoDiags) {
8410
- diagnostics.push({ severity: d.severity, message: d.message, code: d.code });
8411
- }
8412
- if (protoDiags.filter((d) => d.severity === "error").length === 0) {
8413
- const node = fromProtocolJSON2(parsed);
8414
- action = node.action;
8415
- }
8416
- } catch (e) {
8417
- diagnostics.push({
8418
- severity: "error",
8419
- message: e instanceof Error ? e.message : "Invalid protocol JSON",
8420
- code: "parse-error"
8421
- });
8422
- }
8423
- } else if (format === "envelope") {
8424
- try {
8425
- const { isEnvelope: isEnvelope2, fromEnvelopeJSON: fromEnvelopeJSON2, validateProtocolJSON: validateProtocolJSON2 } = await import("@lokascript/framework");
8426
- const parsed = JSON.parse(input);
8427
- if (!isEnvelope2(parsed)) {
8428
- diagnostics.push({
8429
- severity: "error",
8430
- message: "Not a valid LSE envelope: missing lseVersion or nodes",
8431
- code: "invalid-envelope"
8432
- });
8433
- } else {
8434
- for (let i = 0; i < parsed.nodes.length; i++) {
8435
- const nodeDiags = validateProtocolJSON2(parsed.nodes[i]);
8436
- for (const d of nodeDiags) {
8437
- diagnostics.push({
8438
- severity: d.severity,
8439
- message: `Node ${i}: ${d.message}`,
8440
- code: d.code
8441
- });
8442
- }
8443
- }
8444
- if (diagnostics.filter((d) => d.severity === "error").length === 0) {
8445
- const envelope = fromEnvelopeJSON2(parsed);
8446
- action = envelope.nodes[0]?.action;
8447
- }
8448
- }
8449
- } catch (e) {
8450
- diagnostics.push({
8451
- severity: "error",
8452
- message: e instanceof Error ? e.message : "Invalid envelope JSON",
8453
- code: "parse-error"
8454
- });
8455
- }
8456
- }
8457
- const feedbackFormat = format === "protocol" || format === "envelope" ? "json" : format;
8458
- const feedback = buildFeedback(input, feedbackFormat, diagnostics, schemaLookup, action);
8459
- return {
8460
- content: [{ type: "text", text: JSON.stringify(feedback, null, 2) }]
8461
- };
8462
- } catch (error) {
8463
- return {
8464
- content: [
8465
- {
8466
- type: "text",
8467
- text: `Feedback tool error: ${error instanceof Error ? error.message : String(error)}`
8468
- }
8469
- ],
8470
- isError: true
8471
- };
8472
- }
8473
- }
8474
- var _tracker = null;
8475
- async function getTracker() {
8476
- if (!_tracker) {
8477
- const { PatternTracker } = await import("@lokascript/framework");
8478
- _tracker = new PatternTracker(1e3);
8479
- }
8480
- return _tracker;
8481
- }
8482
- async function handlePatternStats() {
8483
- try {
8484
- const tracker = await getTracker();
8485
- const summary = tracker.getSummary();
8486
- const text = summary.totalEvents === 0 ? "No pattern events recorded yet. Events are recorded as LSE inputs are validated." : JSON.stringify(summary, null, 2);
8487
- return {
8488
- content: [{ type: "text", text }]
8489
- };
8490
- } catch (error) {
8491
- return {
8492
- content: [
8493
- {
8494
- type: "text",
8495
- text: `Pattern stats error: ${error instanceof Error ? error.message : String(error)}`
8496
- }
8497
- ],
8498
- isError: true
8499
- };
8500
- }
8501
- }
8502
- async function loadDomainSchemas2(domain) {
8503
- try {
8504
- switch (domain) {
8505
- case "flow":
8506
- return (await import("@lokascript/domain-flow")).allSchemas;
8507
- case "sql":
8508
- return (await import("@lokascript/domain-sql")).allSchemas;
8509
- case "bdd":
8510
- return (await import("@lokascript/domain-bdd")).allSchemas;
8511
- case "llm":
8512
- return (await import("@lokascript/domain-llm")).allSchemas;
8513
- case "jsx":
8514
- return (await import("@lokascript/domain-jsx")).allSchemas;
8515
- case "todo":
8516
- return (await import("@lokascript/domain-todo")).allSchemas;
8517
- case "behaviorspec":
8518
- return (await import("@lokascript/domain-behaviorspec")).allSchemas;
8519
- case "voice":
8520
- return (await import("@lokascript/domain-voice")).allSchemas;
8521
- default:
8522
- return null;
8523
- }
8524
- } catch {
8525
- return null;
8526
- }
8527
- }
8528
- function createSchemaLookup(schemas) {
8529
- const map = /* @__PURE__ */ new Map();
8530
- for (const s of schemas) {
8531
- map.set(s.action, s);
8532
- }
8533
- return {
8534
- getSchema(action) {
8535
- return map.get(action);
8536
- }
8537
- };
8538
- }
8539
-
8540
8197
  // src/tools/lse-pipeline.ts
8541
8198
  var lsePipelineTools = [
8542
8199
  // ── Phase 7.5: LLM-Native LSE tools ──────────────────────────────────────
@@ -9507,6 +9164,231 @@ async function handleGrailTool(name, args) {
9507
9164
  }
9508
9165
  }
9509
9166
 
9167
+ // src/tools/lse-correction.ts
9168
+ var lseCorrectionTools = [
9169
+ {
9170
+ name: "lse_generate_with_correction",
9171
+ description: "Stateless LSE generation helper. Without an attempt, returns a generation prompt and schema context for producing LSE protocol JSON. With an attempt, validates it and returns either the valid node or structured feedback + corrected example + a refined prompt. Call repeatedly (up to maxRounds) to converge on valid LSE. Supports bracket syntax ([command role:value ...]) or raw protocol JSON.",
9172
+ inputSchema: {
9173
+ type: "object",
9174
+ properties: {
9175
+ task: {
9176
+ type: "string",
9177
+ description: 'Natural language description of the UI interaction to generate. E.g. "A button that toggles .active on #sidebar when clicked".'
9178
+ },
9179
+ attempt: {
9180
+ type: "string",
9181
+ description: "Your current LSE attempt \u2014 bracket syntax or JSON string. Omit on round 0 to get a generation prompt."
9182
+ },
9183
+ domain: {
9184
+ type: "string",
9185
+ description: "Optional command domain for schema validation: hyperscript, flow, sql, bdd, voice, etc."
9186
+ },
9187
+ round: {
9188
+ type: "number",
9189
+ description: "Current correction round (0-based, default 0)."
9190
+ },
9191
+ maxRounds: {
9192
+ type: "number",
9193
+ description: "Maximum rounds before giving up (default 3)."
9194
+ }
9195
+ },
9196
+ required: ["task"]
9197
+ }
9198
+ }
9199
+ ];
9200
+ async function handleLseCorrectionTool(name, args) {
9201
+ if (name !== "lse_generate_with_correction") {
9202
+ return errorResponse(`Unknown correction tool: ${name}`);
9203
+ }
9204
+ const task = args.task;
9205
+ if (!task || typeof task !== "string") {
9206
+ return errorResponse("Missing required parameter: task");
9207
+ }
9208
+ const attempt = typeof args.attempt === "string" ? args.attempt.trim() : void 0;
9209
+ const domain = typeof args.domain === "string" ? args.domain : void 0;
9210
+ const round = typeof args.round === "number" ? args.round : 0;
9211
+ const maxRounds = typeof args.maxRounds === "number" ? args.maxRounds : 3;
9212
+ if (!attempt) {
9213
+ return handleGenerationPrompt(task, domain);
9214
+ }
9215
+ if (round >= maxRounds) {
9216
+ return jsonResponse({
9217
+ ok: false,
9218
+ exhausted: true,
9219
+ round,
9220
+ maxRounds,
9221
+ message: `Maximum correction rounds (${maxRounds}) reached without valid LSE. Review the task description and try a simpler interaction pattern.`
9222
+ });
9223
+ }
9224
+ return handleValidateAttempt(task, attempt, domain, round, maxRounds);
9225
+ }
9226
+ async function handleGenerationPrompt(task, domain) {
9227
+ const schemaContext = await buildSchemaContext(domain);
9228
+ const systemContext = [
9229
+ "## LSE (LokaScript Explicit Syntax) Generation",
9230
+ "",
9231
+ "LSE uses bracket syntax: `[command role:value role:value ...]`",
9232
+ "",
9233
+ "### Value types",
9234
+ "- Selector: `.class`, `#id`, `element`, or complex selectors \u2192 `patient:.active`",
9235
+ '- Literal: quoted strings or numbers \u2192 `source:"/api/data"`, `count:3`',
9236
+ "- Reference: built-in refs (me, it, you, body, window, document) \u2192 `destination:me`",
9237
+ "- Flag: boolean flag \u2192 `+async` (enabled), `~async` (disabled)",
9238
+ "",
9239
+ "### Common patterns",
9240
+ "- Toggle class: `[toggle patient:.active]`",
9241
+ "- Add/remove class: `[add patient:.highlight destination:#target]`",
9242
+ '- Set value: `[set patient:#input value:"hello"]`',
9243
+ '- Fetch data: `[fetch source:"/api/data" target:#results]`',
9244
+ "- Show/hide: `[show patient:#modal]` / `[hide patient:#modal]`",
9245
+ "",
9246
+ "### Protocol JSON (alternative format)",
9247
+ "```json",
9248
+ '{"action":"toggle","roles":{"patient":{"type":"selector","value":".active"}}}',
9249
+ "```"
9250
+ ];
9251
+ if (schemaContext) {
9252
+ systemContext.push("", "### Available commands for this domain", schemaContext);
9253
+ }
9254
+ const nextPrompt = [
9255
+ `Task: ${task}`,
9256
+ "",
9257
+ "Generate LSE bracket syntax or protocol JSON for the above task.",
9258
+ "Return ONLY the LSE \u2014 no explanation, no markdown fences.",
9259
+ "If using bracket syntax: `[command role:value ...]`",
9260
+ 'If using JSON: `{"action":"...","roles":{...}}`'
9261
+ ].join("\n");
9262
+ return jsonResponse({
9263
+ ok: false,
9264
+ needsAttempt: true,
9265
+ round: 0,
9266
+ systemContext: systemContext.join("\n"),
9267
+ nextPrompt,
9268
+ instructions: "Use systemContext as your system prompt and nextPrompt as your user message. Pass the response back as `attempt` in the next call."
9269
+ });
9270
+ }
9271
+ async function handleValidateAttempt(task, attempt, domain, round, maxRounds) {
9272
+ const { parseExplicit: parseExplicit2, renderExplicit: renderExplicit2, toProtocolJSON: toProtocolJSON2, validateProtocolJSON: validateProtocolJSON2, fromProtocolJSON: fromProtocolJSON2 } = await import("@lokascript/framework");
9273
+ let node = null;
9274
+ const diagnostics = [];
9275
+ const isJSON = attempt.trimStart().startsWith("{");
9276
+ if (isJSON) {
9277
+ let parsed;
9278
+ try {
9279
+ parsed = JSON.parse(attempt);
9280
+ } catch {
9281
+ diagnostics.push({
9282
+ severity: "error",
9283
+ code: "INVALID_JSON",
9284
+ message: "Attempt is not valid JSON"
9285
+ });
9286
+ }
9287
+ if (parsed) {
9288
+ const protoDiags = validateProtocolJSON2(parsed);
9289
+ for (const d of protoDiags) diagnostics.push(d);
9290
+ if (!protoDiags.some((d) => d.severity === "error")) {
9291
+ try {
9292
+ node = fromProtocolJSON2(parsed);
9293
+ } catch (e) {
9294
+ diagnostics.push({
9295
+ severity: "error",
9296
+ code: "DESERIALIZE_ERROR",
9297
+ message: e instanceof Error ? e.message : String(e)
9298
+ });
9299
+ }
9300
+ }
9301
+ }
9302
+ } else {
9303
+ try {
9304
+ node = parseExplicit2(attempt);
9305
+ } catch (e) {
9306
+ diagnostics.push({
9307
+ severity: "error",
9308
+ code: "PARSE_ERROR",
9309
+ message: e instanceof Error ? e.message : String(e)
9310
+ });
9311
+ }
9312
+ }
9313
+ const hasErrors = diagnostics.some((d) => d.severity === "error");
9314
+ if (!hasErrors && node) {
9315
+ const lse = renderExplicit2(node);
9316
+ const protocol = toProtocolJSON2(node);
9317
+ return jsonResponse({
9318
+ ok: true,
9319
+ round,
9320
+ lse,
9321
+ protocol,
9322
+ diagnostics,
9323
+ message: round === 0 ? "Valid LSE on first attempt." : `Valid LSE after ${round} correction round${round === 1 ? "" : "s"}.`
9324
+ });
9325
+ }
9326
+ const correctedExample = buildCorrectedExample(attempt, diagnostics);
9327
+ const remaining = maxRounds - round - 1;
9328
+ let nextPrompt;
9329
+ if (remaining > 0) {
9330
+ nextPrompt = [
9331
+ `Task: ${task}`,
9332
+ "",
9333
+ "Your previous attempt had errors:",
9334
+ ...diagnostics.filter((d) => d.severity === "error").map((d) => ` \u2022 [${d.code}] ${d.message}`),
9335
+ "",
9336
+ correctedExample ? `Corrected example:
9337
+ ${correctedExample}` : "",
9338
+ "",
9339
+ "Generate a corrected LSE. Return ONLY the LSE \u2014 no explanation."
9340
+ ].filter(Boolean).join("\n");
9341
+ } else {
9342
+ nextPrompt = [
9343
+ `Task: ${task}`,
9344
+ "",
9345
+ "Final attempt. Your previous LSE had these errors:",
9346
+ ...diagnostics.filter((d) => d.severity === "error").map((d) => ` \u2022 [${d.code}] ${d.message}`),
9347
+ "",
9348
+ "Produce the simplest valid LSE you can for this task."
9349
+ ].join("\n");
9350
+ }
9351
+ return jsonResponse({
9352
+ ok: false,
9353
+ round,
9354
+ remainingRounds: remaining,
9355
+ diagnostics,
9356
+ correctedExample,
9357
+ nextPrompt,
9358
+ instructions: remaining > 0 ? `Use nextPrompt to generate a corrected attempt, then call again with round: ${round + 1}.` : "Last correction round \u2014 generate the simplest valid LSE you can."
9359
+ });
9360
+ }
9361
+ function buildCorrectedExample(attempt, diagnostics) {
9362
+ const bracketMatch = attempt.match(/^\[\s*(\w+)/);
9363
+ const jsonMatch = attempt.match(/"action"\s*:\s*"(\w+)"/);
9364
+ const action = bracketMatch?.[1] ?? jsonMatch?.[1];
9365
+ if (!action) return null;
9366
+ const missingRoles = diagnostics.filter((d) => d.code === "MISSING_REQUIRED_ROLE").map((d) => {
9367
+ const m = d.message.match(/role "(\w+)"/);
9368
+ return m?.[1];
9369
+ }).filter(Boolean);
9370
+ if (missingRoles.length > 0) {
9371
+ const roleParts = missingRoles.map((r) => `${r}:.<value>`).join(" ");
9372
+ return `[${action} ${roleParts}]`;
9373
+ }
9374
+ return `[${action} patient:.<selector>]`;
9375
+ }
9376
+ async function buildSchemaContext(domain) {
9377
+ if (!domain) return null;
9378
+ try {
9379
+ const { loadDomainSchemas: loadDomainSchemas2 } = await import("./feedback-tools-S6VDG6F5.js");
9380
+ if (typeof loadDomainSchemas2 !== "function") return null;
9381
+ const schemas = await loadDomainSchemas2(domain);
9382
+ if (!schemas || schemas.length === 0) return null;
9383
+ return schemas.map((s) => {
9384
+ const roles = (s.roles ?? []).map((r) => `${r.role}${r.required ? "" : "?"}`).join(", ");
9385
+ return `- \`${s.action}\`${roles ? ` (${roles})` : ""}${s.description ? ": " + s.description : ""}`;
9386
+ }).join("\n");
9387
+ } catch {
9388
+ return null;
9389
+ }
9390
+ }
9391
+
9510
9392
  // src/resources/content.ts
9511
9393
  function getCommandsReference() {
9512
9394
  return `# Hyperscript Commands Reference
@@ -10535,7 +10417,8 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
10535
10417
  ...trainingDataTools,
10536
10418
  ...feedbackTools,
10537
10419
  ...lsePipelineTools,
10538
- ...grailTools
10420
+ ...grailTools,
10421
+ ...lseCorrectionTools
10539
10422
  ]
10540
10423
  };
10541
10424
  });
@@ -10603,6 +10486,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
10603
10486
  if (name.startsWith("grail_")) {
10604
10487
  return handleGrailTool(name, args);
10605
10488
  }
10489
+ if (name === "lse_generate_with_correction") {
10490
+ return handleLseCorrectionTool(name, args);
10491
+ }
10606
10492
  if (name.startsWith("get_")) {
10607
10493
  return handlePatternTool(name, args);
10608
10494
  }