progmune-runtime 2.0.2 → 2.1.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 (107) hide show
  1. package/.mcp.json +11 -0
  2. package/.progmune_allowlist +50 -0
  3. package/.test_report/test_report.md +87 -0
  4. package/Dockerfile +2 -10
  5. package/FAQ.md +167 -0
  6. package/demo-project/auth.ts +55 -0
  7. package/demo-project/tsconfig.json +8 -0
  8. package/dist/ab-stats.js +11 -0
  9. package/dist/acl-breakdown.js +13 -0
  10. package/dist/all-sessions.js +11 -0
  11. package/dist/antibody-stats.js +11 -0
  12. package/dist/audit.js +218 -0
  13. package/dist/benchmark-count.js +7 -0
  14. package/dist/benchmark-full.js +17 -0
  15. package/dist/benchmark-pass-rate.js +54 -0
  16. package/dist/benchmark-report.js +67 -0
  17. package/dist/benchmark-save.js +62 -0
  18. package/dist/benchmark-status.js +15 -0
  19. package/dist/branch-ledger.js +365 -0
  20. package/dist/branch-tree-count.js +14 -0
  21. package/dist/check.js +506 -0
  22. package/dist/common-fixpath.js +12 -0
  23. package/dist/constraint-types.js +12 -0
  24. package/dist/deterministic-replay.js +277 -0
  25. package/dist/emitter.js +112 -12
  26. package/dist/exec-metrics.js +11 -0
  27. package/dist/execute.js +242 -0
  28. package/dist/extract-ir.js +550 -5
  29. package/dist/failure-collector.js +143 -0
  30. package/dist/failure-corpus.js +481 -35
  31. package/dist/failure-report.js +11 -0
  32. package/dist/failures.js +11 -0
  33. package/dist/fast-path-hits.js +13 -0
  34. package/dist/feedback.js +6 -3
  35. package/dist/file-lock.js +82 -0
  36. package/dist/find-session.js +10 -0
  37. package/dist/fingerprint-list.js +15 -0
  38. package/dist/gen-history-log.js +13 -0
  39. package/dist/generate.js +2 -1
  40. package/dist/generate_500.js +4 -2
  41. package/dist/genome.js +11 -0
  42. package/dist/heatmap-data.js +11 -0
  43. package/dist/heatmap.js +11 -0
  44. package/dist/immune-reporter.js +137 -0
  45. package/dist/learned.js +11 -0
  46. package/dist/ledger-registry.js +241 -0
  47. package/dist/llm.js +43 -2
  48. package/dist/load-benchmarks.js +47 -0
  49. package/dist/main.js +2 -1
  50. package/dist/mcp-server.mjs +446 -34
  51. package/dist/memory-layer.js +51 -13
  52. package/dist/metrics.js +11 -0
  53. package/dist/obs-web.js +561 -0
  54. package/dist/p0_ssg_demo.js +255 -40
  55. package/dist/planner.js +933 -65
  56. package/dist/protocol-registry.js +105 -0
  57. package/dist/recent-session.js +12 -0
  58. package/dist/repair-proposal.js +353 -0
  59. package/dist/report.js +32 -0
  60. package/dist/runtime-invariants.js +161 -0
  61. package/dist/runtime-types.js +117 -0
  62. package/dist/search-planner.js +38 -9
  63. package/dist/semantic-snapshot.js +155 -0
  64. package/dist/semantic-trace.js +1497 -0
  65. package/dist/semantic-validator.js +3 -2
  66. package/dist/semantic_guard_test.js +2 -1
  67. package/dist/sessions.js +11 -0
  68. package/dist/ssg-validator.js +658 -20
  69. package/dist/svl-distribution.js +11 -0
  70. package/dist/terminal-status.js +11 -0
  71. package/dist/test_failure_corpus.js +3 -1
  72. package/dist/token-savings.js +11 -0
  73. package/dist/total-repairs.js +12 -0
  74. package/dist/unresolved-count.js +12 -0
  75. package/dist/valid-fingerprints.js +13 -0
  76. package/dist/validator.js +116 -60
  77. package/dist/verify-fps.js +11 -0
  78. package/dist/verify-ledgers.js +11 -0
  79. package/docs/whitepaper-style.css +77 -0
  80. package/docs/whitepaper-v2.1.md +609 -0
  81. package/docs/whitepaper-v2.2.md +1064 -0
  82. package/docs/whitepaper-v2.2.pdf +0 -0
  83. package/fly.toml +1 -1
  84. package/package.json +13 -4
  85. package/protocols.json +136 -0
  86. package/public/dashboard.html +119 -0
  87. package/readme.md +829 -0
  88. package/server/hub.js +84 -12
  89. package/test/replay-golden/sess_1780063202050_mgeld.json +9 -0
  90. package/test/replay-golden/sess_1780064032560_gocld.json +354 -0
  91. package/test/replay-golden/sess_1780064413331_s2709.json +606 -0
  92. package/test/replay-golden/sess_1780064792710_y3avo.json +614 -0
  93. package/test/replay-golden.ts +84 -0
  94. package/test_benchmark.js +165 -0
  95. package/test_comprehensive.mjs +638 -0
  96. package/test_concurrency.js +129 -0
  97. package/test_ir_robustness.js +85 -0
  98. package/test_semantic_contracts.js +269 -0
  99. package/test_ssg_stress.js +156 -0
  100. package/test_svl3.js +58 -0
  101. package/tsconfig.json +1 -1
  102. package/.env.example +0 -3
  103. package/.progmune_memory/fingerprints.json +0 -7
  104. package/.progmune_memory/opt_in.json +0 -4
  105. package/README.md +0 -118
  106. package/dist/mcp-server.js +0 -55
  107. package/immune_hub_data/2026-05-14.json +0 -50
