ont-run 0.0.3 → 0.0.5

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/README.md CHANGED
@@ -7,6 +7,8 @@ A web framework designed for the era of coding agents. You define the ontology
7
7
  ```typescript
8
8
  // ontology.config.ts
9
9
  import { defineOntology, z } from 'ont-run';
10
+ import getTicket from './resolvers/getTicket.js';
11
+ import assignTicket from './resolvers/assignTicket.js';
10
12
 
11
13
  export default defineOntology({
12
14
  name: 'support-desk',
@@ -23,14 +25,14 @@ export default defineOntology({
23
25
  access: ['support', 'admin'],
24
26
  entities: ['Ticket'],
25
27
  inputs: z.object({ ticketId: z.string().uuid() }),
26
- resolver: './resolvers/getTicket.ts',
28
+ resolver: getTicket,
27
29
  },
28
30
  assignTicket: {
29
31
  description: 'Assign ticket to an agent',
30
32
  access: ['admin'], // If AI tries to add 'public' here, review is triggered
31
33
  entities: ['Ticket'],
32
34
  inputs: z.object({ ticketId: z.string().uuid(), assignee: z.string() }),
33
- resolver: './resolvers/assignTicket.ts',
35
+ resolver: assignTicket,
34
36
  },
35
37
  },
36
38
  // ...
@@ -141,6 +143,7 @@ The resolver context provides:
141
143
 
142
144
  ```typescript
143
145
  import { defineOntology, z } from 'ont-run';
146
+ import getUser from './resolvers/getUser.js';
144
147
 
