progmune-runtime 2.1.1 → 2.1.2

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/emitter.js CHANGED
@@ -152,13 +152,19 @@ function emitCode(actions, meta) {
152
152
  else if (action.kind === "assign" && action.target) {
153
153
  declared.add(action.target);
154
154
  }
155
- // Collect arg value references
155
+ // Collect arg value references AND empty-default params
156
156
  if (action.kind === "call" && action.args) {
157
157
  for (const arg of action.args) {
158
158
  const v = typeof arg === "object" ? arg?.value : arg;
159
159
  if (typeof v === "string" && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(v) && v !== "") {
160
160
  referenced.add(v);
161
161
  }
162
+ // Also detect empty defaults: these should become function params
163
+ const isDefault = v === "" || v === 0 || v === false || v === null
164
+ || (Array.isArray(v) && v.length === 0);
165
+ if (isDefault && typeof arg === "object" && arg.name) {
166
+ referenced.add(arg.name);
167
+ }
162
168
  }
163
169
  }
164
170
  }
@@ -169,10 +175,40 @@ function emitCode(actions, meta) {
169
175
  if (action.kind === "call" && action.args) {
170
176
  for (const arg of action.args) {
171
177
  const v = typeof arg === "object" ? arg?.value : arg;
178
+ const n = typeof arg === "object" ? arg?.name : undefined;
172
179
  const t = typeof arg === "object" ? arg?.type : "string";
180
+ // Variable reference: value matches input name
173
181
  if (typeof v === "string" && inputs.includes(v) && t && t !== "any") {
174
182
  inputTypes.set(v, t);
175
183
  }
184
+ // Empty default: param name matches input name
185
+ const isDefault = v === "" || v === 0 || v === false || v === null
186
+ || (Array.isArray(v) && v.length === 0);
187
+ if (isDefault && n && inputs.includes(n)) {
188
+ const cleanType = (t || "string").replace(/\[\]$/, "");
189
+ if (!inputTypes.has(n))
190
+ inputTypes.set(n, cleanType);
191
+ }
192
+ }
193
+ }
194
+ }
195
+ // If no inputs detected but functions have params with empty defaults,
196
+ // create parameters from function signatures
197
+ if (inputs.length === 0) {
198
+ for (const action of actions) {
199
+ if (action.kind === "call" && action.args && action.args.length > 0) {
200
+ for (const arg of action.args) {
201
+ const name = typeof arg === "object" ? arg.name : "param";
202
+ const type = typeof arg === "object" ? (arg.type || "string") : "string";
203
+ const val = typeof arg === "object" ? arg.value : arg;
204
+ // Only add if value is empty default (not a real value)
205
+ if (val === "" || val === 0 || val === false || val === null || (Array.isArray(val) && val.length === 0)) {
206
+ if (!inputTypes.has(name)) {
207
+ inputs.push(name);
208
+ inputTypes.set(name, type.replace(/\[\]$/, ""));
209
+ }
210
+ }
211
+ }
176
212
  }
177
213
  }
178
214
  }
