dotdog 0.6.0 → 0.7.1

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.
Files changed (2) hide show
  1. package/dist/cli.js +91 -9
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -2684,14 +2684,15 @@ import { homedir as homedir2 } from "os";
2684
2684
  function parse(source) {
2685
2685
  const lines = source.split(`
2686
2686
  `);
2687
- const sections = parseSections(lines);
2688
- return { kind: "document", sections };
2687
+ const errors2 = [];
2688
+ const sections = parseSections(lines, errors2);
2689
+ return { kind: "document", sections, errors: errors2 };
2689
2690
  }
2690
2691
  function parseToJSON(source) {
2691
2692
  const ast = parse(source);
2692
2693
  return JSON.stringify(ast, null, 2);
2693
2694
  }
2694
- function parseSections(lines) {
2695
+ function parseSections(lines, errors2) {
2695
2696
  const sections = [];
2696
2697
  let i = 0;
2697
2698
  let firstHeading = lines.length;
@@ -2701,7 +2702,7 @@ function parseSections(lines) {
2701
2702
  break;
2702
2703
  }
2703
2704
  }
2704
- const rootBlocks = parseBlocks(lines, 0, firstHeading);
2705
+ const rootBlocks = parseBlocks(lines, 0, firstHeading, errors2);
2705
2706
  if (rootBlocks.length > 0) {
2706
2707
  sections.push({
2707
2708
  kind: "section",
@@ -2722,7 +2723,7 @@ function parseSections(lines) {
2722
2723
  const sectionStart = i;
2723
2724
  i++;
2724
2725
  const end = findSectionEnd(lines, i, level);
2725
- const blocks = parseBlocks(lines, sectionStart, end);
2726
+ const blocks = parseBlocks(lines, sectionStart, end, errors2);
2726
2727
  sections.push({
2727
2728
  kind: "section",
2728
2729
  level,
@@ -2746,7 +2747,7 @@ function findSectionEnd(lines, start, currentLevel) {
2746
2747
  }
2747
2748
  return lines.length;
2748
2749
  }
2749
- function parseBlocks(lines, start, end) {
2750
+ function parseBlocks(lines, start, end, errors2) {
2750
2751
  const blocks = [];
2751
2752
  let i = start;
2752
2753
  while (i < end) {
@@ -2793,7 +2794,15 @@ function parseBlocks(lines, start, end) {
2793
2794
  yamlEnd++;
2794
2795
  if (yamlEnd < end) {
2795
2796
  const yamlContent = lines.slice(i + 1, yamlEnd);
2796
- const yaml = parseSimpleYAML(yamlContent);
2797
+ let yaml;
2798
+ try {
2799
+ yaml = parseSimpleYAML(yamlContent);
2800
+ } catch (e) {
2801
+ if (errors2)
2802
+ errors2.push({ message: `YAML parse error: ${e.message}`, line: i + 1, context: lines[i - 1]?.trim() || "(unknown)" });
2803
+ i = yamlEnd + 1;
2804
+ continue;
2805
+ }
2797
2806
  if (yaml.prediction) {
2798
2807
  blocks.push({
2799
2808
  kind: "prediction",
@@ -2878,7 +2887,15 @@ function parseBlocks(lines, start, end) {
2878
2887
  yamlEnd++;
2879
2888
  if (yamlEnd < end && yamlEnd > i + 1) {
2880
2889
  const yamlContent = lines.slice(i + 1, yamlEnd);
2881
- const yaml = parseSimpleYAML(yamlContent);
2890
+ let yaml;
2891
+ try {
2892
+ yaml = parseSimpleYAML(yamlContent);
2893
+ } catch (e) {
2894
+ if (errors2)
2895
+ errors2.push({ message: `YAML parse error: ${e.message}`, line: i + 1, context: lines[i - 1]?.trim() || "(unknown)" });
2896
+ i = yamlEnd + 1;
2897
+ continue;
2898
+ }
2882
2899
  const key = yaml.prediction ? "prediction" : yaml.entity ? "entity" : yaml.event ? "event" : yaml.relationship || yaml.verb ? "relationship" : null;
2883
2900
  if (key) {
2884
2901
  if (key === "prediction") {
@@ -2962,7 +2979,17 @@ function parseStructuredBlock(lines, start, end, kind, headerRest) {
2962
2979
  i++;
2963
2980
  }
2964
2981
  i++;
2965
- const yaml = parseSimpleYAML(yamlLines);
2982
+ let yaml = {};
2983
+ try {
2984
+ yaml = parseSimpleYAML(yamlLines);
2985
+ } catch (e) {
2986
+ if (errors)
2987
+ errors.push({ message: `YAML parse error: ${e.message}`, line: start + 1, context: `${kind}: ${headerRest}` });
2988
+ return {
2989
+ node: { kind: "entity", name: headerRest, description, type: "node", properties: {}, states: [], lifecycle: [], yaml: {}, lineStart: start + 1, lineEnd: i },
2990
+ nextLine: i
2991
+ };
2992
+ }
2966
2993
  if (kind === "entity") {
2967
2994
  return {
2968
2995
  node: buildEntityNode(headerRest, description, yaml, start, i),
@@ -4675,6 +4702,61 @@ kitCmd.command("init <kit>").description("Init a project from a kit").option("-p
4675
4702
  Kit "${kit}" initialized in specs/${projectName}/`));
4676
4703
  console.log(source_default.gray(` Run: dotdog validate`));
4677
4704
  });
4705
+ program2.command("badge [dir]").description("Generate dotdog-badge.svg (shields.io style) showing savings").action((d = ".") => {
4706
+ const dir = resolvePath2(d);
4707
+ const dirs = [join3(dir, "projects"), join3(dir, "specs"), dir];
4708
+ let found = false;
4709
+ for (const dd of dirs) {
4710
+ if (!existsSync3(dd))
4711
+ continue;
4712
+ const projects = readdirSync3(dd, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
4713
+ for (const p of projects) {
4714
+ const pd = join3(dd, p);
4715
+ const dagFile = join3(pd, `${p}.dag`);
4716
+ if (!existsSync3(join3(pd, "SPEC.dog")))
4717
+ continue;
4718
+ if (!existsSync3(dagFile)) {
4719
+ console.log(source_default.red(` No .dag for ${p}. Run dotdog compile first.`));
4720
+ continue;
4721
+ }
4722
+ const dag = JSON.parse(readFileSync3(dagFile, "utf-8"));
4723
+ const saved = dag.tk && dag.tk.saved ? dag.tk.saved : 0;
4724
+ const fmt = saved >= 1000 ? `${(saved / 1000).toFixed(1)}K` : `${saved}`;
4725
+ const label = "dotdog";
4726
+ const value = `${fmt} tokens saved`;
4727
+ const pct = dag.tk && dag.tk.sv ? dag.tk.sv : 0;
4728
+ const color = pct > 90 ? "#4c1" : pct > 70 ? "#dfb317" : "#e05d44";
4729
+ const labelLen = Math.round(label.length * 7.2);
4730
+ const valueLen = Math.round(value.length * 7.2);
4731
+ const leftW = Math.max(labelLen + 10, 70);
4732
+ const rightW = Math.max(valueLen + 10, 40);
4733
+ const totalW = leftW + rightW;
4734
+ const leftX = leftW / 2 * 10;
4735
+ const rightX = (leftW + rightW / 2) * 10;
4736
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${totalW}" height="20" role="img" aria-label="${label}: ${value}">
4737
+ <title>${label}: ${value}</title>
4738
+ <linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient>
4739
+ <clipPath id="r"><rect width="${totalW}" height="20" rx="3" fill="#fff"/></clipPath>
4740
+ <g clip-path="url(#r)">
4741
+ <rect width="${leftW}" height="20" fill="#555"/>
4742
+ <rect x="${leftW}" width="${rightW}" height="20" fill="${color}"/>
4743
+ <rect width="${totalW}" height="20" fill="url(#s)"/>
4744
+ </g>
4745
+ <g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110">
4746
+ <g transform="scale(.1)">
4747
+ <text x="${leftX}" y="140" textLength="${labelLen * 10}">${label}</text>
4748
+ <text x="${rightX}" y="140" textLength="${valueLen * 10}">${value}</text>
4749
+ </g>
4750
+ </g>
4751
+ </svg>`;
4752
+ writeFileSync2(join3(dir, "dotdog-badge.svg"), svg);
4753
+ console.log(source_default.green(` ✓ dotdog-badge.svg (${label}: ${value})`));
4754
+ found = true;
4755
+ }
4756
+ }
4757
+ if (!found)
4758
+ console.log(source_default.yellow("No projects found. Run dotdog init first."));
4759
+ });
4678
4760
  program2.parse();
4679
4761
  export {
4680
4762
  parseToJSON,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dotdog",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "description": "CLI tool for structured software specifications. Validate .dog files, compile .dag graphs, query via MCP.",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",