dotdog 0.7.0 → 0.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.
Files changed (2) hide show
  1. package/dist/cli.js +57 -17
  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),
@@ -3582,20 +3609,31 @@ program2.command("init <project>").option("-m, --minimal", "Only SPEC.dog + data
3582
3609
  console.log(source_default.bold(`
3583
3610
  Project "${p}" initialized. Fill in SPEC.dog then run spec validate.`));
3584
3611
  });
3585
- program2.command("list").action(() => {
3612
+ program2.command("list").option("--json", "Output project names as JSON").action((opts) => {
3613
+ const entries = [];
3586
3614
  for (const d of ["projects", "specs"]) {
3587
3615
  const dd = join3(process.cwd(), d);
3588
3616
  if (!existsSync3(dd))
3589
3617
  continue;
3590
3618
  const projects = readdirSync3(dd, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
3619
+ for (const p of projects) {
3620
+ const sp = join3(dd, p);
3621
+ const n = existsSync3(sp) ? readdirSync3(sp).filter((f) => f.endsWith(".dog")).length : 0;
3622
+ entries.push({ root: d, name: p, dogFiles: n });
3623
+ }
3624
+ }
3625
+ if (opts.json) {
3626
+ console.log(JSON.stringify(entries.map((e) => e.name)));
3627
+ return;
3628
+ }
3629
+ for (const d of ["projects", "specs"]) {
3630
+ const projects = entries.filter((e) => e.root === d);
3591
3631
  if (!projects.length)
3592
3632
  continue;
3593
3633
  console.log(source_default.bold(`
3594
3634
  ${d}/`));
3595
3635
  for (const p of projects) {
3596
- const sp = join3(dd, p);
3597
- const n = existsSync3(sp) ? readdirSync3(sp).filter((f) => f.endsWith(".dog")).length : 0;
3598
- console.log(` ${source_default.cyan(p)} : ${n} .dog files`);
3636
+ console.log(` ${source_default.cyan(p.name)} : ${p.dogFiles} .dog files`);
3599
3637
  }
3600
3638
  }
3601
3639
  });
@@ -4693,10 +4731,12 @@ program2.command("badge [dir]").description("Generate dotdog-badge.svg (shields.
4693
4731
  continue;
4694
4732
  }
4695
4733
  const dag = JSON.parse(readFileSync3(dagFile, "utf-8"));
4696
- const savings = dag.tk && dag.tk.sv ? Math.round(dag.tk.sv) : 0;
4697
- const label = "spec savings";
4698
- const value = `${savings}%`;
4699
- const color = savings > 90 ? "#4c1" : savings > 70 ? "#dfb317" : "#e05d44";
4734
+ const saved = dag.tk && dag.tk.saved ? dag.tk.saved : 0;
4735
+ const fmt = saved >= 1000 ? `${(saved / 1000).toFixed(1)}K` : `${saved}`;
4736
+ const label = "dotdog";
4737
+ const value = `${fmt} tokens saved`;
4738
+ const pct = dag.tk && dag.tk.sv ? dag.tk.sv : 0;
4739
+ const color = pct > 90 ? "#4c1" : pct > 70 ? "#dfb317" : "#e05d44";
4700
4740
  const labelLen = Math.round(label.length * 7.2);
4701
4741
  const valueLen = Math.round(value.length * 7.2);
4702
4742
  const leftW = Math.max(labelLen + 10, 70);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dotdog",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
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",