@o-lang/olang 1.0.16 → 1.0.17

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/cli.js +45 -33
  2. package/package.json +1 -1
package/cli.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  const { Command } = require('commander');
3
3
  const { parse } = require('./src/parser');
4
4
  const { execute } = require('./src/runtime');
@@ -22,7 +22,6 @@ function ensureOlExtension(filename) {
22
22
  */
23
23
  async function defaultMockResolver(action, context) {
24
24
  if (!action || typeof action !== 'string') return `[Unhandled: ${String(action)}]`;
25
-
26
25
  if (action.startsWith('Search for ')) {
27
26
  return {
28
27
  title: "HR Policy 2025",
@@ -30,45 +29,38 @@ async function defaultMockResolver(action, context) {
30
29
  url: "mock://hr-policy"
31
30
  };
32
31
  }
33
-
34
32
  if (action.startsWith('Ask ')) {
35
- return "✅ [Mock] Summarized for demonstration.";
33
+ return " [Mock] Summarized for demonstration.";
36
34
  }
37
-
38
35
  if (action.startsWith('Notify ')) {
39
36
  const recipient = action.match(/Notify (\S+)/)?.[1] || 'user@example.com';
40
- return `📬 Notification sent to ${recipient}`;
37
+ return ` 📬 Notification sent to ${recipient}`;
41
38
  }
42
-
43
39
  if (action.startsWith('Debrief ') || action.startsWith('Evolve ')) {
44
40
  console.log(`[O-Lang] ${action}`);
45
41
  return 'Acknowledged';
46
42
  }
47
-
48
43
  return `[Unhandled: ${action}]`;
49
44
  }
45
+ defaultMockResolver.resolverName = 'defaultMockResolver';
50
46
 
51
47
  /**
52
48
  * Built-in Math Resolver
53
49
  */
54
50
  async function builtInMathResolver(action, context) {
55
51
  if (!action || typeof action !== 'string') return null;
56
-
57
52
  const a = action.replace(/\{([^\}]+)\}/g, (_, k) => {
58
53
  const v = context[k.trim()];
59
54
  return v !== undefined ? v : `{${k}}`;
60
55
  });
61
-
62
56
  let m;
63
57
  m = a.match(/^add\(([^,]+),\s*([^)]+)\)$/i); if (m) return parseFloat(m[1]) + parseFloat(m[2]);
64
58
  m = a.match(/^subtract\(([^,]+),\s*([^)]+)\)$/i); if (m) return parseFloat(m[1]) - parseFloat(m[2]);
65
59
  m = a.match(/^multiply\(([^,]+),\s*([^)]+)\)$/i); if (m) return parseFloat(m[1]) * parseFloat(m[2]);
66
60
  m = a.match(/^divide\(([^,]+),\s*([^)]+)\)$/i); if (m) return parseFloat(m[1]) / parseFloat(m[2]);
67
61
  m = a.match(/^sum\(\s*\[([^\]]+)\]\s*\)$/i); if (m) return m[1].split(',').map(s => parseFloat(s.trim())).reduce((s, v) => s + v, 0);
68
-
69
62
  return null;
70
63
  }
71
- // Add resolver metadata so workflow policy recognizes it
72
64
  builtInMathResolver.resolverName = 'builtInMathResolver';
73
65
 
74
66
  /**
@@ -84,7 +76,7 @@ function createResolverChain(resolvers, verbose = false) {
84
76
  context[`__resolver_${i}`] = res;
85
77
  lastResult = res;
86
78
  } catch (e) {
87
- console.error(`❌ Resolver ${i} failed for action "${action}":`, e.message);
79
+ console.error(` Resolver ${i} failed for action "${action}":`, e.message);
88
80
  }
89
81
  }
90
82
  if (verbose) console.log(`[Resolver Chain] action="${action}" lastResult=`, lastResult);
@@ -96,17 +88,16 @@ function createResolverChain(resolvers, verbose = false) {
96
88
 
97
89
  function loadSingleResolver(specifier) {
98
90
  if (!specifier) return defaultMockResolver;
99
-
100
91
  try {
101
92
  const resolver = require(specifier);
102
93
  if (typeof resolver !== 'function') throw new Error(`Resolver must export a function`);
103
- console.log(`📦 Loaded resolver: ${specifier}`);
94
+ console.log(` 📦 Loaded resolver: ${specifier}`);
104
95
  return resolver;
105
96
  } catch (e1) {
106
97
  try {
107
98
  const absolutePath = path.resolve(process.cwd(), specifier);
108
99
  const resolver = require(absolutePath);
109
- console.log(`📁 Loaded resolver: ${absolutePath}`);
100
+ console.log(` 📁 Loaded resolver: ${absolutePath}`);
110
101
  return resolver;
111
102
  } catch (e2) {
112
103
  throw new Error(
@@ -117,16 +108,40 @@ function loadSingleResolver(specifier) {
117
108
  }
118
109
 
119
110
  /**
120
- * loadResolverChain: include built-in math resolver first, then user resolvers, then default mock resolver
111
+ * POLICY-AWARE resolver loader: only includes resolvers in allowedResolvers
121
112
  */