@@ -0,0 +1,277 @@
1
+ "use strict";
2
+ /**
3
+ * Phase 4: Deterministic Replay (P1)
4
+ *
5
+ * Verifies that replaying a session's ledger against current rules
6
+ * produces the same result as the stored execution certificate.
7
+ *
8
+ * Answers: "Would this execution produce the same result today?"
9
+ * Not just "read the log" — actively re-validates every transition.
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.replaySession = replaySession;
46
+ exports.replayLedger = replayLedger;
47
+ exports.replayWithDetail = replayWithDetail;
48
+ const fs = __importStar(require("fs"));
49
+ const path = __importStar(require("path"));
50
+ const ledger_registry_1 = require("./ledger-registry");
51
+ const protocol_registry_1 = require("./protocol-registry");
52
+ const ssg_validator_1 = require("./ssg-validator");
53
+ const branch_ledger_1 = require("./branch-ledger");
54
+ // ── Core Replay ──
55
+ /** Replay a session from disk, comparing against its stored fingerprint. */
56
+ function replaySession(sessionId, currentRules, namespaceInitialStates = (0, protocol_registry_1.getNsInit)()) {
57
+ // Load session
58
+ const sessionsDir = path.resolve(process.env.PROGMUNE_PROJECT_DIR || process.cwd(), ".progmune_corpus/sessions");
59
+ const sessionFile = path.join(sessionsDir, `${sessionId}.json`);
60
+ if (!fs.existsSync(sessionFile)) {
61
+ return {
62
+ success: false,
63
+ sessionId,
64
+ finalState: {},
65
+ replayedHash: "",
66
+ storedHash: "",
67
+ ruleHashMatch: false,
68
+ ledgerHashMatch: false,
69
+ totalTransitions: 0,
70
+ validTransitions: 0,
71
+ invalidTransitions: 0,
72
+ divergencePoint: 0,
73
+ divergenceDetail: `Session file not found: ${sessionFile}`,
74
+ };
75
+ }
76
+ const session = JSON.parse(fs.readFileSync(sessionFile, "utf-8"));
77
+ // Collect all transitions
78
+ let transitions = [];
79
+ let sessionRuleHash = session.ruleHash || "";
80
+ // Handle branch tree if present (Phase 4)
81
+ if (session.branchTree && session.branchTree.length > 0) {
82
+ const branches = session.branchTree;
83
+ const map = (0, branch_ledger_1.buildBranchMap)(branches);
84
+ const root = (0, branch_ledger_1.findRootBranch)(branches);
85
+ if (root) {
86
+ transitions = (0, branch_ledger_1.flattenBranch)(root, map);
87
+ }
88
+ // Use first attempt's ruleHash as session hash
89
+ if (!sessionRuleHash && branches[0]?.transitions[0]?.ruleHash) {
90
+ sessionRuleHash = branches[0].transitions[0].ruleHash;
91
+ }
92
+ }
93
+ else {
94
+ // Legacy: collect from attempts
95
+ for (const attempt of (session.attempts || [])) {
96
+ if (attempt.transitions) {
97
+ transitions = transitions.concat(attempt.transitions);
98
+ }
99
+ if (!sessionRuleHash && (attempt.ruleHash || session.ruleHash)) {
100
+ sessionRuleHash = attempt.ruleHash || session.ruleHash;
101
+ }
102
+ }
103
+ }
104
+ // Load fingerprint
105
+ const fingerprint = (0, ledger_registry_1.getFingerprint)(sessionId);
106
+ const storedHash = fingerprint?.ledgerHash || "";
107
+ // Compute current rule hash
108
+ let currentRuleHash = "";
109
+ if (currentRules && currentRules.size > 0) {
110
+ currentRuleHash = (0, ssg_validator_1.hashRules)(currentRules);
111
+ }
112
+ return replayLedger(sessionId, transitions, sessionRuleHash, storedHash, currentRuleHash, currentRules, namespaceInitialStates);
113
+ }
114
+ /** Core replay logic: replay transitions against (optional) current rules. */
115
+ function replayLedger(sessionId, transitions, storedRuleHash, storedLedgerHash, currentRuleHash, currentRules, namespaceInitialStates = (0, protocol_registry_1.getNsInit)()) {
116
+ const replayedHash = transitions.length > 0 ? (0, ssg_validator_1.hashLedger)(transitions) : "";
117
+ const ruleHashMatch = !currentRuleHash || !storedRuleHash
118
+ ? true // can't compare if either is missing
119
+ : currentRuleHash === storedRuleHash;
120
+ const ledgerHashMatch = !storedLedgerHash
121
+ ? true // no fingerprint to compare against
122
+ : replayedHash === storedLedgerHash;
123
+ // Replay each transition if we have current rules
124
+ let validTransitions = 0;
125
+ let invalidTransitions = 0;
126
+ let divergencePoint;
127
+ let divergenceDetail;
128
+ if (currentRules && currentRules.size > 0) {
129
+ const ctx = {
130
+ ledger: [],
131
+ currentState: (0, ssg_validator_1.rebuildState)([], namespaceInitialStates),
132
+ };
133
+ for (let i = 0; i < transitions.length; i++) {
134
+ const t = transitions[i];
135
+ if (!t.valid) {
136
+ invalidTransitions++;
137
+ continue;
138
+ }
139
+ try {
140
+ // Re-validate against current rules
141
+ const { valid, transition } = (0, ssg_validator_1.validateTransition)(ctx, t.function, i, currentRules, namespaceInitialStates, currentRuleHash || "");
142
+ if (!valid && divergencePoint === undefined) {
143
+ divergencePoint = i;
144
+ divergenceDetail = `Transition[${i}] "${t.function}" is no longer valid under current rules.`;
145
+ }
146
+ // Check statesBefore matches rebuilt state
147
+ const rebuiltBefore = ctx.currentState;
148
+ const beforeMatch = deepEqualSnapshots(rebuiltBefore, t.statesBefore);
149
+ if (!beforeMatch && divergencePoint === undefined) {
150
+ divergencePoint = i;
151
+ divergenceDetail = `Transition[${i}] "${t.function}" statesBefore mismatch: rebuilt=${JSON.stringify(rebuiltBefore[t.namespace] || [])} recorded=${JSON.stringify(t.statesBefore[t.namespace] || [])}`;
152
+ }
153
+ if (valid) {
154
+ validTransitions++;
155
+ ctx.ledger.push(transition);
156
+ ctx.currentState = transition.statesAfter;
157
+ }
158
+ else {
159
+ invalidTransitions++;
160
+ ctx.ledger.push({ ...t, valid: false });
161
+ }
162
+ }
163
+ catch {
164
+ invalidTransitions++;
165
+ if (divergencePoint === undefined) {
166
+ divergencePoint = i;
167
+ divergenceDetail = `Transition[${i}] "${t.function}" threw an error during replay. Rule may have changed.`;
168
+ }
169
+ }
170
+ }
171
+ }
172
+ else {
173
+ // No current rules: just verify structural consistency
174
+ const consistency = (0, ssg_validator_1.checkLedgerConsistency)(transitions, namespaceInitialStates);
175
+ if (!consistency.consistent) {
176
+ divergencePoint = consistency.violations[0]?.index;
177
+ divergenceDetail = `Structural inconsistency: ${consistency.violations.length} violation(s). First: [${consistency.violations[0]?.invariant}] at index ${consistency.violations[0]?.index}`;
178
+ }
179
+ validTransitions = transitions.filter(t => t.valid).length;
180
+ invalidTransitions = transitions.filter(t => !t.valid).length;
181
+ }
182
+ // Compute final state
183
+ const finalState = transitions.length > 0
184
+ ? (0, ssg_validator_1.rebuildState)(transitions.filter(t => t.valid), namespaceInitialStates)
185
+ : {};
186
+ const success = ruleHashMatch && ledgerHashMatch && divergencePoint === undefined;
187
+ return {
188
+ success,
189
+ sessionId,
190
+ finalState,
191
+ divergencePoint,
192
+ divergenceDetail,
193
+ replayedHash,
194
+ storedHash: storedLedgerHash,
195
+ ruleHashMatch,
196
+ ledgerHashMatch,
197
+ totalTransitions: transitions.length,
198
+ validTransitions,
199
+ invalidTransitions,
200
+ };
201
+ }
202
+ /** Replay with per-transition detail — for debugging and UI. */
203
+ function replayWithDetail(transitions, currentRules, namespaceInitialStates = (0, protocol_registry_1.getNsInit)()) {
204
+ if (!currentRules || currentRules.size === 0) {
205
+ return transitions.map(t => ({
206
+ index: t.actionIndex,
207
+ function: t.function,
208
+ namespace: t.namespace,
209
+ originalValid: t.valid,
210
+ replayValid: t.valid,
211
+ statesBeforeMatch: true,
212
+ statesAfterMatch: true,
213
+ }));
214
+ }
215
+ const ctx = {
216
+ ledger: [],
217
+ currentState: (0, ssg_validator_1.rebuildState)([], namespaceInitialStates),
218
+ };
219
+ const currentRuleHash = (0, ssg_validator_1.hashRules)(currentRules);
220
+ const results = [];
221
+ for (let i = 0; i < transitions.length; i++) {
222
+ const t = transitions[i];
223
+ const result = {
224
+ index: t.actionIndex,
225
+ function: t.function,
226
+ namespace: t.namespace,
227
+ originalValid: t.valid,
228
+ replayValid: false,
229
+ statesBeforeMatch: false,
230
+ statesAfterMatch: false,
231
+ };
232
+ if (!t.valid) {
233
+ result.detail = "Originally invalid";
234
+ results.push(result);
235
+ continue;
236
+ }
237
+ try {
238
+ const { valid, transition } = (0, ssg_validator_1.validateTransition)(ctx, t.function, i, currentRules, namespaceInitialStates, currentRuleHash);
239
+ result.replayValid = valid;
240
+ result.statesBeforeMatch = deepEqualSnapshots(ctx.currentState, t.statesBefore);
241
+ result.statesAfterMatch = valid
242
+ ? deepEqualSnapshots(transition.statesAfter, t.statesAfter)
243
+ : false;
244
+ if (!result.statesBeforeMatch) {
245
+ result.detail = `statesBefore mismatch`;
246
+ }
247
+ else if (!result.statesAfterMatch) {
248
+ result.detail = `statesAfter mismatch`;
249
+ }
250
+ else if (!valid) {
251
+ result.detail = `No longer valid under current rules`;
252
+ }
253
+ ctx.ledger.push(valid ? transition : { ...t, valid: false });
254
+ ctx.currentState = valid ? transition.statesAfter : ctx.currentState;
255
+ }
256
+ catch (e) {
257
+ result.replayValid = false;
258
+ result.detail = `Error: ${e.message?.slice(0, 80)}`;
259
+ }
260
+ results.push(result);
261
+ }
262
+ return results;
263
+ }
264
+ // ── Helpers ──
265
+ function deepEqualSnapshots(a, b) {
266
+ const keysA = Object.keys(a).sort();
267
+ const keysB = Object.keys(b).sort();
268
+ if (keysA.length !== keysB.length)
269
+ return false;
270
+ for (const k of keysA) {
271
+ if (!b[k])
272
+ return false;
273
+ if (a[k].join(",") !== b[k].join(","))
274
+ return false;
275
+ }
276
+ return true;
277
+ }
package/dist/emitter.js CHANGED
@@ -39,11 +39,44 @@ const BASIC_TYPES = new Set([
39
39
  "string", "number", "boolean", "any", "void", "undefined", "null",
40
40
  "str", "int", "float", "bool", "list", "dict", "tuple", "bytes",
41
41
  ]);
