dirac-lang 0.1.32 → 0.1.34

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 CHANGED
@@ -255,3 +255,31 @@ npm install -g dirac-lang
255
255
  ---
256
256
 
257
257
  *"In the quantum realm, a bra meets a ket to produce reality. In Dirac, a declaration meets an LLM to produce execution."*
258
+
259
+ ## PAUL: The Human-Friendly Dirac Dialect
260
+
261
+ Dirac’s XML-based language is designed for robust machine execution and symbolic reasoning. For human authors, we introduce **PAUL** (Programming AI Utility Language)—a concise, bra/ket-inspired notation for writing Dirac programs quickly and intuitively.
262
+
263
+ - PAUL uses bra/ket syntax and positional arguments for readability.
264
+ - It is ideal for human editing, rapid prototyping, and LLM prompts.
265
+ - PAUL scripts are typically saved with the `.bk` extension.
266
+ - The Dirac interpreter translates PAUL to XML Dirac for execution.
267
+
268
+ **Example:**
269
+
270
+ PAUL (.bk):
271
+ ```
272
+ |greet Alice>
273
+ ```
274
+
275
+ Dirac XML (.di):
276
+ ```xml
277
+ <greet name="Alice" />
278
+ ```
279
+
280
+ **Note:**
281
+ - PAUL relies on conventions for mapping positional arguments to named parameters.
282
+ - For machine execution, always convert PAUL to XML Dirac.
283
+ - The `.bk` extension is recommended for PAUL scripts.
284
+
285
+ PAUL is the human-centric dialect of Dirac—optimized for clarity, speed, and LLM interaction.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  integrate
3
- } from "./chunk-YRJ3SODI.js";
3
+ } from "./chunk-HPGONBNW.js";
4
4
  import {
5
5
  DiracParser
6
6
  } from "./chunk-HRHAMPOB.js";
@@ -8,7 +8,7 @@ import {
8
8
  createSession,
9
9
  getAvailableSubroutines,
10
10
  getOutput
11
- } from "./chunk-JIWLKB5O.js";
11
+ } from "./chunk-GLXVY235.js";
12
12
 
13
13
  // src/utils/llm-adapter.ts
14
14
  function createLLMAdapter(session) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  registerSubroutine
3
- } from "./chunk-JIWLKB5O.js";
3
+ } from "./chunk-GLXVY235.js";
4
4
 
5
5
  // src/tags/subroutine.ts
6
6
  function executeSubroutine(session, element) {
@@ -0,0 +1,166 @@
1
+ // src/runtime/braket-parser.ts
2
+ var BraKetParser = class {
3
+ lines = [];
4
+ currentLine = 0;
5
+ /**
6
+ * Parse bra-ket notation and compile to XML
7
+ */
8
+ parse(source) {
9
+ this.lines = source.split("\n");
10
+ this.currentLine = 0;
11
+ const xml = ["<dirac>"];
12
+ this.parseBlock(xml, -1);
13
+ xml.push("</dirac>");
14
+ return xml.join("\n");
15
+ }
16
+ /**
17
+ * Parse a block of lines at a given indentation level
18
+ */
19
+ parseBlock(output, parentIndent) {
20
+ while (this.currentLine < this.lines.length) {
21
+ const line = this.parseLine(this.lines[this.currentLine]);
22
+ if (line.type === "empty") {
23
+ this.currentLine++;
24
+ continue;
25
+ }
26
+ if (line.indent <= parentIndent) {
27
+ break;
28
+ }
29
+ if (line.type === "bra") {
30
+ const attrs = line.attrs ? ` ${this.convertAttributes(line.attrs)}` : "";
31
+ output.push(`${" ".repeat(line.indent)}<subroutine name="${line.tag}"${attrs}>`);
32
+ this.currentLine++;
33
+ this.parseBlock(output, line.indent);
34
+ output.push(`${" ".repeat(line.indent)}</subroutine>`);
35
+ continue;
36
+ }
37
+ if (line.type === "ket") {
38
+ const indent = " ".repeat(line.indent);
39
+ const attrs = line.attrs ? ` ${this.convertAttributes(line.attrs)}` : "";
40
+ const nextLine = this.currentLine + 1 < this.lines.length ? this.parseLine(this.lines[this.currentLine + 1]) : null;
41
+ if (nextLine && nextLine.indent > line.indent && nextLine.type !== "empty") {
42
+ output.push(`${indent}<${line.tag}${attrs}>`);
43
+ this.currentLine++;
44
+ this.parseBlock(output, line.indent);
45
+ output.push(`${indent}</${line.tag}>`);
46
+ } else {
47
+ if (line.text) {
48
+ const content = this.convertInlineKets(line.text);
49
+ output.push(`${indent}<${line.tag}${attrs}>${content}</${line.tag}>`);
50
+ } else {
51
+ output.push(`${indent}<${line.tag}${attrs}/>`);
52
+ }
53
+ this.currentLine++;
54
+ }
55
+ continue;
56
+ }
57
+ if (line.type === "text") {
58
+ const indent = " ".repeat(line.indent);
59
+ const content = this.convertInlineKets(line.text || "");
60
+ output.push(`${indent}${content}`);
61
+ this.currentLine++;
62
+ continue;
63
+ }
64
+ }
65
+ }
66
+ /**
67
+ * Parse a single line into structured form
68
+ */
69
+ parseLine(raw) {
70
+ const match = raw.match(/^(\s*)(.*)/);
71
+ const indent = match ? Math.floor(match[1].length / 2) : 0;
72
+ const content = match ? match[2] : "";
73
+ if (!content.trim()) {
74
+ return { indent, type: "empty", raw };
75
+ }
76
+ const braMatch = content.match(/^<([a-zA-Z_][a-zA-Z0-9_-]*)\s*([^|]*)\|$/);
77
+ if (braMatch) {
78
+ return {
79
+ indent,
80
+ type: "bra",
81
+ tag: braMatch[1],
82
+ attrs: braMatch[2].trim() || void 0,
83
+ raw
84
+ };
85
+ }
86
+ const ketMatch = content.match(/^\|([a-zA-Z_][a-zA-Z0-9_-]*)\s*([^>]*?)>\s*(.*)/);
87
+ if (ketMatch) {
88
+ return {
89
+ indent,
90
+ type: "ket",
91
+ tag: ketMatch[1],
92
+ attrs: ketMatch[2].trim() || void 0,
93
+ text: ketMatch[3] || void 0,
94
+ raw
95
+ };
96
+ }
97
+ return {
98
+ indent,
99
+ type: "text",
100
+ text: content,
101
+ raw
102
+ };
103
+ }
104
+ /**
105
+ * Convert bra-ket attribute syntax to XML
106
+ * Examples:
107
+ * name=value → name="value"
108
+ * x=5 y=10 → x="5" y="10"
109
+ * select=@* → select="@*"
110
+ */
111
+ convertAttributes(attrs) {
112
+ if (!attrs) return "";
113
+ const parts = [];
114
+ let current = "";
115
+ let inQuotes = false;
116
+ let quoteChar = "";
117
+ for (let i = 0; i < attrs.length; i++) {
118
+ const char = attrs[i];
119
+ if ((char === '"' || char === "'") && (i === 0 || attrs[i - 1] !== "\\")) {
120
+ if (!inQuotes) {
121
+ inQuotes = true;
122
+ quoteChar = char;
123
+ current += char;
124
+ } else if (char === quoteChar) {
125
+ inQuotes = false;
126
+ current += char;
127
+ } else {
128
+ current += char;
129
+ }
130
+ } else if (char === " " && !inQuotes) {
131
+ if (current.trim()) {
132
+ parts.push(current.trim());
133
+ current = "";
134
+ }
135
+ } else {
136
+ current += char;
137
+ }
138
+ }
139
+ if (current.trim()) {
140
+ parts.push(current.trim());
141
+ }
142
+ return parts.map((part) => {
143
+ const match = part.match(/^([a-zA-Z_][a-zA-Z0-9_-]*)=(.+)$/);
144
+ if (!match) return part;
145
+ const [, name, value] = match;
146
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
147
+ return `${name}=${value}`;
148
+ }
149
+ return `${name}="${value}"`;
150
+ }).join(" ");
151
+ }
152
+ /**
153
+ * Convert inline kets within text content
154
+ * Example: "Hello |variable name=x> world" → "Hello <variable name="x"/> world"
155
+ */
156
+ convertInlineKets(text) {
157
+ return text.replace(/\|([a-zA-Z_][a-zA-Z0-9_-]*)\s*([^>]*?)>/g, (match, tag, attrs) => {
158
+ const attrStr = attrs.trim() ? ` ${this.convertAttributes(attrs.trim())}` : "";
159
+ return `<${tag}${attrStr}/>`;
160
+ });
161
+ }
162
+ };
163
+
164
+ export {
165
+ BraKetParser
166
+ };
@@ -51,6 +51,38 @@ var OllamaProvider = class {
51
51
  }
