musubix2 0.5.62 → 0.5.63

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.
@@ -1 +1 @@
1
- {"generator":"musubix2","version":"0.5.62","timestamp":"2026-07-10T20:40:37.368Z"}
1
+ {"generator":"musubix2","version":"0.5.63","timestamp":"2026-07-10T20:51:46.354Z"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "1.0",
3
- "generatedAt": "2026-07-10T20:40:37.396Z",
3
+ "generatedAt": "2026-07-10T20:51:46.385Z",
4
4
  "entries": [
5
5
  {
6
6
  "platform": "copilot",
package/dist/cli.js CHANGED
@@ -2808,7 +2808,8 @@ var init_design = __esm({
2808
2808
  if (reqs.length === 1) {
2809
2809
  const r = reqs[0];
2810
2810
  const sig = deriveMethodSignature(r.text, r.title);
2811
- const compName = this.pascal(r.title || sig.name) + (/(service|manager|controller|repository)$/i.test(r.title) ? "" : "Service");
2811
+ const base = this.pascal(r.title) || this.pascal(sig.name) || "Component";
2812
+ const compName = base + (/(service|manager|controller|repository)$/i.test(base) ? "" : "Service");
2812
2813
  return [{
2813
2814
  name: compName,
2814
2815
  responsibility: r.title || `Handle ${r.id}`,
@@ -2863,12 +2864,10 @@ var init_design = __esm({
2863
2864
  }
2864
2865
  return [...entities];
2865
2866
  }
2867
+ /** PascalCase the ASCII words of a string; returns '' if none survive (e.g. a
2868
+ * fully non-ASCII title), so callers can fall back to another name source. */
2866
2869
  pascal(text) {
2867
- const words = text.split(/[\s_\-,、]+/).filter(Boolean);
2868
- if (words.length === 0) {
2869
- return "Component";
2870
- }
2871
- return words.map((w) => w.replace(/[^A-Za-z0-9]/g, "")).filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
2870
+ return text.split(/[\s_\-,、]+/).map((w) => w.replace(/[^A-Za-z0-9]/g, "")).filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
2872
2871
  }
2873
2872
  suggestInterfaces(reqs) {
2874
2873
  const interfaces = [];
@@ -12785,7 +12784,7 @@ var init_dist14 = __esm({
12785
12784
  mockSolve(smtScript) {
12786
12785
  const start = Date.now();
12787
12786
  try {
12788
- if (smtScript.includes("(assert false)")) {
12787
+ if (smtScript.includes("(assert false)") || this.hasBooleanContradiction(smtScript)) {
12789
12788
  return {
12790
12789
  status: "unsat",
12791
12790
  time: Date.now() - start
@@ -12810,6 +12809,38 @@ var init_dist14 = __esm({
12810
12809
  };
12811
12810
  }
12812
12811
  }
12812
+ /**
12813
+ * Detect a basic Boolean contradiction without a real solver: an atom that is
12814
+ * *unconditionally* forced both true and false. Covers the common EARS cases —
12815
+ * `SHALL X` (`(=> true X)` or `(assert X)`) versus `SHALL NOT X`
12816
+ * (`(not X)`) — so `verify` flags e.g. "grant access" / "not grant access".
12817
+ * Conditional assertions (`(=> cond X)` with cond ≠ true) are not forcing and
12818
+ * are ignored. This is a sound-but-incomplete check (real z3 covers the rest).
12819
+ */
12820
+ hasBooleanContradiction(smtScript) {
12821
+ const forced = /* @__PURE__ */ new Map();
12822
+ let contradiction = false;
12823
+ const set = (atom, value) => {
12824
+ if (forced.has(atom) && forced.get(atom) !== value) {
12825
+ contradiction = true;
12826
+ }
12827
+ forced.set(atom, value);
12828
+ };
12829
+ for (const raw of smtScript.split("\n")) {
12830
+ const line = raw.trim();
12831
+ let m;
12832
+ if (m = /^\(assert \(=> true \(not (\w+)\)\)\)$/.exec(line)) {
12833
+ set(m[1], false);
12834
+ } else if (m = /^\(assert \(=> true (\w+)\)\)$/.exec(line)) {
12835
+ set(m[1], true);
12836
+ } else if (m = /^\(assert \(not (\w+)\)\)$/.exec(line)) {
12837
+ set(m[1], false);
12838
+ } else if (m = /^\(assert (\w+)\)$/.exec(line)) {
12839
+ set(m[1], true);
12840
+ }
12841
+ }
12842
+ return contradiction;
12843
+ }
12813
12844
  };
12814
12845
  PreconditionVerifier = class {
12815
12846
  async verify(requirement, converter, solver) {
package/dist/index.js CHANGED
@@ -2808,7 +2808,8 @@ var init_design = __esm({
2808
2808
  if (reqs.length === 1) {
2809
2809
  const r = reqs[0];
2810
2810
  const sig = deriveMethodSignature(r.text, r.title);
2811
- const compName = this.pascal(r.title || sig.name) + (/(service|manager|controller|repository)$/i.test(r.title) ? "" : "Service");
2811
+ const base = this.pascal(r.title) || this.pascal(sig.name) || "Component";
2812
+ const compName = base + (/(service|manager|controller|repository)$/i.test(base) ? "" : "Service");
2812
2813
  return [{
2813
2814
  name: compName,
2814
2815
  responsibility: r.title || `Handle ${r.id}`,
@@ -2863,12 +2864,10 @@ var init_design = __esm({
2863
2864
  }
2864
2865
  return [...entities];
2865
2866
  }
2867
+ /** PascalCase the ASCII words of a string; returns '' if none survive (e.g. a
2868
+ * fully non-ASCII title), so callers can fall back to another name source. */
2866
2869
  pascal(text) {
2867
- const words = text.split(/[\s_\-,、]+/).filter(Boolean);
2868
- if (words.length === 0) {
2869
- return "Component";
2870
- }
2871
- return words.map((w) => w.replace(/[^A-Za-z0-9]/g, "")).filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
2870
+ return text.split(/[\s_\-,、]+/).map((w) => w.replace(/[^A-Za-z0-9]/g, "")).filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
2872
2871
  }
2873
2872
  suggestInterfaces(reqs) {
2874
2873
  const interfaces = [];
@@ -12785,7 +12784,7 @@ var init_dist14 = __esm({
12785
12784
  mockSolve(smtScript) {
12786
12785
  const start = Date.now();
12787
12786
  try {
12788
- if (smtScript.includes("(assert false)")) {
12787
+ if (smtScript.includes("(assert false)") || this.hasBooleanContradiction(smtScript)) {
12789
12788
  return {
12790
12789
  status: "unsat",
12791
12790
  time: Date.now() - start
@@ -12810,6 +12809,38 @@ var init_dist14 = __esm({
12810
12809
  };
12811
12810
  }
12812
12811
  }
12812
+ /**
12813
+ * Detect a basic Boolean contradiction without a real solver: an atom that is
12814
+ * *unconditionally* forced both true and false. Covers the common EARS cases —
12815
+ * `SHALL X` (`(=> true X)` or `(assert X)`) versus `SHALL NOT X`
12816
+ * (`(not X)`) — so `verify` flags e.g. "grant access" / "not grant access".
12817
+ * Conditional assertions (`(=> cond X)` with cond ≠ true) are not forcing and
12818
+ * are ignored. This is a sound-but-incomplete check (real z3 covers the rest).
12819
+ */
12820
+ hasBooleanContradiction(smtScript) {
12821
+ const forced = /* @__PURE__ */ new Map();
12822
+ let contradiction = false;
12823
+ const set = (atom, value) => {
12824
+ if (forced.has(atom) && forced.get(atom) !== value) {
12825
+ contradiction = true;
12826
+ }
12827
+ forced.set(atom, value);
12828
+ };
12829
+ for (const raw of smtScript.split("\n")) {
12830
+ const line = raw.trim();
12831
+ let m;
12832
+ if (m = /^\(assert \(=> true \(not (\w+)\)\)\)$/.exec(line)) {
12833
+ set(m[1], false);
12834
+ } else if (m = /^\(assert \(=> true (\w+)\)\)$/.exec(line)) {
12835
+ set(m[1], true);
12836
+ } else if (m = /^\(assert \(not (\w+)\)\)$/.exec(line)) {
12837
+ set(m[1], false);
12838
+ } else if (m = /^\(assert (\w+)\)$/.exec(line)) {
12839
+ set(m[1], true);
12840
+ }
12841
+ }
12842
+ return contradiction;
12843
+ }
12813
12844
  };
12814
12845
  PreconditionVerifier = class {
12815
12846
  async verify(requirement, converter, solver) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musubix2",
3
- "version": "0.5.62",
3
+ "version": "0.5.63",
4
4
  "description": "MUSUBIX2 — Specification Driven Development System",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",