42
+ /** Normalize a type string to an importable type name.
43
+ * Strips [], <...>, unions, and typeof expressions.
44
+ * e.g. "StateTransition[]" → "StateTransition"
45
+ * "Map<string, string>" → "Map"
46
+ * "Action | null" → "Action"
47
+ * "ReturnType<typeof fn>" → null (complex, skip) */
48
+ function normalizeTypeName(raw) {
49
+ let t = raw.trim();
50
+ // Skip function types and complex expressions
51
+ if (t.includes("=>") || t.includes("typeof"))
52
+ return null;
53
+ // Strip array brackets
54
+ t = t.replace(/\[\]/g, "");
55
+ // Strip generic parameters
56
+ t = t.replace(/<[^>]*>/g, "");
57
+ // Take first part of union/intersection
58
+ t = t.split("|")[0].split("&")[0].trim();
59
+ // Must be a simple identifier
60
+ if (/^[A-Z][a-zA-Z0-9_]*$/.test(t))
61
+ return t;
62
+ return null;
63
+ }
42
64
  function getImportPath(file) {
43
- return "./" + file.replace(/\.ts$|\.tsx$/, "");
65
+ // Normalize: strip common src/ prefix since generated code lives in src/
66
+ let clean = file.replace(/\.ts$|\.tsx$/, "");
67
+ if (clean.startsWith("src/"))
68
+ clean = clean.slice(4);
69
+ return "./" + clean;
44
70
  }