145
148
  export default defineOntology({
146
149
  name: 'my-api',
@@ -150,11 +153,16 @@ export default defineOntology({
150
153
  prod: { debug: false },
151
154
  },
152
155
 
156
+ // Auth returns access groups (and optional user identity)
153
157
  auth: async (req: Request) => {
154
158
  const token = req.headers.get('Authorization');
155
- if (!token) return ['public'];
156
- if (token === 'admin-secret') return ['admin', 'user', 'public'];
157
- return ['user', 'public'];
159
+ if (!token) return { groups: ['public'] };
160
+
161
+ const user = await verifyToken(token);
162
+ return {
163
+ groups: user.isAdmin ? ['admin', 'user', 'public'] : ['user', 'public'],
164
+ user: { id: user.id, email: user.email }, // Optional: for row-level access
165
+ };
158
166
  },
159
167
 
160
168
  accessGroups: {
@@ -174,12 +182,75 @@ export default defineOntology({
174
182
  access: ['user', 'admin'],
175
183
  entities: ['User'],
176
184
  inputs: z.object({ userId: z.string().uuid() }),
177
- resolver: './resolvers/getUser.ts',
185
+ resolver: getUser,
178
186
  },
179
187
  },
180
188
  });
181
189
  ```
182
190
 
191
+ ## Row-Level Access Control
192
+
193
+ The framework handles **group-based access** (user → group → function) out of the box. For **row-level ownership** (e.g., "users can only edit their own posts"), use `userContext()`:
194
+
195
+ ```typescript
196
+ import { defineOntology, userContext, z } from 'ont-run';
197
+ import editPost from './resolvers/editPost.js';
198
+
199
+ export default defineOntology({
200
+ // Auth must return user identity for userContext to work
201
+ auth: async (req) => {
202
+ const user = await verifyToken(req);
203
+ return {
204
+ groups: ['user'],
205
+ user: { id: user.id, email: user.email },
206
+ };
207
+ },
208
+
209
+ functions: {
210
+ editPost: {
211
+ description: 'Edit a post',
212
+ access: ['user', 'admin'],
213
+ entities: ['Post'],
214
+ inputs: z.object({
215
+ postId: z.string(),
216
+ title: z.string(),
217
+ // currentUser is injected at runtime, hidden from API callers
218
+ currentUser: userContext(z.object({
219
+ id: z.string(),
220
+ email: z.string(),
221
+ })),
222
+ }),
223
+ resolver: editPost,
224
+ },
225
+ },
226
+ });
227
+ ```
228
+
229
+ In the resolver, you receive the typed user object:
230
+
231
+ ```typescript
232
+ // resolvers/editPost.ts
233
+ export default async function editPost(
234
+ ctx: ResolverContext,
235
+ args: { postId: string; title: string; currentUser: { id: string; email: string } }
236
+ ) {
237
+ const post = await db.posts.findById(args.postId);
238
+
239
+ // Row-level check: only author or admin can edit
240
+ if (args.currentUser.id !== post.authorId && !ctx.accessGroups.includes('admin')) {
241
+ throw new Error('Not authorized to edit this post');
242
+ }
243
+
244
+ return db.posts.update(args.postId, { title: args.title });
245
+ }
246
+ ```
247
+
248
+ **Key points:**
249
+ - `userContext()` fields are **injected** from `auth()` result's `user` field
250
+ - They're **hidden** from public API/MCP schemas (callers don't see or provide them)
251
+ - They're **type-safe** in resolvers
252
+ - The review UI shows a badge for functions using user context
253
+
183
254
  ## The Lockfile
184
255
 
185
256
  `ont.lock` is the enforcement mechanism. It contains a hash of your ontology:
package/dist/bin/ont.js CHANGED
@@ -6170,8 +6170,9 @@ function hasUserContextMetadata(schema) {
6170
6170
  }
6171
6171
  function getUserContextFields(schema) {
6172
6172
  const fields = [];
6173
- if (schema instanceof exports_external.ZodObject) {
6174
- const shape = schema.shape;
6173
+ const def = schema._def;
6174
+ if (def?.typeName === "ZodObject" && typeof def.shape === "function") {
6175
+ const shape = def.shape();
6175
6176
  for (const [key, value] of Object.entries(shape)) {
6176
6177
  if (hasUserContextMetadata(value)) {
6177
6178
  fields.push(key);
@@ -6182,7 +6183,6 @@ function getUserContextFields(schema) {
6182
6183
  }
6183
6184
  var FIELD_FROM_METADATA, USER_CONTEXT_METADATA;
6184
6185
  var init_categorical = __esm(() => {
6185
- init_zod();
6186
6186
  FIELD_FROM_METADATA = Symbol.for("ont:fieldFrom");
6187
6187
  USER_CONTEXT_METADATA = Symbol.for("ont:userContext");
6188
6188
  });
@@ -10233,6 +10233,10 @@ var Hono2 = class extends Hono {
10233
10233
  }
10234
10234
  };
10235
10235
 
10236
+ // src/browser/server.ts
10237
+ import { readFileSync as readFileSync2 } from "fs";
10238
+ import { basename } from "path";
10239
+
10236
10240
  // node_modules/open/index.js
10237
10241
  import process7 from "node:process";
10238
10242
  import { Buffer as Buffer2 } from "node:buffer";
@@ -10840,6 +10844,7 @@ function transformToGraphData(config) {
10840
10844
  const edges = [];
10841
10845
  const accessGroupCounts = {};
10842
10846
  const entityCounts = {};
10847
+ let userContextFunctionCount = 0;
10843
10848
  for (const groupName of Object.keys(config.accessGroups)) {
10844
10849
  accessGroupCounts[groupName] = 0;
10845
10850
  }
@@ -10857,6 +10862,9 @@ function transformToGraphData(config) {
10857
10862
  }
10858
10863
  const userContextFields = getUserContextFields(fn.inputs);
10859
10864
  const usesUserContext = userContextFields.length > 0;
10865
+ if (usesUserContext) {
10866
+ userContextFunctionCount++;
10867
+ }
10860
10868
  nodes.push({
10861
10869
  id: `function:${name}`,
10862
10870
  type: "function",
@@ -10865,7 +10873,6 @@ function transformToGraphData(config) {
10865
10873
  metadata: {
10866
10874
  inputs: safeZodToJsonSchema(fn.inputs),
10867
10875
  outputs: fn.outputs ? safeZodToJsonSchema(fn.outputs) : undefined,
10868
- resolver: fn.resolver,
10869
10876
  usesUserContext: usesUserContext || undefined
10870
10877
  }
10871
10878
  });
@@ -10927,7 +10934,8 @@ function transformToGraphData(config) {
10927
10934
  ontologyName: config.name,
10928
10935
  totalFunctions: Object.keys(config.functions).length,
10929
10936
  totalEntities: config.entities ? Object.keys(config.entities).length : 0,
10930
- totalAccessGroups: Object.keys(config.accessGroups).length
10937
+ totalAccessGroups: Object.keys(config.accessGroups).length,
10938
+ totalUserContextFunctions: userContextFunctionCount
10931
10939
  }
10932
10940
  };
10933
10941
  }
@@ -11098,7 +11106,7 @@ function enhanceWithDiff(graphData, diff) {
11098
11106
 
11099
11107
  // src/browser/server.ts
11100
11108
  async function startBrowserServer(options) {
11101
- const { config, diff = null, configDir, port: preferredPort, openBrowser = true } = options;
11109
+ const { config, diff = null, configDir, configPath, port: preferredPort, openBrowser = true } = options;
11102
11110
  const baseGraphData = transformToGraphData(config);
11103
11111
  const graphData = enhanceWithDiff(baseGraphData, diff);
11104
11112
  return new Promise(async (resolve2) => {
@@ -11145,6 +11153,21 @@ async function startBrowserServer(options) {
11145
11153
  }, 500);
11146
11154
  return c3.json({ success: true });
11147
11155
  });
11156
+ app.get("/api/source", (c3) => {
11157
+ if (!configPath) {
11158
+ return c3.json({ error: "Config path not available" }, 400);
11159
+ }
11160
+ try {
11161
+ const source = readFileSync2(configPath, "utf-8");
11162
+ const filename = basename(configPath);
11163
+ return c3.json({ source, filename, path: configPath });
11164
+ } catch (error) {
11165
+ return c3.json({
11166
+ error: "Failed to read config file",
11167
+ message: error instanceof Error ? error.message : "Unknown error"
11168
+ }, 500);
11169
+ }
11170
+ });
11148
11171
  app.get("/", (c3) => c3.html(generateBrowserUI(graphData)));
11149
11172
  const port = preferredPort || await findAvailablePort(3457);
11150
11173
  const server = await serve2(app, port);
@@ -11173,6 +11196,9 @@ Ontology ${hasChanges ? "Review" : "Browser"} available at: ${url}`);
11173
11196
  });