52
52
  };
53
53
 
54
+ // src/llm/custom.ts
55
+ var CustomLLMProvider = class {
56
+ client;
57
+ model;
58
+ constructor(options = {}) {
59
+ this.client = new CustomLLMClient(options);
60
+ this.model = options.model || "default";
61
+ }
62
+ async complete(prompt, opts = {}) {
63
+ const messages = opts.messages || [
64
+ { role: "user", content: prompt }
65
+ ];
66
+ return await this.client.chat({ messages });
67
+ }
68
+ };
69
+ var CustomLLMClient = class {
70
+ baseUrl;
71
+ constructor({ baseUrl = "http://localhost:5001" } = {}) {
72
+ this.baseUrl = baseUrl;
73
+ }
74
+ async chat({ messages }) {
75
+ const prompt = messages.map((m) => `${m.role}: ${m.content}`).join("\n");
76
+ const res = await fetch(`${this.baseUrl}/chat`, {
77
+ method: "POST",
78
+ headers: { "Content-Type": "application/json" },
79
+ body: JSON.stringify({ message: prompt })
80
+ });
81
+ const data = await res.json();
82
+ return data.response;
83
+ }
84
+ };
85
+
54
86
  // src/runtime/session.ts
55
87
  function substituteAttribute(session, value) {
56
88
  if (typeof value !== "string") return value;
@@ -81,8 +113,12 @@ function createSession(config = {}) {
81
113
  if (!openaiKey) throw new Error("OPENAI_API_KEY required for OpenAI provider");
82
114
  llmClient = new OpenAI({ apiKey: openaiKey });
83
115
  break;
116
+ case "custom":
117
+ const customBaseUrl = config.customLLMUrl || process.env.CUSTOM_LLM_URL || "http://localhost:5001";
118
+ llmClient = new CustomLLMProvider({ baseUrl: customBaseUrl, model: ollamaModel });
119
+ break;
84
120
  default:
85
- throw new Error(`Unknown LLM provider: ${llmProvider}. Use 'ollama', 'anthropic', or 'openai'.`);
121
+ throw new Error(`Unknown LLM provider: ${llmProvider}. Use 'ollama', 'anthropic', 'openai', or 'custom'.`);
86
122
  }
87
123
  }
88
124
  return {
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-HRHAMPOB.js";
4
4
  import {
5
5
  executeSubroutine
6
- } from "./chunk-JMUUPZZA.js";
6
+ } from "./chunk-4QLTSCDG.js";
7
7
  import {
8
8
  cleanSubroutinesToBoundary,
9
9
  cleanToBoundary,
@@ -25,7 +25,7 @@ import {
25
25
  substituteVariables,
26
26
  throwException,
27
27
  unsetExceptionBoundary
28
- } from "./chunk-JIWLKB5O.js";
28
+ } from "./chunk-GLXVY235.js";
29
29
 
30
30
  // src/tags/parameters.ts
31
31
  async function executeParameters(session, element) {
@@ -257,7 +257,7 @@ async function executeCall(session, element) {
257
257
  }
258
258
  }