@@ -192,11 +228,17 @@ function emitCode(actions, meta) {
192
228
  const val = a?.value;
193
229
  if (typeof val === "string" && declared.has(val))
194
230
  return val;
195
- // If value looks like a variable name (valid JS identifier), pass it through
196
231
  if (typeof val === "string" && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(val) && val !== "") {
197
232
  declared.add(val);
198
233
  return val;
199
234
  }
235
+ // Empty default value → use function's parameter name (input parameter)
236
+ const isDefault = val === "" || val === 0 || val === false || val === null
237
+ || (Array.isArray(val) && val.length === 0);
238
+ if (isDefault && a?.name && inputs.includes(a.name)) {
239
+ declared.add(a.name);
240
+ return a.name;
241
+ }
200
242
  const paramType = meta?.params?.[i]?.type || "any";
201
243
  if (BASIC_TYPES.has(paramType)) {
202
244
  if (paramType === "string" || paramType === "str")
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeHealthScore = computeHealthScore;
4
+ exports.formatHealthLevel = formatHealthLevel;
5
+ exports.countSessionLedgers = countSessionLedgers;
6
+ /** Compute overall immune health score from failure and antibody data.
7
+ * @requires FAILURE_GENOME @produces HEALTH_SCORE
8
+ * @tags health, score, immune
9
+ */
10
+ function computeHealthScore(failureGenome, antibodyStats) {
11
+ const totalFailures = failureGenome?.totalFailures || 0;
12
+ const totalHits = antibodyStats?.totalHits || 0;
13
+ const base = 100;
14
+ const failurePenalty = Math.min(totalFailures * 2, 40);
15
+ const antibodyBonus = Math.min(totalHits * 3, 20);
16
+ return Math.max(0, Math.min(100, base - failurePenalty + antibodyBonus));
17
+ }
18
+ /** Format a health score as a status level.
19
+ * @requires HEALTH_SCORE @produces HEALTH_STATUS
20
+ * @tags health, format
21
+ */
22
+ function formatHealthLevel(score) {
23
+ if (score >= 90)
24
+ return "Excellent";
25
+ if (score >= 70)
26
+ return "Good";
27
+ if (score >= 50)
28
+ return "Fair";
29
+ return "Poor";
30
+ }
31
+ /** Validate a ledger and return pass/fail counts.
32
+ * @requires SESSION_LIST @produces VALIDATION_COUNTS
33
+ * @tags ledger, validation, audit
34
+ */
35
+ function countSessionLedgers(sessions) {
36
+ const withLedger = sessions.filter((s) => {
37
+ return s.attempts?.some((a) => a.transitions?.length > 0);
38
+ }).length;
39
+ return { total: sessions.length, withLedger };
40
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.countTotalTransitions = countTotalTransitions;
4
+ exports.formatTransitionCount = formatTransitionCount;
5
+ exports.hasViolations = hasViolations;
6
+ exports.countSessionsWithViolations = countSessionsWithViolations;
7
+ /** Count total transitions across all session ledgers.
8
+ * @requires SESSION_LIST @produces TRANSITION_COUNT
9
+ * @tags ledger, count, statistics
10
+ */
11
+ function countTotalTransitions(sessions) {
12
+ let count = 0;
13
+ for (const s of sessions) {
14
+ for (const a of (s.attempts || [])) {
15
+ count += (a.transitions || []).length;
16
+ }
17
+ }
18
+ return count;
19
+ }
20
+ /** Format a transition count as a summary string.
21
+ * @requires TRANSITION_COUNT @produces FORMATTED_COUNT
22
+ * @tags ledger, format
23
+ */
24
+ function formatTransitionCount(count) {
25
+ return `${count} total transitions across all sessions`;
26
+ }
27
+ /** Check if a session has any protocol violations in its attempts.
28
+ * @requires SESSION_DATA @produces VIOLATION_CHECK
29
+ * @tags ledger, validation
30
+ */
31
+ function hasViolations(session) {
32
+ return (session.attempts || []).some((a) => (a.violations || []).length > 0);
33
+ }
34
+ /** Count sessions that have violations.
35
+ * @requires SESSION_LIST @produces VIOLATION_COUNT
36
+ * @tags ledger, validation, statistics
37
+ */
38
+ function countSessionsWithViolations(sessions) {
39
+ return sessions.filter(s => hasViolations(s)).length;
40
+ }
package/dist/stdlib.js ADDED
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ /**
3
+ * Progmune Standard Library — general-purpose utilities for external tasks.
4
+ * Each function has @requires/@produces for Capability Graph integration.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.isValidEmail = isValidEmail;
8
+ exports.truncate = truncate;
9
+ exports.camelToSnake = camelToSnake;
10
+ exports.capitalizeWords = capitalizeWords;
11
+ exports.countSubstring = countSubstring;
12
+ exports.removeWhitespace = removeWhitespace;
13
+ exports.mostFrequent = mostFrequent;
14
+ exports.unique = unique;
15
+ exports.chunk = chunk;
16
+ exports.arrayDiff = arrayDiff;
17
+ exports.average = average;
18
+ exports.median = median;
19
+ exports.roundTo = roundTo;
20
+ exports.isPrime = isPrime;
21
+ exports.randomInt = randomInt;
22
+ exports.deepClone = deepClone;
23
+ exports.pick = pick;
24
+ exports.deepMerge = deepMerge;
25
+ exports.hasRequiredFields = hasRequiredFields;
26
+ exports.isPlainObject = isPlainObject;
27
+ exports.parseSemver = parseSemver;
28
+ exports.formatDuration = formatDuration;
29
+ exports.formatFileSize = formatFileSize;
30
+ exports.toQueryString = toQueryString;
31
+ exports.retry = retry;
32
+ exports.debounce = debounce;
33
+ // ── String ──
34
+ /** @requires STRING @produces VALIDATION_RESULT @tags string, email, validation */
35
+ function isValidEmail(str) {
36
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(str);
37
+ }
38
+ /** @requires STRING @produces TRUNCATED_STRING @tags string, format */
39
+ function truncate(str, maxLen, ellipsis = "...") {
40
+ return str.length <= maxLen ? str : str.slice(0, maxLen - ellipsis.length) + ellipsis;
41
+ }
42
+ /** @requires STRING @produces FORMATTED_STRING @tags string, case, format */
43
+ function camelToSnake(str) {
44
+ return str.replace(/[A-Z]/g, (c) => "_" + c.toLowerCase());
45
+ }
46
+ /** @requires STRING @produces FORMATTED_STRING @tags string, case, format */
47
+ function capitalizeWords(str) {
48
+ return str.replace(/\b\w/g, (c) => c.toUpperCase());
49
+ }
50
+ /** @requires STRING @produces COUNT @tags string, count */
51
+ function countSubstring(str, sub) {
52
+ if (!sub)
53
+ return 0;
54
+ let count = 0, pos = 0;
55
+ while ((pos = str.indexOf(sub, pos)) !== -1) {
56
+ count++;
57
+ pos += sub.length;
58
+ }
59
+ return count;
60
+ }
61
+ /** @requires STRING @produces CLEANED_STRING @tags string, format */
62
+ function removeWhitespace(str) {
63
+ return str.replace(/\s+/g, "");
64
+ }
65
+ // ── Array ──
66
+ /** @requires ARRAY @produces ELEMENT @tags array, statistics */
67
+ function mostFrequent(arr) {
68
+ if (arr.length === 0)
69
+ return null;
70
+ const counts = new Map();
71
+ for (const item of arr)
72
+ counts.set(item, (counts.get(item) || 0) + 1);
73
+ return [...counts.entries()].sort((a, b) => b[1] - a[1])[0][0];
74
+ }
75
+ /** @requires ARRAY @produces ARRAY @tags array, dedupe */
76
+ function unique(arr) { return [...new Set(arr)]; }
77
+ /** @requires ARRAY @produces ARRAY @tags array, chunk */
78
+ function chunk(arr, size) {
79
+ const result = [];
80
+ for (let i = 0; i < arr.length; i += size)
81
+ result.push(arr.slice(i, i + size));
82
+ return result;
83
+ }
84
+ /** @requires ARRAY @produces ARRAY @tags array, difference */
85
+ function arrayDiff(a, b) {
86
+ const setB = new Set(b);
87
+ return a.filter(x => !setB.has(x));
88
+ }
89
+ // ── Math ──
90
+ /** @requires NUMBERS @produces AVERAGE @tags math, statistics */
91
+ function average(nums) {
92
+ return nums.length === 0 ? 0 : nums.reduce((a, b) => a + b, 0) / nums.length;
93
+ }
94
+ /** @requires NUMBERS @produces MEDIAN @tags math, statistics */
95
+ function median(nums) {
96
+ if (nums.length === 0)
97
+ return 0;
98
+ const sorted = [...nums].sort((a, b) => a - b);
99
+ const mid = Math.floor(sorted.length / 2);
100
+ return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
101
+ }
102
+ /** @requires NUMBER @produces ROUNDED_NUMBER @tags math, format */
103
+ function roundTo(num, decimals) {
104
+ const factor = Math.pow(10, decimals);
105
+ return Math.round(num * factor) / factor;
106
+ }
107
+ /** @requires NUMBER @produces PRIME_CHECK @tags math, validation */
108
+ function isPrime(n) {
109
+ if (n < 2)
110
+ return false;
111
+ for (let i = 2; i <= Math.sqrt(n); i++)
112
+ if (n % i === 0)
113
+ return false;
114
+ return true;
115
+ }
116
+ /** @requires NUMBERS @produces RANDOM_INT @tags math, random */
117
+ function randomInt(min, max) {
118
+ return Math.floor(Math.random() * (max - min + 1)) + min;
119
+ }
120
+ // ── Object ──
121
+ /** @requires OBJECT @produces CLONED_OBJECT @tags object, clone */
122
+ function deepClone(obj) {
123
+ return JSON.parse(JSON.stringify(obj));
124
+ }
125
+ /** @requires OBJECT @produces PICKED_OBJECT @tags object, filter */
126
+ function pick(obj, keys) {
127
+ const result = {};
128
+ for (const k of keys)
129
+ if (k in obj)
130
+ result[k] = obj[k];
131
+ return result;
132
+ }
133
+ /** @requires OBJECTS @produces MERGED_OBJECT @tags object, merge */
134
+ function deepMerge(...objects) {
135
+ return objects.reduce((acc, obj) => {
136
+ for (const key of Object.keys(obj || {})) {
137
+ acc[key] = typeof obj[key] === "object" && !Array.isArray(obj[key])
138
+ ? deepMerge(acc[key] || {}, obj[key]) : obj[key];
139
+ }
140
+ return acc;
141
+ }, {});
142
+ }
143
+ // ── Validation ──
144
+ /** @requires OBJECT @produces VALIDATION_RESULT @tags validation, schema */
145
+ function hasRequiredFields(obj, fields) {
146
+ return fields.every(f => obj && obj[f] !== undefined && obj[f] !== null);
147
+ }
148
+ /** @requires ANY @produces VALIDATION_RESULT @tags validation, type */
149
+ function isPlainObject(val) {
150
+ return val !== null && typeof val === "object" && !Array.isArray(val);
151
+ }
152
+ /** @requires STRING @produces PARSED_VERSION @tags validation, semver */
153
+ function parseSemver(version) {
154
+ const match = version.match(/^(\d+)\.(\d+)\.(\d+)/);
155
+ if (!match)
156
+ return null;
157
+ return { major: +match[1], minor: +match[2], patch: +match[3] };
158
+ }
159
+ // ── Formatting ──
160
+ /** @requires NUMBER @produces FORMATTED_STRING @tags format, duration */
161
+ function formatDuration(ms) {
162
+ if (ms < 1000)
163
+ return `${ms}ms`;
164
+ if (ms < 60000)
165
+ return `${(ms / 1000).toFixed(1)}s`;
166
+ const mins = Math.floor(ms / 60000);
167
+ const secs = Math.round((ms % 60000) / 1000);
168
+ return `${mins}m ${secs}s`;
169
+ }
170
+ /** @requires NUMBER @produces FORMATTED_STRING @tags format, file */
171
+ function formatFileSize(bytes) {
172
+ if (bytes < 1024)
173
+ return `${bytes}B`;
174
+ if (bytes < 1048576)
175
+ return `${(bytes / 1024).toFixed(1)}KB`;
176
+ return `${(bytes / 1048576).toFixed(1)}MB`;
177
+ }
178
+ /** @requires OBJECT @produces QUERY_STRING @tags web, format */
179
+ function toQueryString(obj) {
180
+ return Object.entries(obj)
181
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
182
+ .join("&");
183
+ }
184
+ // ── Async ──
185
+ /** @requires FUNCTION @produces RETRY_RESULT @tags async, retry */
186
+ async function retry(fn, maxRetries = 3) {
187
+ for (let i = 0; i < maxRetries; i++) {
188
+ try {
189
+ return await fn();
190
+ }
191
+ catch (e) {
192
+ if (i === maxRetries - 1)
193
+ throw e;
194
+ }
195
+ }
196
+ throw new Error("unreachable");
197
+ }
198
+ /** @requires FUNCTION @produces DEBOUNCED_FUNCTION @tags async, debounce */
199
+ function debounce(fn, delay) {
200
+ let timer;
201
+ return ((...args) => {
202
+ clearTimeout(timer);
203
+ timer = setTimeout(() => fn(...args), delay);
204
+ });
205
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "progmune-runtime",
3
- "version": "2.1.1",
3
+ "version": "2.1.2",
4
4
  "description": "Progmune Runtime — Program Immunology: Constraint-Guided Program Synthesis Runtime",
5
5
  "main": "dist/mcp-server.mjs",
6
6
  "bin": {