11174
11197
  }
11175
11198
  function generateBrowserUI(graphData) {
11199
+ const userContextFilterBtn = graphData.meta.totalUserContextFunctions > 0 ? `<button class="filter-btn" data-filter="userContext" title="Functions using userContext()">
11200
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:14px;height:14px;vertical-align:middle;margin-right:4px;"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>User Context (${graphData.meta.totalUserContextFunctions})
11201
+ </button>` : "";
11176
11202
  return `<!DOCTYPE html>
11177
11203
  <html lang="en">
11178
11204
  <head>
@@ -11750,6 +11776,89 @@ function generateBrowserUI(graphData) {
11750
11776
  color: var(--change-added);
11751
11777
  }
11752
11778
 
11779
+ /* Source View */
11780
+ .source-view {
11781
+ display: none;
11782
+ grid-column: 2 / 4;
11783
+ padding: 24px;
11784
+ overflow-y: auto;
11785
+ background: linear-gradient(to bottom, rgba(255, 255, 255, 0.5), rgba(231, 225, 207, 0.3));
11786
+ }
11787
+
11788
+ .source-view.active {
11789
+ display: flex;
11790
+ flex-direction: column;
11791
+ }
11792
+
11793
+ .source-header {
11794
+ display: flex;
11795
+ align-items: center;
11796
+ justify-content: space-between;
11797
+ padding: 12px 20px;
11798
+ background: rgba(2, 61, 96, 0.95);
11799
+ border-radius: 12px 12px 0 0;
11800
+ color: white;
11801
+ }
11802
+
11803
+ .source-filename {
11804
+ font-family: 'Space Mono', monospace;
11805
+ font-size: 13px;
11806
+ font-weight: 500;
11807
+ }
11808
+
11809
+ .copy-btn {
11810
+ display: flex;
11811
+ align-items: center;
11812
+ gap: 6px;
11813
+ padding: 6px 12px;
11814
+ background: rgba(255, 255, 255, 0.1);
11815
+ border: 1px solid rgba(255, 255, 255, 0.2);
11816
+ border-radius: 6px;
11817
+ color: white;
11818
+ font-family: 'Space Grotesk', sans-serif;
11819
+ font-size: 12px;
11820
+ cursor: pointer;
11821
+ transition: all 0.2s ease;
11822
+ }
11823
+
11824
+ .copy-btn:hover {
11825
+ background: rgba(255, 255, 255, 0.2);
11826
+ }
11827
+
11828
+ .copy-btn.copied {
11829
+ background: rgba(21, 168, 168, 0.3);
11830
+ border-color: var(--vanna-teal);
11831
+ }
11832
+
11833
+ .source-code {
11834
+ flex: 1;
11835
+ margin: 0;
11836
+ padding: 20px;
11837
+ background: #1e1e1e;
11838
+ border-radius: 0 0 12px 12px;
11839
+ overflow: auto;
11840
+ font-family: 'Space Mono', monospace;
11841
+ font-size: 13px;
11842
+ line-height: 1.6;
11843
+ color: #d4d4d4;
11844
+ tab-size: 2;
11845
+ }
11846
+
11847
+ .source-code code {
11848
+ display: block;
11849
+ white-space: pre;
11850
+ }
11851
+
11852
+ /* Syntax highlighting classes */
11853
+ .source-code .keyword { color: #569cd6; }
11854
+ .source-code .string { color: #ce9178; }
11855
+ .source-code .number { color: #b5cea8; }
11856
+ .source-code .comment { color: #6a9955; }
11857
+ .source-code .function { color: #dcdcaa; }
11858
+ .source-code .type { color: #4ec9b0; }
11859
+ .source-code .property { color: #9cdcfe; }
11860
+ .source-code .punctuation { color: #d4d4d4; }
11861
+
11753
11862
  /* No Changes State */
11754
11863
  .no-changes {
11755
11864
  text-align: center;
@@ -12478,6 +12587,7 @@ function generateBrowserUI(graphData) {
12478
12587
  <div class="view-tabs">
12479
12588
  <button class="view-tab active" data-view="graph">Graph</button>
12480
12589
  <button class="view-tab" data-view="table">Table</button>
12590
+ <button class="view-tab" data-view="source">Source</button>
12481
12591
  </div>
12482
12592
 
12483
12593
  <div class="filter-buttons" id="graphFilters">
@@ -12491,6 +12601,7 @@ function generateBrowserUI(graphData) {
12491
12601
  <button class="filter-btn" data-filter="accessGroup">
12492
12602
  <span class="dot access"></span> Access
12493
12603
  </button>
12604
+ ${userContextFilterBtn}
12494
12605
  </div>
12495
12606
 
12496
12607
  <div class="layout-selector">
@@ -12597,6 +12708,20 @@ function generateBrowserUI(graphData) {
12597
12708
  <div class="table-view" id="tableView">
12598
12709
  <div id="tableContent"></div>
12599
12710
  </div>
12711
+
12712
+ <!-- Source View -->
12713
+ <div class="source-view" id="sourceView">
12714
+ <div class="source-header">
12715
+ <span class="source-filename" id="sourceFilename">ontology.config.ts</span>
12716
+ <button class="copy-btn" id="copySourceBtn" title="Copy to clipboard">
12717
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
12718
+ <rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
12719
+ </svg>
12720
+ Copy
12721
+ </button>
12722
+ </div>
12723
+ <pre class="source-code" id="sourceCode"><code>Loading...</code></pre>
12724
+ </div>
12600
12725
  </div>
12601
12726
 
12602
12727
  <!-- Review Footer -->
@@ -12635,6 +12760,7 @@ function generateBrowserUI(graphData) {
12635
12760
  metadata: node.metadata,
12636
12761
  changeStatus: node.changeStatus || 'unchanged',
12637
12762
  changeDetails: node.changeDetails || null,
12763
+ usesUserContext: node.metadata?.usesUserContext || false,
12638
12764
  },
12639
12765
  });
12640
12766
  }
@@ -12687,6 +12813,19 @@ function generateBrowserUI(graphData) {
12687
12813
  'height': 55,
12688
12814
  },
12689
12815
  },
12816
+ // Function nodes with userContext - show indicator below label
12817
+ {
12818
+ selector: 'node[type="function"][?usesUserContext]',
12819
+ style: {
12820
+ 'background-image': 'data:image/svg+xml,' + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><circle cx="16" cy="16" r="14" fill="#e8f4f8" stroke="#023d60" stroke-width="1.5"/><g transform="translate(4, 4)" fill="none" stroke="#023d60" stroke-width="2"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></g></svg>'),
12821
+ 'background-width': '18px',
12822
+ 'background-height': '18px',
12823
+ 'background-position-x': '50%',
12824
+ 'background-position-y': '75%',
12825
+ 'text-valign': 'center',
12826
+ 'text-margin-y': -8,
12827
+ },
12828
+ },
12690
12829
  // Entity nodes - Teal
12691
12830
  {
12692
12831
  selector: 'node[type="entity"]',
@@ -13228,6 +13367,16 @@ function generateBrowserUI(graphData) {
13228
13367
  if (filter === 'all') {
13229
13368
  cy.nodes().removeClass('hidden');
13230
13369
  cy.edges().removeClass('hidden');
13370
+ } else if (filter === 'userContext') {
13371
+ // Special filter: show only functions with userContext
13372
+ cy.nodes().forEach(node => {
13373
+ if (node.data('type') === 'function' && node.data('usesUserContext')) {
13374
+ node.removeClass('hidden');
13375
+ } else {
13376
+ node.addClass('hidden');
13377
+ }
13378
+ });
13379
+ cy.edges().addClass('hidden');
13231
13380
  } else {
13232
13381
  cy.nodes().forEach(node => {
13233
13382
  if (node.data('type') === filter) {
@@ -13449,6 +13598,7 @@ function generateBrowserUI(graphData) {
13449
13598
  const graphContainer = document.querySelector('.graph-container');
13450
13599
  const detailPanel = document.getElementById('detailPanel');
13451
13600
  const tableView = document.getElementById('tableView');
13601
+ const sourceView = document.getElementById('sourceView');
13452
13602
  const graphFilters = document.getElementById('graphFilters');
13453
13603
  const layoutSelector = document.querySelector('.layout-selector');
13454
13604
 
@@ -13456,15 +13606,25 @@ function generateBrowserUI(graphData) {
13456
13606
  graphContainer.style.display = 'block';
13457
13607
  detailPanel.style.display = 'block';
13458
13608
  tableView.classList.remove('active');
13609
+ sourceView.classList.remove('active');
13459
13610
  if (graphFilters) graphFilters.style.display = 'flex';
13460
13611
  if (layoutSelector) layoutSelector.style.display = 'flex';
13461
- } else {
13612
+ } else if (view === 'table') {
13462
13613
  graphContainer.style.display = 'none';
13463
13614
  detailPanel.style.display = 'none';
13464
13615
  tableView.classList.add('active');
13616
+ sourceView.classList.remove('active');
13465
13617
  if (graphFilters) graphFilters.style.display = 'none';
13466
13618
  if (layoutSelector) layoutSelector.style.display = 'none';
13467
13619
  renderTableView();
13620
+ } else if (view === 'source') {
13621
+ graphContainer.style.display = 'none';
13622
+ detailPanel.style.display = 'none';
13623
+ tableView.classList.remove('active');
13624
+ sourceView.classList.add('active');
13625
+ if (graphFilters) graphFilters.style.display = 'none';
13626
+ if (layoutSelector) layoutSelector.style.display = 'none';
13627
+ loadSourceView();
13468
13628
  }
13469
13629
  }
13470
13630
 
@@ -13506,6 +13666,74 @@ function generateBrowserUI(graphData) {
13506
13666
  });
13507
13667
  }
13508
13668
 
13669
+ // Source view
13670
+ let sourceLoaded = false;
13671
+ let sourceContent = '';
13672
+
13673
+ async function loadSourceView() {
13674
+ if (sourceLoaded) return;
13675
+
13676
+ const codeEl = document.getElementById('sourceCode').querySelector('code');
13677
+ const filenameEl = document.getElementById('sourceFilename');
13678
+
13679
+ try {
13680
+ const res = await fetch('/api/source');
13681
+ if (!res.ok) throw new Error('Failed to load source');
13682
+ const data = await res.json();
13683
+
13684
+ sourceContent = data.source;
13685
+ filenameEl.textContent = data.filename;
13686
+ codeEl.innerHTML = highlightTypeScript(data.source);
13687
+ sourceLoaded = true;
13688
+ } catch (err) {
13689
+ codeEl.textContent = 'Error loading source: ' + err.message;
13690
+ }
13691
+ }
13692
+
13693
+ function highlightTypeScript(code) {
13694
+ // Escape HTML first
13695
+ code = code.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
13696
+
13697
+ // Comments (single and multi-line)
13698
+ code = code.replace(/(\\/\\/.*$)/gm, '<span class="comment">$1</span>');
13699
+ code = code.replace(/(\\/\\*[\\s\\S]*?\\*\\/)/g, '<span class="comment">$1</span>');
13700
+
13701
+ // Strings (double, single, and template)
13702
+ code = code.replace(/("(?:[^"\\\\]|\\\\.)*")/g, '<span class="string">$1</span>');
13703
+ code = code.replace(/('(?:[^'\\\\]|\\\\.)*')/g, '<span class="string">$1</span>');
13704
+ code = code.replace(/(\`(?:[^\`\\\\]|\\\\.)*\`)/g, '<span class="string">$1</span>');
13705
+
13706
+ // Keywords
13707
+ const keywords = ['import', 'export', 'from', 'const', 'let', 'var', 'function', 'return', 'if', 'else', 'for', 'while', 'class', 'extends', 'new', 'this', 'true', 'false', 'null', 'undefined', 'typeof', 'instanceof', 'async', 'await', 'default', 'as', 'type', 'interface'];
13708
+ keywords.forEach(kw => {
13709
+ code = code.replace(new RegExp('\\\\b(' + kw + ')\\\\b', 'g'), '<span class="keyword">$1</span>');
13710
+ });
13711
+
13712
+ // Numbers
13713
+ code = code.replace(/\\b(\\d+\\.?\\d*)\\b/g, '<span class="number">$1</span>');
13714
+
13715
+ // Function calls
13716
+ code = code.replace(/\\b([a-zA-Z_][a-zA-Z0-9_]*)\\s*\\(/g, '<span class="function">$1</span>(');
13717
+
13718
+ return code;
13719
+ }
13720
+
13721
+ // Copy source button
13722
+ document.getElementById('copySourceBtn').addEventListener('click', async () => {
13723
+ const btn = document.getElementById('copySourceBtn');
13724
+ try {
13725
+ await navigator.clipboard.writeText(sourceContent);
13726
+ btn.classList.add('copied');
13727
+ btn.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg> Copied!';
13728
+ setTimeout(() => {
13729
+ btn.classList.remove('copied');
13730
+ btn.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg> Copy';
13731
+ }, 2000);
13732
+ } catch (err) {
13733
+ console.error('Failed to copy:', err);
13734
+ }
13735
+ });
13736
+
13509
13737
  function renderTableSection(title, items, type) {
13510
13738
  const changedCount = items.filter(n => n.changeStatus !== 'unchanged').length;
13511
13739
 
@@ -13679,7 +13907,7 @@ var reviewCommand = defineCommand({
13679
13907
  process.exit(0);
13680
13908
  }
13681
13909
  consola.info("Loading ontology config...");
13682
- const { config, configDir } = await loadConfig();
13910
+ const { config, configDir, configPath } = await loadConfig();
13683
13911
  const { ontology: newOntology, hash: newHash } = computeOntologyHash(config);
13684
13912
  const lockfile = await readLockfile(configDir);
13685
13913
  const oldOntology = lockfile?.ontology || null;
@@ -13727,7 +13955,8 @@ var reviewCommand = defineCommand({
13727
13955
  const result = await startBrowserServer({
13728
13956
  config,
13729
13957
  diff: diff.hasChanges ? diff : null,
13730
- configDir
13958
+ configDir,
13959
+ configPath
13731
13960
  });
13732
13961
  if (diff.hasChanges) {
13733
13962
  if (result.approved) {
@@ -13744,13 +13973,77 @@ var reviewCommand = defineCommand({
13744
13973
  }
13745
13974
  }
13746
13975
  });
13976
+ // package.json
13977
+ var package_default = {
13978
+ name: "ont-run",
13979
+ version: "0.0.5",
13980
+ description: "Ontology-enforced API framework for AI coding agents",
13981
+ type: "module",
13982
+ bin: {
13983
+ "ont-run": "./dist/bin/ont.js"
13984
+ },
13985
+ exports: {
13986
+ ".": {
13987
+ types: "./dist/src/index.d.ts",
13988
+ bun: "./src/index.ts",
13989
+ default: "./dist/index.js"
13990
+ }
13991
+ },
13992
+ files: [
13993
+ "dist",
13994
+ "src",
13995
+ "bin"
13996
+ ],
13997
+ scripts: {
13998
+ dev: "bun run bin/ont.ts",
13999
+ build: "bun build ./src/index.ts --outdir ./dist --target node",
14000
+ "build:cli": "bun build ./bin/ont.ts --outfile ./dist/bin/ont.js --target node --external @modelcontextprotocol/sdk",
14001
+ "build:types": "tsc --declaration --emitDeclarationOnly",
14002
+ prepublishOnly: "bun run build && bun run build:cli && bun run build:types",
14003
+ docs: "cd docs && bun run dev",
14004
+ "docs:build": "cd docs && bun run build",
14005
+ "docs:preview": "cd docs && bun run preview"
14006
+ },
14007
+ dependencies: {
14008
+ "@hono/node-server": "^1.19.8",
14009
+ "@modelcontextprotocol/sdk": "^1.0.0",
14010
+ citty: "^0.1.6",
14011
+ consola: "^3.2.0",
14012
+ hono: "^4.6.0",
14013
+ open: "^10.0.0",
14014
+ zod: "^3.24.0",
14015
+ "zod-to-json-schema": "^3.23.0"
14016
+ },
14017
+ devDependencies: {
14018
+ "@types/bun": "latest",
14019
+ typescript: "^5.5.0"
14020
+ },
14021
+ peerDependencies: {
14022
+ bun: ">=1.0.0"
14023
+ },
14024
+ peerDependenciesMeta: {
14025
+ bun: {
14026
+ optional: true
14027
+ }
14028
+ },
14029
+ keywords: [
14030
+ "api",
14031
+ "framework",
14032
+ "access-control",
14033
+ "ai-agents",
14034
+ "hono",
14035
+ "zod",
14036
+ "typescript"
14037
+ ],
14038
+ license: "MIT"
14039
+ };
13747
14040
 
13748
14041
  // src/cli/index.ts
13749
14042
  var main = defineCommand({
13750
14043
  meta: {
13751
14044
  name: "ont",
13752
14045
  description: "Ontology - Ontology-first backends with human-approved AI access & edits",
13753
- version: "0.1.0"
14046
+ version: package_default.version
13754
14047
  },
13755
14048
  subCommands: {
13756
14049
  init: initCommand,