259
259
  async function registerExtendChain(session, subroutine, currentName) {
260
- const { executeSubroutine: executeSubroutine2 } = await import("./subroutine-I5XXJMFL.js");
260
+ const { executeSubroutine: executeSubroutine2 } = await import("./subroutine-V4D4LQIH.js");
261
261
  const extendsAttr = subroutine.attributes.extends;
262
262
  let parentName;
263
263
  if (extendsAttr) {
@@ -425,12 +425,12 @@ async function executeIf(session, element) {
425
425
  const condition = await evaluatePredicate(session, conditionElement);
426
426
  if (condition) {
427
427
  if (thenElement) {
428
- const { integrateChildren: integrateChildren2 } = await import("./interpreter-WP3KMLST.js");
428
+ const { integrateChildren: integrateChildren2 } = await import("./interpreter-F65BCAYX.js");
429
429
  await integrateChildren2(session, thenElement);
430
430
  }
431
431
  } else {
432
432
  if (elseElement) {
433
- const { integrateChildren: integrateChildren2 } = await import("./interpreter-WP3KMLST.js");
433
+ const { integrateChildren: integrateChildren2 } = await import("./interpreter-F65BCAYX.js");
434
434
  await integrateChildren2(session, elseElement);
435
435
  }
436
436
  }
@@ -443,7 +443,7 @@ async function evaluatePredicate(session, predicateElement) {
443
443
  return await evaluateCondition(session, predicateElement);
444
444
  }
445
445
  const outputLengthBefore = session.output.length;
446
- const { integrate: integrate2 } = await import("./interpreter-WP3KMLST.js");
446
+ const { integrate: integrate2 } = await import("./interpreter-F65BCAYX.js");
447
447
  await integrate2(session, predicateElement);
448
448
  const newOutputChunks = session.output.slice(outputLengthBefore);
449
449
  const result = newOutputChunks.join("").trim();
@@ -466,11 +466,11 @@ async function evaluateCondition(session, condElement) {
466
466
  }
467
467
  const outputLengthBefore = session.output.length;
468
468
  const args = [];
469
- const { integrate: integrate2 } = await import("./interpreter-WP3KMLST.js");
469
+ const { integrate: integrate2 } = await import("./interpreter-F65BCAYX.js");
470
470
  for (const child of condElement.children) {
471
471
  if (child.tag.toLowerCase() === "arg") {
472
472
  const argOutputStart = session.output.length;
473
- const { integrateChildren: integrateChildren2 } = await import("./interpreter-WP3KMLST.js");
473
+ const { integrateChildren: integrateChildren2 } = await import("./interpreter-F65BCAYX.js");
474
474
  await integrateChildren2(session, child);
475
475
  const newChunks = session.output.slice(argOutputStart);
476
476
  const argValue = newChunks.join("");
@@ -531,7 +531,7 @@ function evaluateConditionType(evalType, args) {
531
531
  // src/tags/llm.ts
532
532
  async function executeLLM(session, element) {
533
533
  if (!session.llmClient) {
534
- throw new Error("<llm> tag requires LLM configuration. Set LLM_PROVIDER (ollama/anthropic/openai) and appropriate API keys in environment or config.yml");
534
+ throw new Error("<llm> tag requires LLM configuration. Set LLM_PROVIDER (ollama/anthropic/openai/custom) and appropriate API keys in environment or config.yml");
535
535
  }
536
536
  if (session.limits.currentLLMCalls >= session.limits.maxLLMCalls) {
537
537
  throw new Error("Maximum LLM calls exceeded");
@@ -540,7 +540,8 @@ async function executeLLM(session, element) {
540
540
  const providerName = session.llmClient.constructor.name;
541
541
  const isOpenAI = providerName === "OpenAI";
542
542
  const isOllama = providerName === "OllamaProvider";
543
- const defaultModel = isOpenAI ? "gpt-4.1-2025-04-14" : isOllama ? "llama2" : "claude-sonnet-4-20250514";
543
+ const isCustom = providerName === "CustomLLMProvider";
544
+ const defaultModel = isOpenAI ? "gpt-4.1-2025-04-14" : isOllama ? "llama2" : isCustom ? "custom-model" : "claude-sonnet-4-20250514";
544
545
  const model = element.attributes.model || process.env.DEFAULT_MODEL || defaultModel;
545
546
  const outputVar = element.attributes.output;
546
547
  const contextVar = element.attributes.context;
@@ -579,7 +580,7 @@ async function executeLLM(session, element) {
579
580
  console.error("[LLM] Full prompt sent to LLM (noextra):\n" + prompt + "\n");
580
581
  }
581
582
  } else {
582
- const { getAvailableSubroutines } = await import("./session-UIWHLPTR.js");
583
+ const { getAvailableSubroutines } = await import("./session-UBATJEND.js");
583
584
  const subroutines = getAvailableSubroutines(session);
584
585
  if (session.debug) {
585
586
  console.error(
@@ -647,6 +648,14 @@ then you call it like
647
648
  temperature,
648
649
  max_tokens: maxTokens
649
650
  });
651
+ } else if (isCustom) {
652
+ const customPrompt = dialogHistory.map((m) => `${m.role}: ${m.content}`).join("\n");
653
+ result = await session.llmClient.complete(customPrompt, {
654
+ model,
655
+ temperature,
656
+ max_tokens: maxTokens,
657
+ messages: dialogHistory
658
+ });
650
659
  } else {
651
660
  const response = await session.llmClient.messages.create({
652
661
  model,
@@ -706,7 +715,7 @@ ${result}
706
715
  const parser = new DiracParser();
707
716
  let dynamicAST = parser.parse(diracCode);
708
717
  if (validateTags) {
709
- const { validateDiracCode, applyCorrectedTags } = await import("./tag-validator-QX47WU2J.js");
718
+ const { validateDiracCode, applyCorrectedTags } = await import("./tag-validator-3RLLFTY6.js");
710
719
  let validation = await validateDiracCode(session, dynamicAST, { autocorrect });
711
720
  let retryCount = 0;
712
721
  while (!validation.valid && retryCount < maxRetries) {
@@ -735,6 +744,14 @@ Please fix these errors and generate valid Dirac XML again. Remember to only use
735
744
  temperature,
736
745
  max_tokens: maxTokens
737
746
  });
747
+ } else if (isCustom) {
748
+ const customPrompt = dialogHistory.map((m) => `${m.role}: ${m.content}`).join("\n");
749
+ result = await session.llmClient.complete(customPrompt, {
750
+ model,
751
+ temperature,
752
+ max_tokens: maxTokens,
753
+ messages: dialogHistory
754
+ });
738
755
  } else {
739
756
  const response = await session.llmClient.messages.create({
740
757
  model,
@@ -815,6 +832,14 @@ ${feedbackPrompt}
815
832
  temperature,
816
833
  max_tokens: maxTokens
817
834
  });
835
+ } else if (isCustom) {
836
+ const customPrompt = dialogHistory.map((m) => `${m.role}: ${m.content}`).join("\n");
837
+ result = await session.llmClient.complete(customPrompt, {
838
+ model,
839
+ temperature,
840
+ max_tokens: maxTokens,
841
+ messages: dialogHistory
842
+ });
818
843
  } else {
819
844
  const response = await session.llmClient.messages.create({
820
845
  model,
@@ -1237,7 +1262,7 @@ async function getBestTagMatch(candidate, allowed) {
1237
1262
  return { tag: allowed[bestIdx], score: bestScore };
1238
1263
  }
1239
1264
  async function executeTagCheck(session, element) {
1240
- const { getAvailableSubroutines } = await import("./session-UIWHLPTR.js");
1265
+ const { getAvailableSubroutines } = await import("./session-UBATJEND.js");
1241
1266
  const subroutines = getAvailableSubroutines(session);
1242
1267
  const allowed = new Set(subroutines.map((s) => s.name));
1243
1268
  console.error("[tag-check] Allowed subroutines:", Array.from(allowed));
@@ -1330,7 +1355,7 @@ async function executeTagCheck(session, element) {
1330
1355
  const executeTag = correctedTag || tagName;
1331
1356
  console.error(`[tag-check] Executing <${executeTag}/> as all checks passed and execute=true.`);
1332
1357
  const elementToExecute = correctedTag ? { ...child, tag: correctedTag } : child;
1333
- const { integrate: integrate2 } = await import("./interpreter-WP3KMLST.js");
1358
+ const { integrate: integrate2 } = await import("./interpreter-F65BCAYX.js");
1334
1359
  await integrate2(session, elementToExecute);
1335
1360
  }
1336
1361
  }
@@ -1339,7 +1364,7 @@ async function executeTagCheck(session, element) {
1339
1364
  // src/tags/throw.ts
1340
1365
  async function executeThrow(session, element) {
1341
1366
  const exceptionName = element.attributes?.name || "exception";
1342
- const { integrateChildren: integrateChildren2 } = await import("./interpreter-WP3KMLST.js");
1367
+ const { integrateChildren: integrateChildren2 } = await import("./interpreter-F65BCAYX.js");
1343
1368
  const exceptionDom = {
1344
1369
  tag: "exception-content",
1345
1370
  attributes: { name: exceptionName },
@@ -1352,7 +1377,7 @@ async function executeThrow(session, element) {
1352
1377
  // src/tags/try.ts
1353
1378
  async function executeTry(session, element) {
1354
1379
  setExceptionBoundary(session);
1355
- const { integrateChildren: integrateChildren2 } = await import("./interpreter-WP3KMLST.js");
1380
+ const { integrateChildren: integrateChildren2 } = await import("./interpreter-F65BCAYX.js");
1356
1381
  await integrateChildren2(session, element);
1357
1382
  unsetExceptionBoundary(session);
1358
1383
  }
@@ -1362,7 +1387,7 @@ async function executeCatch(session, element) {
1362
1387
  const exceptionName = element.attributes?.name || "exception";
1363
1388
  const caughtCount = lookupException(session, exceptionName);
1364
1389
  if (caughtCount > 0) {
1365
- const { integrateChildren: integrateChildren2 } = await import("./interpreter-WP3KMLST.js");
1390
+ const { integrateChildren: integrateChildren2 } = await import("./interpreter-F65BCAYX.js");
1366
1391
  await integrateChildren2(session, element);
1367
1392
  }
1368
1393
  flushCurrentException(session);
@@ -1371,7 +1396,7 @@ async function executeCatch(session, element) {
1371
1396
  // src/tags/exception.ts
1372
1397
  async function executeException(session, element) {
1373
1398
  const exceptions = getCurrentExceptions(session);
1374
- const { integrateChildren: integrateChildren2 } = await import("./interpreter-WP3KMLST.js");
1399
+ const { integrateChildren: integrateChildren2 } = await import("./interpreter-F65BCAYX.js");
1375
1400
  for (const exceptionDom of exceptions) {
1376
1401
  await integrateChildren2(session, exceptionDom);
1377
1402
  }
@@ -1511,7 +1536,7 @@ async function executeForeach(session, element) {
1511
1536
  const parser2 = new DiracParser2();
1512
1537
  try {
1513
1538
  const fromElement = parser2.parse(fromAttr);
1514
- const { integrate: integrate2 } = await import("./interpreter-WP3KMLST.js");
1539
+ const { integrate: integrate2 } = await import("./interpreter-F65BCAYX.js");
1515
1540
  await integrate2(session, fromElement);
1516
1541
  } catch (e) {
1517
1542
  session.output = savedOutput;
package/dist/cli.js CHANGED
@@ -1,11 +1,14 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ BraKetParser
4
+ } from "./chunk-DRPHX3WX.js";
2
5
  import {
3
6
  execute
4
- } from "./chunk-UYDP4ZFS.js";
5
- import "./chunk-YRJ3SODI.js";
7
+ } from "./chunk-4LLFMVOW.js";
8
+ import "./chunk-HPGONBNW.js";
6
9
  import "./chunk-HRHAMPOB.js";
7
- import "./chunk-JMUUPZZA.js";
8
- import "./chunk-JIWLKB5O.js";
10
+ import "./chunk-4QLTSCDG.js";
11
+ import "./chunk-GLXVY235.js";
9
12
 
10
13
  // src/cli.ts
11
14
  import "dotenv/config";
@@ -13,7 +16,7 @@ import "dotenv/config";
13
16
  // package.json
14
17
  var package_default = {
15
18
  name: "dirac-lang",
16
- version: "0.1.32",
19
+ version: "0.1.34",
17
20
  description: "LLM-Augmented Declarative Execution",
18
21
  type: "module",
19
22
  main: "dist/index.js",
@@ -63,175 +66,14 @@ var package_default = {
63
66
  import fs from "fs";
64
67
  import yaml from "js-yaml";
65
68
  import { resolve, extname } from "path";
66
-
67
- // src/runtime/braket-parser.ts
68
- var BraKetParser = class {
69
- lines = [];
70
- currentLine = 0;
71
- /**
72
- * Parse bra-ket notation and compile to XML
73
- */
74
- parse(source) {
75
- this.lines = source.split("\n");
76
- this.currentLine = 0;
77
- const xml = ["<dirac>"];
78
- this.parseBlock(xml, -1);
79
- xml.push("</dirac>");
80
- return xml.join("\n");
81
- }
82
- /**
83
- * Parse a block of lines at a given indentation level
84
- */
85
- parseBlock(output, parentIndent) {
86
- while (this.currentLine < this.lines.length) {
87
- const line = this.parseLine(this.lines[this.currentLine]);
88
- if (line.type === "empty") {
89
- this.currentLine++;
90
- continue;
91
- }
92
- if (line.indent <= parentIndent) {
93
- break;
94
- }
95
- if (line.type === "bra") {
96
- const attrs = line.attrs ? ` ${this.convertAttributes(line.attrs)}` : "";
97
- output.push(`${" ".repeat(line.indent)}<subroutine name="${line.tag}"${attrs}>`);
98
- this.currentLine++;
99
- this.parseBlock(output, line.indent);
100
- output.push(`${" ".repeat(line.indent)}</subroutine>`);
101
- continue;
102
- }
103
- if (line.type === "ket") {
104
- const indent = " ".repeat(line.indent);
105
- const attrs = line.attrs ? ` ${this.convertAttributes(line.attrs)}` : "";
106
- const nextLine = this.currentLine + 1 < this.lines.length ? this.parseLine(this.lines[this.currentLine + 1]) : null;
107
- if (nextLine && nextLine.indent > line.indent && nextLine.type !== "empty") {
108
- output.push(`${indent}<${line.tag}${attrs}>`);
109
- this.currentLine++;
110
- this.parseBlock(output, line.indent);
111
- output.push(`${indent}</${line.tag}>`);
112
- } else {
113
- if (line.text) {
114
- const content = this.convertInlineKets(line.text);
115
- output.push(`${indent}<${line.tag}${attrs}>${content}</${line.tag}>`);
116
- } else {
117
- output.push(`${indent}<${line.tag}${attrs}/>`);
118
- }
119
- this.currentLine++;
120
- }
121
- continue;
122
- }
123
- if (line.type === "text") {
124
- const indent = " ".repeat(line.indent);
125
- const content = this.convertInlineKets(line.text || "");
126
- output.push(`${indent}${content}`);
127
- this.currentLine++;
128
- continue;
129
- }
130
- }
131
- }
132
- /**
133
- * Parse a single line into structured form
134
- */
135
- parseLine(raw) {
136
- const match = raw.match(/^(\s*)(.*)/);
137
- const indent = match ? Math.floor(match[1].length / 2) : 0;
138
- const content = match ? match[2] : "";
139
- if (!content.trim()) {
140
- return { indent, type: "empty", raw };
141
- }
142
- const braMatch = content.match(/^<([a-zA-Z_][a-zA-Z0-9_-]*)\s*([^|]*)\|$/);
143
- if (braMatch) {
144
- return {
145
- indent,
146
- type: "bra",
147
- tag: braMatch[1],
148
- attrs: braMatch[2].trim() || void 0,
149
- raw
150
- };
151
- }
152
- const ketMatch = content.match(/^\|([a-zA-Z_][a-zA-Z0-9_-]*)\s*([^>]*?)>\s*(.*)/);
153
- if (ketMatch) {
154
- return {
155
- indent,
156
- type: "ket",
157
- tag: ketMatch[1],
158
- attrs: ketMatch[2].trim() || void 0,
159
- text: ketMatch[3] || void 0,
160
- raw
161
- };
162
- }
163
- return {
164
- indent,
165
- type: "text",
166
- text: content,
167
- raw
168
- };
169
- }
170
- /**
171
- * Convert bra-ket attribute syntax to XML
172
- * Examples:
173
- * name=value → name="value"
174
- * x=5 y=10 → x="5" y="10"
175
- * select=@* → select="@*"
176
- */
177
- convertAttributes(attrs) {
178
- if (!attrs) return "";
179
- const parts = [];
180
- let current = "";
181
- let inQuotes = false;
182
- let quoteChar = "";
183
- for (let i = 0; i < attrs.length; i++) {
184
- const char = attrs[i];
185
- if ((char === '"' || char === "'") && (i === 0 || attrs[i - 1] !== "\\")) {
186
- if (!inQuotes) {
187
- inQuotes = true;
188
- quoteChar = char;
189
- current += char;
190
- } else if (char === quoteChar) {
191
- inQuotes = false;
192
- current += char;
193
- } else {
194
- current += char;
195
- }
196
- } else if (char === " " && !inQuotes) {
197
- if (current.trim()) {
198
- parts.push(current.trim());
199
- current = "";
200
- }
201
- } else {
202
- current += char;
203
- }
204
- }
205
- if (current.trim()) {
206
- parts.push(current.trim());
207
- }
208
- return parts.map((part) => {
209
- const match = part.match(/^([a-zA-Z_][a-zA-Z0-9_-]*)=(.+)$/);
210
- if (!match) return part;
211
- const [, name, value] = match;
212
- if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
213
- return `${name}=${value}`;
214
- }
215
- return `${name}="${value}"`;
216
- }).join(" ");
217
- }
218
- /**
219
- * Convert inline kets within text content
220
- * Example: "Hello |variable name=x> world" → "Hello <variable name="x"/> world"
221
- */
222
- convertInlineKets(text) {
223
- return text.replace(/\|([a-zA-Z_][a-zA-Z0-9_-]*)\s*([^>]*?)>/g, (match, tag, attrs) => {
224
- const attrStr = attrs.trim() ? ` ${this.convertAttributes(attrs.trim())}` : "";
225
- return `<${tag}${attrStr}/>`;
226
- });
227
- }
228
- };
229
-
230
- // src/cli.ts
231
69
  async function main() {
232
70
  const args = process.argv.slice(2);
233
71
  if (args.includes("--help") || args.includes("-h")) {
234
72
  console.log("Usage: dirac <file.di|file.bk>");
73
+ console.log(" dirac shell [options]");
74
+ console.log("");
75
+ console.log("Commands:");
76
+ console.log(" shell Start interactive shell (REPL)");
235
77
  console.log("");
236
78
  console.log("File formats:");
237
79
  console.log(" .di XML notation (verbose)");
@@ -245,14 +87,51 @@ async function main() {
245
87
  console.log(" --model <name> Set default LLM model");
246
88
  console.log(" --max-llm <n> Maximum LLM calls (default: 100)");
247
89
  console.log(" --max-depth <n> Maximum recursion depth (default: 50)");
90
+ console.log(" -f, --config <path> Path to config.yml file");
248
91
  process.exit(0);
249
92
  }
250
93
  if (args.includes("--version") || args.includes("-v")) {
251
94
  console.log(package_default.version);
252
95
  process.exit(0);
253
96
  }
97
+ if (args[0] === "shell") {
98
+ const { DiracShell } = await import("./shell-FHSPULIL.js");
99
+ const shellConfig = { debug: false };
100
+ for (let i = 1; i < args.length; i++) {
101
+ const arg = args[i];
102
+ if (arg === "--debug") {
103
+ shellConfig.debug = true;
104
+ } else if ((arg === "-f" || arg === "--config") && i + 1 < args.length) {
105
+ const configPath = resolve(args[++i]);
106
+ if (fs.existsSync(configPath)) {
107
+ const configData = yaml.load(fs.readFileSync(configPath, "utf-8"));
108
+ Object.assign(shellConfig, {
109
+ llmProvider: configData.llmProvider,
110
+ llmModel: configData.llmModel,
111
+ customLLMUrl: configData.customLLMUrl
112
+ });
113
+ }
114
+ }
115
+ }
116
+ if (!shellConfig.llmProvider) {
117
+ const defaultConfigPath = resolve(process.cwd(), "config.yml");
118
+ if (fs.existsSync(defaultConfigPath)) {
119
+ try {
120
+ const configData = yaml.load(fs.readFileSync(defaultConfigPath, "utf-8"));
121
+ shellConfig.llmProvider = shellConfig.llmProvider || configData.llmProvider;
122
+ shellConfig.llmModel = shellConfig.llmModel || configData.llmModel;
123
+ shellConfig.customLLMUrl = shellConfig.customLLMUrl || configData.customLLMUrl;
124
+ } catch (err) {
125
+ }
126
+ }
127
+ }
128
+ const shell = new DiracShell(shellConfig);
129
+ shell.start();
130
+ return;
131
+ }
254
132
  if (args.length === 0) {
255
133
  console.error("Usage: dirac <file.di|file.bk>");
134
+ console.error(" dirac shell [options]");
256
135
  console.error("Try dirac --help for more information.");
257
136
  process.exit(1);
258
137
  }
package/dist/index.d.ts CHANGED
@@ -94,6 +94,7 @@ interface DiracConfig {
94
94
  filePath?: string;
95
95
  llmProvider?: string;
96
96
  llmModel?: string;
97
+ customLLMUrl?: string;
97
98
  }
98
99
 
99
100
  /**
package/dist/index.js CHANGED
@@ -2,19 +2,19 @@ import {
2
2
  createLLMAdapter,
3
3
  execute,
4
4
  executeUserCommand
5
- } from "./chunk-UYDP4ZFS.js";
5
+ } from "./chunk-4LLFMVOW.js";
6
6
  import {
7
7
  integrate
8
- } from "./chunk-YRJ3SODI.js";
8
+ } from "./chunk-HPGONBNW.js";
9
9
  import {
10
10
  DiracParser
11
11
  } from "./chunk-HRHAMPOB.js";
12
- import "./chunk-JMUUPZZA.js";
12
+ import "./chunk-4QLTSCDG.js";
13
13
  import {
14
14
  createSession,
15
15
  getAvailableSubroutines,
16
16
  getOutput
17
- } from "./chunk-JIWLKB5O.js";
17
+ } from "./chunk-GLXVY235.js";
18
18
  export {
19
19
  DiracParser,
20
20
  createLLMAdapter,
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  integrate,
3
3
  integrateChildren
4
- } from "./chunk-YRJ3SODI.js";
4
+ } from "./chunk-HPGONBNW.js";
5
5
  import "./chunk-HRHAMPOB.js";
6
- import "./chunk-JMUUPZZA.js";
7
- import "./chunk-JIWLKB5O.js";
6
+ import "./chunk-4QLTSCDG.js";
7
+ import "./chunk-GLXVY235.js";
8
8
  export {
9
9
  integrate,
10
10
  integrateChildren
@@ -26,7 +26,7 @@ import {
26
26
  substituteVariables,
27
27
  throwException,
28
28
  unsetExceptionBoundary
29
- } from "./chunk-JIWLKB5O.js";
29
+ } from "./chunk-GLXVY235.js";
30
30
  export {
31
31
  cleanSubroutinesToBoundary,
32
32
  cleanToBoundary,
@@ -0,0 +1,290 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ BraKetParser
4
+ } from "./chunk-DRPHX3WX.js";
5
+ import {
6
+ integrate
7
+ } from "./chunk-HPGONBNW.js";
8
+ import {
9
+ DiracParser
10
+ } from "./chunk-HRHAMPOB.js";
11
+ import "./chunk-4QLTSCDG.js";
12
+ import {
13
+ createSession
14
+ } from "./chunk-GLXVY235.js";
15
+
16
+ // src/shell.ts
17
+ import * as readline from "readline";
18
+ import * as fs from "fs";
19
+ import * as path from "path";
20
+ import * as os from "os";
21
+ import yaml from "js-yaml";
22
+ var HISTORY_FILE = path.join(os.homedir(), ".dirac_history");
23
+ var MAX_HISTORY = 1e3;
24
+ var DiracShell = class {
25
+ session;
26
+ braketParser;
27
+ xmlParser;
28
+ rl;
29
+ inputBuffer = [];
30
+ baseIndent = null;
31
+ config;
32
+ constructor(config = {}) {
33
+ this.config = config;
34
+ this.session = createSession(config);
35
+ this.braketParser = new BraKetParser();
36
+ this.xmlParser = new DiracParser();
37
+ this.rl = readline.createInterface({
38
+ input: process.stdin,
39
+ output: process.stdout,
40
+ prompt: "> ",
41
+ historySize: MAX_HISTORY
42
+ });
43
+ this.loadHistory();
44
+ this.setupHandlers();
45
+ }
46
+ loadHistory() {
47
+ try {
48
+ if (fs.existsSync(HISTORY_FILE)) {
49
+ const history = fs.readFileSync(HISTORY_FILE, "utf-8").split("\n").filter((line) => line.trim()).slice(-MAX_HISTORY);
50
+ this.rl.history = history.reverse();
51
+ }
52
+ } catch (err) {
53
+ }
54
+ }
55
+ saveHistory() {
56
+ try {
57
+ const history = this.rl.history.slice().reverse().join("\n");
58
+ fs.writeFileSync(HISTORY_FILE, history, "utf-8");
59
+ } catch (err) {
60
+ }
61
+ }
62
+ setupHandlers() {
63
+ this.rl.on("line", async (input) => {
64
+ await this.handleInput(input);
65
+ });
66
+ this.rl.on("close", () => {
67
+ this.saveHistory();
68
+ console.log("\nGoodbye!");
69
+ process.exit(0);
70
+ });
71
+ this.rl.on("SIGINT", () => {
72
+ if (this.inputBuffer.length > 0) {
73
+ this.inputBuffer = [];
74
+ this.baseIndent = null;
75
+ console.log("\n(Input cancelled)");
76
+ this.rl.setPrompt("> ");
77
+ this.rl.prompt();
78
+ } else {
79
+ this.rl.close();
80
+ }
81
+ });
82
+ }
83
+ async handleInput(input) {
84
+ if (!this.inputBuffer.length && input.trim().startsWith(":")) {
85
+ await this.handleCommand(input.trim());
86
+ this.rl.prompt();
87
+ return;
88
+ }
89
+ const indent = this.getIndent(input);
90
+ if (this.inputBuffer.length === 0) {
91
+ this.inputBuffer.push(input);
92
+ this.baseIndent = indent;
93
+ if (this.needsContinuation(input)) {
94
+ this.rl.setPrompt("... ");
95
+ console.log(" (Press Enter on empty line to execute, or Ctrl+C to cancel)");
96
+ this.rl.prompt();
97
+ return;
98
+ }
99
+ } else {
100
+ if (input.trim() === "") {
101
+ await this.executeBuffer();
102
+ this.rl.setPrompt("> ");
103
+ this.rl.prompt();
104
+ return;
105
+ }
106
+ this.inputBuffer.push(input);
107
+ this.rl.setPrompt("... ");
108
+ this.rl.prompt();
109
+ return;
110
+ }
111
+ await this.executeBuffer();
112
+ this.rl.prompt();
113
+ }
114
+ getIndent(line) {
115
+ const match = line.match(/^(\s*)/);
116
+ return match ? match[1].length : 0;
117
+ }
118
+ needsContinuation(line) {
119
+ const trimmed = line.trim();
120
+ if (trimmed.match(/^<[a-zA-Z_][a-zA-Z0-9_-]*.*\|$/)) {
121
+ return true;
122
+ }
123
+ const ketMatch = trimmed.match(/^\|([a-zA-Z_][a-zA-Z0-9_-]*)\s*([^>]*?)>\s*(.*)$/);
124
+ if (ketMatch && !ketMatch[3]) {
125
+ return true;
126
+ }
127
+ return false;
128
+ }
129
+ async executeBuffer() {
130
+ if (this.inputBuffer.length === 0) return;
131
+ const input = this.inputBuffer.join("\n");
132
+ this.inputBuffer = [];
133
+ this.baseIndent = null;
134
+ try {
135
+ this.session.output = [];
136
+ const xml = this.braketParser.parse(input);
137
+ if (this.config.debug) {
138
+ console.log("[Debug] Generated XML:\n", xml);
139
+ }
140
+ const ast = this.xmlParser.parse(xml);
141
+ await integrate(this.session, ast);
142
+ if (this.session.output.length > 0) {
143
+ console.log(this.session.output.join(""));
144
+ }
145
+ } catch (error) {
146
+ console.error("Error:", error instanceof Error ? error.message : String(error));
147
+ if (this.config.debug && error instanceof Error && error.stack) {
148
+ console.error(error.stack);
149
+ }
150
+ }
151
+ }
152
+ async handleCommand(cmd) {
153
+ const parts = cmd.slice(1).split(/\s+/);
154
+ const command = parts[0];
155
+ const args = parts.slice(1);
156
+ switch (command) {
157
+ case "help":
158
+ console.log(`
159
+ Dirac Shell - Interactive REPL
160
+
161
+ Commands:
162
+ :help Show this help
163
+ :vars List all variables
164
+ :subs List all subroutines
165
+ :clear Clear session (reset variables and subroutines)
166
+ :debug Toggle debug mode
167
+ :config Show current configuration
168
+ :exit Exit shell
169
+
170
+ Syntax:
171
+ |tag attrs>text Ket notation (most tags)
172
+ <name| Bra notation (subroutine definitions)
173
+ |output>content Indented children
174
+
175
+ Multi-line Input:
176
+ - Type a line that needs continuation (like <greeting| or |llm>)
177
+ - Shell switches to '...' prompt
178
+ - Type your content lines (add spaces for indentation manually)
179
+ - Press ENTER on an empty line to execute
180
+ - Or press Ctrl+C to cancel
181
+
182
+ Note: You must manually add spaces for indentation (2 spaces per level)
183
+
184
+ Examples:
185
+ |output>Hello World
186
+ |defvar name=count value=5>
187
+ |llm>create a greeting subroutine
188
+ <greeting| name=String
189
+ |output>Hello |variable name=name>
190
+ |greeting name=World>
191
+ `);
192
+ break;
193
+ case "vars":
194
+ if (this.session.variables.length === 0) {
195
+ console.log("No variables defined");
196
+ } else {
197
+ console.log("Variables:");
198
+ for (const v of this.session.variables) {
199
+ if (v.visible) {
200
+ console.log(` ${v.name} = ${JSON.stringify(v.value)}`);
201
+ }
202
+ }
203
+ }
204
+ break;
205
+ case "subs":
206
+ if (this.session.subroutines.length === 0) {
207
+ console.log("No subroutines defined");
208
+ } else {
209
+ console.log("Subroutines:");
210
+ for (const s of this.session.subroutines) {
211
+ const params = s.parameters?.map((p) => p.name).join(", ") || "";
212
+ console.log(` ${s.name}(${params})`);
213
+ if (s.description) {
214
+ console.log(` ${s.description}`);
215
+ }
216
+ }
217
+ }
218
+ break;
219
+ case "clear":
220
+ this.session.variables = [];
221
+ this.session.subroutines = [];
222
+ this.session.varBoundary = 0;
223
+ this.session.subBoundary = 0;
224
+ console.log("Session cleared");
225
+ break;
226
+ case "debug":
227
+ this.config.debug = !this.config.debug;
228
+ this.session.debug = this.config.debug;
229
+ console.log(`Debug mode: ${this.config.debug ? "ON" : "OFF"}`);
230
+ break;
231
+ case "config":
232
+ console.log("Configuration:");
233
+ console.log(` LLM Provider: ${this.config.llmProvider || "none"}`);
234
+ console.log(` LLM Model: ${this.config.llmModel || "default"}`);
235
+ console.log(` Debug: ${this.config.debug ? "ON" : "OFF"}`);
236
+ if (this.config.customLLMUrl) {
237
+ console.log(` Custom LLM URL: ${this.config.customLLMUrl}`);
238
+ }
239
+ break;
240
+ case "exit":
241
+ case "quit":
242
+ this.rl.close();
243
+ break;
244
+ default:
245
+ console.log(`Unknown command: ${command}. Type :help for available commands.`);
246
+ }
247
+ }
248
+ start() {
249
+ console.log("Dirac Shell v0.1.0");
250
+ console.log("Type :help for commands, :exit to quit\n");
251
+ if (this.config.llmProvider) {
252
+ console.log(`LLM: ${this.config.llmProvider} (${this.config.llmModel || "default"})
253
+ `);
254
+ } else {
255
+ console.log("Warning: No LLM provider configured. Set LLM_PROVIDER environment variable.\n");
256
+ }
257
+ this.rl.prompt();
258
+ }
259
+ };
260
+ async function main() {
261
+ let config = {
262
+ debug: process.env.DEBUG === "1"
263
+ };
264
+ const configPath = path.join(process.cwd(), "config.yml");
265
+ if (fs.existsSync(configPath)) {
266
+ try {
267
+ const configData = yaml.load(fs.readFileSync(configPath, "utf-8"));
268
+ config = {
269
+ ...config,
270
+ llmProvider: configData.llmProvider || process.env.LLM_PROVIDER,
271
+ llmModel: configData.llmModel || process.env.LLM_MODEL,
272
+ customLLMUrl: configData.customLLMUrl || process.env.CUSTOM_LLM_URL
273
+ };
274
+ } catch (err) {
275
+ console.error("Warning: Could not load config.yml");
276
+ }
277
+ } else {
278
+ config.llmProvider = process.env.LLM_PROVIDER;
279
+ config.llmModel = process.env.LLM_MODEL;
280
+ config.customLLMUrl = process.env.CUSTOM_LLM_URL;
281
+ }
282
+ const shell = new DiracShell(config);
283
+ shell.start();
284
+ }
285
+ if (import.meta.url === `file://${process.argv[1]}`) {
286
+ main();
287
+ }
288
+ export {
289
+ DiracShell
290
+ };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  executeSubroutine
3
- } from "./chunk-JMUUPZZA.js";
4
- import "./chunk-JIWLKB5O.js";
3
+ } from "./chunk-4QLTSCDG.js";
4
+ import "./chunk-GLXVY235.js";
5
5
  export {
6
6
  executeSubroutine
7
7
  };
@@ -49,7 +49,7 @@ async function getBestTagMatch(candidate, allowed) {
49
49
  }
50
50
  async function validateTag(session, element, options = {}) {
51
51
  const { autocorrect = false, similarityCutoff = SIMILARITY_CUTOFF } = options;
52
- const { getAvailableSubroutines } = await import("./session-UIWHLPTR.js");
52
+ const { getAvailableSubroutines } = await import("./session-UBATJEND.js");
53
53
  const subroutines = getAvailableSubroutines(session);
54
54
  const allowed = new Set(subroutines.map((s) => s.name));
55
55
  const tagName = element.tag;
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  integrate
3
- } from "./chunk-YRJ3SODI.js";
3
+ } from "./chunk-HPGONBNW.js";
4
4
  import {
5
5
  DiracParser
6
6
  } from "./chunk-HRHAMPOB.js";
7
- import "./chunk-JMUUPZZA.js";
7
+ import "./chunk-4QLTSCDG.js";
8
8
  import {
9
9
  createSession,
10
10
  getOutput
11
- } from "./chunk-JIWLKB5O.js";
11
+ } from "./chunk-GLXVY235.js";
12
12
 
13
13
  // src/test-runner.ts
14
14
  import fs from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dirac-lang",
3
- "version": "0.1.32",
3
+ "version": "0.1.34",
4
4
  "description": "LLM-Augmented Declarative Execution",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",