122
- function loadResolverChain(specifiers, verbose = false) {
113
+ function loadResolverChain(specifiers, verbose = false, allowedResolvers = new Set()) {
123
114
  const userResolvers = specifiers?.map(loadSingleResolver) || [];
124
- const resolvers = [builtInMathResolver, ...userResolvers, defaultMockResolver];
115
+ const resolvers = [];
125
116
 
126
- if (!specifiers || specifiers.length === 0) {
127
- console.log('ℹ️ No resolver provided. Using built-in math + default mock resolver.');
117
+ // Only add builtInMathResolver if allowed
118
+ if (allowedResolvers.has('builtInMathResolver')) {
119
+ resolvers.push(builtInMathResolver);
120
+ }
121
+
122
+ // Add user resolvers only if their name is allowed
123
+ for (const r of userResolvers) {
124
+ const name = r.resolverName || r.name || 'unknown';
125
+ if (allowedResolvers.has(name)) {
126
+ resolvers.push(r);
127
+ } else if (verbose) {
128
+ console.warn(` ⚠️ Skipping disallowed user resolver: ${name}`);
129
+ }
130
+ }
131
+
132
+ // Only add defaultMockResolver if explicitly allowed
133
+ if (allowedResolvers.has('defaultMockResolver')) {
134
+ resolvers.push(defaultMockResolver);
135
+ }
136
+
137
+ if (resolvers.length === 0) {
138
+ if (verbose) {
139
+ console.warn(' ⚠️ No allowed resolvers loaded. Actions may fail.');
140
+ }
128
141
  } else {
129
- console.log(`📦 Loaded user resolvers: ${specifiers.join(', ')}`);
142
+ if (verbose) {
143
+ console.log(` ℹ️ Loaded allowed resolvers: ${resolvers.map(r => r.resolverName || 'anonymous').join(', ')}`);
144
+ }
130
145
  }
131
146
 
132
147
  return createResolverChain(resolvers, verbose);
@@ -136,7 +151,6 @@ function loadResolverChain(specifiers, verbose = false) {
136
151
  * CLI Setup
137
152
  */
138
153
  const program = new Command();
139
-
140
154
  program
141
155
  .name('olang')
142
156
  .description('O-Lang CLI: run .ol workflows with rule-enforced agent governance')
@@ -162,29 +176,27 @@ program
162
176
  .action(async (file, options) => {
163
177
  try {
164
178
  ensureOlExtension(file);
165
-
166
179
  const content = fs.readFileSync(file, 'utf8');
167
- const workflow = parse(content);
168
-
180
+ const workflow = parse(content, file);
169
181
  if (!workflow || typeof workflow !== 'object') {
170
- console.error('❌ Error: Parsed workflow is invalid or empty');
182
+ console.error(' Error: Parsed workflow is invalid or empty');
171
183
  process.exit(1);
172
184
  }
173
-
174
185
  if (options.verbose) {
175
- console.log('📄 Parsed Workflow:', JSON.stringify(workflow, null, 2));
186
+ console.log(' 📄 Parsed Workflow:', JSON.stringify(workflow, null, 2));
176
187
  }
177
188
 
178
- const resolver = loadResolverChain(options.resolver, options.verbose);
189
+ // Pass allowedResolvers to loadResolverChain
190
+ const allowedSet = new Set(workflow.allowedResolvers.map(r => r.trim()));
191
+ const resolver = loadResolverChain(options.resolver, options.verbose, allowedSet);
179
192
 
180
193
  const result = await execute(workflow, options.input, resolver, options.verbose);
181
-
182
194
  console.log('\n=== Workflow Result ===');
183
195
  console.log(JSON.stringify(result, null, 2));
184
196
  } catch (err) {
185
- console.error('❌ Error:', err.message);
197
+ console.error(' Error:', err.message);
186
198
  process.exit(1);
187
199
  }
188
200
  });
189
201
 
190
- program.parse(process.argv);
202
+ program.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@o-lang/olang",
3
- "version": "1.0.16",
3
+ "version": "1.0.17",
4
4
  "author": "Olalekan Ogundipe <info@workfily.com>",
5
5
  "description": "O-Lang: A governance language for user-directed, rule-enforced agent workflows",
6
6
  "main": "./src/index.js",