45
- function emitCode(actions) {
46
- const ir = JSON.parse(fs.readFileSync("ir.json", "utf-8"));
71
+ /**
72
+ * 将动作序列编译为目标语言代码。
73
+ * @protocol namespace=dev_pipeline pre_states=["SEQUENCE_VALIDATED"] post_states=["CODE_EMITTED"] invalidate=["SEQUENCE_VALIDATED"]
74
+ */
75
+ function emitCode(actions, meta) {
76
+ const irRaw = JSON.parse(fs.readFileSync("ir.json", "utf-8"));
77
+ // Support both old format (array) and new format ({typeMap, functions})
78
+ const typeMap = irRaw.typeMap || {};
79
+ const ir = irRaw.functions || irRaw;
47
80
  const fnIndex = new Map();
48
81
  const fnMeta = new Map();
49
82
  for (const f of ir) {
@@ -56,16 +89,21 @@ function emitCode(actions) {
56
89
  if (action.kind === "call" && action.function) {
57
90
  const file = fnIndex.get(action.function);
58
91
  const meta = fnMeta.get(action.function);
59
- if (file) {
92
+ // Skip external functions — they are global/standard library (fs, path, etc.)
93
+ // Skip non-exported functions — can't import what isn't exported
94
+ if (file && file !== "(external)" && meta?.exported !== false) {
60
95
  if (!imports.has(file))
61
96
  imports.set(file, new Set());
62
97
  imports.get(file).add(action.function);
63
98
  if (meta?.params) {
64
99
  for (const p of meta.params) {
65
- if (!BASIC_TYPES.has(p.type)) {
66
- if (!typeImports.has(file))
67
- typeImports.set(file, new Set());
68
- typeImports.get(file).add(p.type);
100
+ const normalized = normalizeTypeName(p.type);
101
+ if (normalized && !BASIC_TYPES.has(normalized)) {
102
+ // Use typeMap to find the correct module for this type
103
+ const typeFile = typeMap[normalized] || file;
104
+ if (!typeImports.has(typeFile))
105
+ typeImports.set(typeFile, new Set());
106
+ typeImports.get(typeFile).add(normalized);
69
107
  }
70
108
  }
71
109
  }
@@ -81,14 +119,63 @@ function emitCode(actions) {
81
119
  };
82
120
  for (const a of actions)
83
121
  collect(a);
122
+ // ── Generation marker (provable usage) ──
84
123
  let code = "";
124
+ if (meta?.sessionId) {
125
+ const ts = new Date().toISOString();
126
+ code += `// @progmune-generated session=${meta.sessionId} timestamp=${ts}`;
127
+ if (meta.ruleHash)
128
+ code += ` ruleHash=${meta.ruleHash}`;
129
+ code += `\n`;
130
+ const funcs = meta.irFunctionCount ?? ir.length;
131
+ const rules = meta.protocolRuleCount ?? 0;
132
+ code += `// Generated with IR constraint: ${funcs} functions`;
133
+ if (rules > 0)
134
+ code += `, ${rules} protocol rules`;
135
+ code += `\n`;
136
+ }
85
137
  for (const [file, funcSet] of imports)
86
138
  code += `import { ${[...funcSet].join(", ")} } from "${getImportPath(file)}";\n`;
87
139
  for (const [file, typeSet] of typeImports)
88
140
  code += `import type { ${[...typeSet].join(", ")} } from "${getImportPath(file)}";\n`;
89
- code += "\nexport function main() {\n";
141
+ // Pre-scan: find input variables (referenced but never assigned via call/assign)
90
142
  const declared = new Set();
143
+ const referenced = new Set();
91
144
  let counter = 0;
145
+ // First pass: collect declared and referenced variables
146
+ for (const action of actions) {
147
+ if (action.kind === "call" && action.assignTo) {
148
+ declared.add(action.assignTo);
149
+ }
150
+ else if (action.kind === "assign" && action.target) {
151
+ declared.add(action.target);
152
+ }
153
+ // Collect arg value references
154
+ if (action.kind === "call" && action.args) {
155
+ for (const arg of action.args) {
156
+ const v = typeof arg === "object" ? arg?.value : arg;
157
+ if (typeof v === "string" && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(v) && v !== "") {
158
+ referenced.add(v);
159
+ }
160
+ }
161
+ }
162
+ }
163
+ // Inputs = referenced but not declared — add as typed parameters
164
+ const inputs = [...referenced].filter(v => !declared.has(v) && v !== "");
165
+ const inputTypes = new Map();
166
+ for (const action of actions) {
167
+ if (action.kind === "call" && action.args) {
168
+ for (const arg of action.args) {
169
+ const v = typeof arg === "object" ? arg?.value : arg;
170
+ const t = typeof arg === "object" ? arg?.type : "string";
171
+ if (typeof v === "string" && inputs.includes(v) && t && t !== "any") {
172
+ inputTypes.set(v, t);
173
+ }
174
+ }
175
+ }
176
+ }
177
+ const paramList = inputs.map(v => `${v}: ${inputTypes.get(v) || "string"}`).join(", ");
178
+ code += `\nexport function main(${paramList}) {\n`;
92
179
  const convert = (action, indent = " ") => {
93
180
  if (!action || !action.kind)
94
181
  return "";
@@ -103,15 +190,20 @@ function emitCode(actions) {
103
190
  const val = a?.value;
104
191
  if (typeof val === "string" && declared.has(val))
105
192
  return val;
193
+ // If value looks like a variable name (valid JS identifier), pass it through
194
+ if (typeof val === "string" && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(val) && val !== "") {
195
+ declared.add(val);
196
+ return val;
197
+ }
106
198
  const paramType = meta?.params?.[i]?.type || "any";
107
199
  if (BASIC_TYPES.has(paramType)) {
108
200
  if (paramType === "string" || paramType === "str")
109
- return `"defaultStr"`;
201
+ return `""`;
110
202
  if (paramType === "number" || paramType === "int" || paramType === "float")
111
203
  return "0";
112
204
  if (paramType === "boolean" || paramType === "bool")
113
205
  return "false";
114
- return `"default"`;
206
+ return `""`;
115
207
  }
116
208
  if (paramType === "UserPayload")
117
209
  return `{ id: 1, role: "user" } as UserPayload`;
@@ -161,6 +253,14 @@ function emitCode(actions) {
161
253
  };
162
254
  for (const a of actions)
163
255
  code += convert(a) + "\n";
164
- code += "}\nmain();\n";
256
+ code += "}\n";
257
+ // Call main with params if it has inputs, otherwise no-arg call
258
+ if (inputs.length > 0) {
259
+ // Don't call — the user provides the arguments
260
+ // Just export the function for external use
261
+ }
262
+ else {
263
+ code += "main();\n";
264
+ }
165
265
  return code;
166
266
  }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.main = main;
4
+ // @progmune-generated session=sess_1780343438004_ux6bt timestamp=2026-06-01T19:50:39.415Z ruleHash=9dec68bc2995e92a
5
+ // Generated with IR constraint: 385 functions, 17 protocol rules
6
+ const execute_1 = require("./execute");
7
+ function main() {
8
+ const metrics = (0, execute_1.getExecutionMetrics)();
9
+ return metrics;
10
+ }
11
+ main();