@olane/o-context 0.8.9

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/LICENSE ADDED
@@ -0,0 +1,34 @@
1
+ # Dual License: MIT OR Apache-2.0
2
+
3
+ Copyright (c) 2025 Olane Inc.
4
+
5
+ Olane OS is dual-licensed under your choice of either:
6
+
7
+ - **MIT License** (LICENSE-MIT or https://opensource.org/licenses/MIT)
8
+ - **Apache License, Version 2.0** (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
9
+
10
+ ## Why Dual Licensing?
11
+
12
+ Dual licensing provides developers with flexibility when integrating Olane OS into their projects:
13
+
14
+ - **Choose MIT**: If you prefer a simple, permissive license without patent provisions
15
+ - **Choose Apache 2.0**: If you desire explicit patent protection and other features of the Apache license
16
+
17
+ You may choose either license to govern your use of this software.
18
+
19
+ ## License Terms
20
+
21
+ ### MIT License
22
+ The MIT license is very permissive and allows users to do almost anything with the software, including using, copying, modifying, merging, publishing, distributing, and selling it. The primary requirement is that the original copyright and license notice must be included in all copies of the software.
23
+
24
+ See LICENSE-MIT for the full license text.
25
+
26
+ ### Apache License 2.0
27
+ The Apache License 2.0 is also a permissive free software license. It grants users the right to use, modify, and distribute the software. It also includes provisions regarding patent grants, which are not present in the MIT license.
28
+
29
+ See LICENSE-APACHE for the full license text.
30
+
31
+ ## Contributing
32
+
33
+ Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual-licensed as above, without any additional terms or conditions.
34
+
package/README.md ADDED
@@ -0,0 +1,614 @@
1
+ # @olane/o-core
2
+
3
+ The kernel layer of Olane OS - an agentic operating system where AI agents are the users, and you build tool nodes as applications.
4
+
5
+ [![npm version](https://badge.fury.io/js/%40olane%2Fo-core.svg)](https://www.npmjs.com/package/@olane/o-core)
6
+ [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)
7
+
8
+ ## What is o-core?
9
+
10
+ **o-core** is the **kernel layer** of Olane OS - the foundational runtime for building tool nodes that AI agents use. Think of it as the Linux kernel: it defines how processes work (lifecycle, IPC, addressing, routing) but doesn't implement specific transport layers.
11
+
12
+ ### The Three-Layer Model
13
+
14
+ ```
15
+ AI Agents (LLMs|Humans) → use → Tool Nodes (you build) → run on → Olane OS (o-core)
16
+ ```
17
+
18
+ - **Agents (Users)**: GPT-4, Claude, Humans, etc. - the intelligent users
19
+ - **Tool Nodes (Applications)**: Domain-specific capabilities you build
20
+ - **o-core (OS Kernel)**: The runtime infrastructure that makes it all work
21
+
22
+ This is **NOT** a network framework or API library - it's the abstract operating system layer that makes inter-process communication (IPC), resource addressing, and hierarchical organization possible.
23
+
24
+ ## Key Features
25
+
26
+ - 🏗️ **Tool Node Runtime**: Base infrastructure for creating tool node processes that agents use
27
+ - 📍 **Hierarchical Addressing**: `o://` protocol for filesystem-like tool node addressing
28
+ - 🔀 **Intelligent Routing**: Automatic request routing through tool node hierarchies
29
+ - 🔌 **Transport-Agnostic**: Abstract layer - works with any communication layer (libp2p, HTTP, custom)
30
+ - 🌳 **Hierarchy Management**: Built-in parent-child relationships between tool nodes
31
+ - 🔄 **Lifecycle Management**: Complete process state management and graceful shutdown
32
+ - 📊 **Observable**: Built-in metrics, logging, and request tracking
33
+ - 🛡️ **Fault-Tolerant**: Error handling, graceful degradation, and automatic cleanup
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pnpm install @olane/o-core @olane/o-protocol
39
+ ```
40
+
41
+ ## Quick Start
42
+
43
+ ### Creating Your First Tool Node
44
+
45
+ > **Note**: `oCore` is an abstract base class. For production use, extend higher-level packages like `oNodeTool` (from `@olane/o-node`), `oLaneTool` (from `@olane/o-lane`), or `McpTool` (from `@olane/o-mcp`). The example below demonstrates the core concepts.
46
+
47
+ ```typescript
48
+ import { oCore, oAddress, NodeType, NodeState } from '@olane/o-core';
49
+ import { oRequest, oResponse } from '@olane/o-core';
50
+
51
+ // Extend oCore to create your tool node
52
+ class MyToolNode extends oCore {
53
+ constructor(config: { address: oAddress }) {
54
+ super({
55
+ address: config.address,
56
+ type: NodeType.AGENT, // Type remains AGENT for now (legacy naming)
57
+ description: 'My first tool node',
58
+ methods: {
59
+ greet: {
60
+ name: 'greet',
61
+ description: 'Greets the user',
62
+ parameters: {
63
+ name: { type: 'string', required: true }
64
+ }
65
+ }
66
+ }
67
+ });
68
+ }
69
+
70
+ // Implement required abstract methods
71
+ async execute(request: oRequest): Promise<any> {
72
+ const { method, params } = request;
73
+
74
+ if (method === 'greet') {
75
+ return { message: `Hello, ${params.name}!` };
76
+ }
77
+
78
+ throw new Error(`Unknown method: ${method}`);
79
+ }
80
+
81
+ configureTransports(): any[] {
82
+ // Configure your transport layer (libp2p, HTTP, etc.)
83
+ return [];
84
+ }
85
+
86
+ async connect(nextHop: oAddress, target: oAddress) {
87
+ // Implement connection logic
88
+ return this.connectionManager.connect({ nextHop, target });
89
+ }
90
+
91
+ initializeRouter(): void {
92
+ // Initialize routing logic
93
+ this.router = new MyRouter();
94
+ }
95
+
96
+ async register(): Promise<void> {
97
+ // Register with parent or leader node
98
+ console.log('Tool node registered');
99
+ }
100
+
101
+ async unregister(): Promise<void> {
102
+ // Cleanup registration
103
+ console.log('Tool node unregistered');
104
+ }
105
+ }
106
+
107
+ // Create and start your tool node
108
+ // IMPORTANT: Use simple (non-nested) addresses in constructors.
109
+ // Nested addresses like 'o://company/customer-service' are created
110
+ // automatically at runtime during parent-child registration.
111
+ const toolNode = new MyToolNode({
112
+ address: new oAddress('o://customer-service')
113
+ });
114
+ await toolNode.start();
115
+
116
+ // AI agents can now use this tool node via its o:// address
117
+ const response = await toolNode.use(
118
+ new oAddress('o://customer-service'),
119
+ {
120
+ method: 'greet',
121
+ params: { name: 'Alice' }
122
+ }
123
+ );
124
+
125
+ // Response follows the standard wrapping structure:
126
+ // response.result.success - boolean indicating success/failure
127
+ // response.result.data - the returned data on success
128
+ // response.result.error - error details on failure
129
+ if (response.result.success) {
130
+ console.log(response.result.data); // { message: "Hello, Alice!" }
131
+ }
132
+
133
+ // Stop the tool node gracefully
134
+ await toolNode.stop();
135
+ ```
136
+
137
+ ### Tool Node Communication (IPC)
138
+
139
+ ```typescript
140
+ // Tool Node A can communicate with Tool Node B using o:// addresses
141
+ // Use simple addresses in constructors; nested addresses are created at runtime
142
+ const salesTool = new MyToolNode({ address: new oAddress('o://sales') });
143
+ const analyticsTool = new MyToolNode({ address: new oAddress('o://analytics') });
144
+
145
+ await salesTool.start();
146
+ await analyticsTool.start();
147
+
148
+ // Sales tool calls analytics tool (inter-process communication)
149
+ const result = await salesTool.use(
150
+ new oAddress('o://analytics'),
151
+ {
152
+ method: 'analyze',
153
+ params: { data: salesData }
154
+ }
155
+ );
156
+ ```
157
+
158
+ ### Hierarchical Organization
159
+
160
+ ```typescript
161
+ // Create a parent-child hierarchy of tool nodes
162
+ // Use simple addresses in constructors - nested addresses are created at runtime
163
+ const parent = new MyToolNode({ address: new oAddress('o://company') });
164
+
165
+ // Children use simple addresses with a parent reference
166
+ // During registration, child addresses become nested (e.g., 'o://company/sales')
167
+ const child1 = new MyToolNode({ address: new oAddress('o://sales') });
168
+ const child2 = new MyToolNode({ address: new oAddress('o://marketing') });
169
+
170
+ await parent.start();
171
+ await child1.start();
172
+ await child2.start();
173
+
174
+ // Register children with parent - this creates the nested addresses
175
+ parent.addChildNode(child1);
176
+ parent.addChildNode(child2);
177
+
178
+ // After registration:
179
+ // child1.address -> 'o://company/sales'
180
+ // child2.address -> 'o://company/marketing'
181
+ // Routing happens automatically through the hierarchy
182
+ ```
183
+
184
+ ## Core Concepts
185
+
186
+ ### Tool Node Lifecycle States
187
+
188
+ Tool nodes (processes) transition through the following states:
189
+
190
+ - `STOPPED` - Initial state, tool node is not running
191
+ - `STARTING` - Tool node is initializing
192
+ - `RUNNING` - Tool node is active and processing requests
193
+ - `STOPPING` - Tool node is shutting down gracefully
194
+ - `ERROR` - Tool node encountered an error
195
+
196
+ ```typescript
197
+ console.log(toolNode.state); // NodeState.RUNNING
198
+
199
+ await toolNode.stop();
200
+ console.log(toolNode.state); // NodeState.STOPPED
201
+ ```
202
+
203
+ ### The o:// Protocol
204
+
205
+ Addresses in Olane OS follow a hierarchical filesystem-like pattern:
206
+
207
+ ```typescript
208
+ // Hierarchical addresses exist at runtime after parent-child registration.
209
+ // They are created by the system, not by constructors directly.
210
+ // For example, after registration a child address may become:
211
+ const address1 = new oAddress('o://company/finance/accounting');
212
+ const address2 = new oAddress('o://users/alice/inbox');
213
+
214
+ // Address operations
215
+ console.log(address1.paths); // "company/finance/accounting"
216
+ console.log(address1.root); // "o://company"
217
+ console.log(address1.validate()); // true
218
+
219
+ // Static vs dynamic addresses
220
+ const staticAddr = address1.toStaticAddress();
221
+ console.log(staticAddr.toString()); // "o://accounting"
222
+
223
+ // IMPORTANT: When creating nodes in constructors, always use simple
224
+ // (non-nested) addresses. Nested addresses are created automatically
225
+ // during parent-child registration at runtime.
226
+ // ✅ new oAddress('o://my-tool')
227
+ // ❌ new oAddress('o://parent/my-tool') -- violates validateNotNested()
228
+ ```
229
+
230
+ **📖 For complete details on address resolution, routing algorithms, and custom resolvers, see the [Router System documentation](./src/router/README.md).**
231
+
232
+ ### Request/Response Pattern
233
+
234
+ All inter-process communication (IPC) follows a request/response pattern using JSON-RPC 2.0:
235
+
236
+ ```typescript
237
+ // Making a request from one tool node to another
238
+ // Full signature: use(address: oAddress, data?: { method: string, params: any, id?: string }, options?: UseOptions)
239
+ const response: oResponse = await toolNode.use(
240
+ new oAddress('o://target-toolnode'),
241
+ {
242
+ method: 'processData',
243
+ params: { key: 'value' },
244
+ id: 'unique-request-id'
245
+ }
246
+ );
247
+
248
+ // Always check the response structure
249
+ if (response.result.success) {
250
+ console.log('Data:', response.result.data);
251
+ } else {
252
+ console.error('Error:', response.result.error);
253
+ }
254
+
255
+ // Transport-level errors throw exceptions
256
+ try {
257
+ const response = await toolNode.use(targetAddress, requestData);
258
+ // Check response.result.success for application-level errors
259
+ } catch (error) {
260
+ if (error instanceof oError) {
261
+ console.error(`Transport error ${error.code}: ${error.message}`);
262
+ }
263
+ }
264
+ ```
265
+
266
+ **📖 Learn more about JSON-RPC messaging, request states, and connection lifecycle in the [Connection System documentation](./src/connection/README.md).**
267
+
268
+ ### Response Structure
269
+
270
+ When you call `use()`, the response follows a standard wrapping structure created by the `ResponseBuilder`. In higher-level packages (`@olane/o-node`, `@olane/o-tool`, `@olane/o-lane`), responses are wrapped with `success`, `data`, and `error` fields:
271
+
272
+ ```typescript
273
+ const response = await toolNode.use(targetAddress, {
274
+ method: 'processData',
275
+ params: { key: 'value' }
276
+ });
277
+
278
+ // Standard response structure:
279
+ // {
280
+ // jsonrpc: "2.0",
281
+ // id: "request-id",
282
+ // result: {
283
+ // success: boolean, // Whether the operation succeeded
284
+ // data: any, // The returned data (on success)
285
+ // error?: string // Error details (on failure)
286
+ // }
287
+ // }
288
+
289
+ // Always check success before accessing data
290
+ if (response.result.success) {
291
+ const data = response.result.data;
292
+ console.log('Result:', data);
293
+ } else {
294
+ console.error('Error:', response.result.error);
295
+ }
296
+ ```
297
+
298
+ > **Important**: Access data via `response.result.data`, not `response.result` directly. The `result` object contains the wrapping fields (`success`, `data`, `error`), not the raw return value.
299
+
300
+ ### Metrics and Observability
301
+
302
+ Every tool node tracks metrics automatically:
303
+
304
+ ```typescript
305
+ // Access tool node metrics
306
+ console.log(toolNode.metrics.successCount);
307
+ console.log(toolNode.metrics.errorCount);
308
+
309
+ // Built-in logging
310
+ toolNode.logger.debug('Debug message');
311
+ toolNode.logger.info('Info message');
312
+ toolNode.logger.warn('Warning message');
313
+ toolNode.logger.error('Error message');
314
+ ```
315
+
316
+ ## Architecture
317
+
318
+ ### Abstract Base Class
319
+
320
+ `oCore` is an abstract base class that provides:
321
+
322
+ - **Lifecycle Management**: `start()`, `stop()`, `initialize()`, `teardown()`
323
+ - **Communication**: `use()`, `useDirect()`, `connect()`
324
+ - **Routing**: `router`, `initializeRouter()`
325
+ - **Hierarchy**: `addChildNode()`, `removeChildNode()`, `hierarchyManager`
326
+ - **State Management**: `state`, `NodeState` enum
327
+ - **Observability**: `metrics`, `logger`, `requestManager`
328
+
329
+ ### Key Components
330
+
331
+ #### 1. Router System (oAddress & oRouter)
332
+ Hierarchical addressing and intelligent routing for tool nodes
333
+
334
+ ```typescript
335
+ const addr = new oAddress('o://domain/subdomain/resource');
336
+ addr.validate(); // Check if address is valid
337
+ addr.toStaticAddress(); // Convert to static address
338
+ addr.toCID(); // Convert to Content ID
339
+
340
+ // Router determines the next hop in the network
341
+ const { nextHopAddress, targetAddress } = await router.translate(
342
+ address,
343
+ node
344
+ );
345
+ ```
346
+
347
+ **📚 [View detailed Router System documentation →](./src/router/README.md)**
348
+
349
+ #### 2. Connection System (oConnection & oConnectionManager)
350
+ Inter-Process Communication (IPC) layer for tool-node-to-tool-node messaging
351
+
352
+ ```typescript
353
+ // Connections are cached and reused
354
+ const connection = await connectionManager.connect({
355
+ nextHop: nextHopAddress,
356
+ target: targetAddress
357
+ });
358
+
359
+ // Send data over the connection
360
+ const response = await connection.send({
361
+ address: 'o://target/service',
362
+ payload: { key: 'value' }
363
+ });
364
+ ```
365
+
366
+ **📚 [View detailed Connection System documentation →](./src/connection/README.md)**
367
+
368
+ #### 3. oHierarchyManager
369
+ Manages parent-child relationships between tool nodes
370
+
371
+ ```typescript
372
+ toolNode.hierarchyManager.addChild(childAddress);
373
+ toolNode.hierarchyManager.removeChild(childAddress);
374
+ console.log(toolNode.hierarchyManager.children);
375
+ ```
376
+
377
+ ## Advanced Usage
378
+
379
+ ### Custom Transport & Connection Implementation
380
+
381
+ ```typescript
382
+ import { oTransport, TransportType, oConnection, oConnectionConfig } from '@olane/o-core';
383
+
384
+ class MyCustomTransport extends oTransport {
385
+ constructor() {
386
+ super(TransportType.CUSTOM);
387
+ }
388
+
389
+ async send(data: any): Promise<any> {
390
+ // Implement your transport logic (HTTP, WebSocket, etc.)
391
+ }
392
+ }
393
+
394
+ // Custom connection implementation
395
+ class MyConnection extends oConnection {
396
+ async transmit(request: oRequest): Promise<oResponse> {
397
+ // Implement your connection logic
398
+ const response = await fetch(this.nextHopAddress.toString(), {
399
+ method: 'POST',
400
+ body: request.toString()
401
+ });
402
+ return new oResponse(await response.json());
403
+ }
404
+ }
405
+
406
+ class MyToolNode extends oCore {
407
+ configureTransports(): any[] {
408
+ return [new MyCustomTransport()];
409
+ }
410
+ }
411
+ ```
412
+
413
+ **📖 For connection pooling, retry logic, middleware, and transport-specific implementations, see the [Connection System documentation](./src/connection/README.md).**
414
+
415
+ ### Custom Router Implementation
416
+
417
+ ```typescript
418
+ import { oRouter, RouteResponse } from '@olane/o-core';
419
+
420
+ class MyRouter extends oRouter {
421
+ async translate(address: oAddress, node: oCore): Promise<RouteResponse> {
422
+ // Implement custom routing logic
423
+ return {
424
+ nextHopAddress: calculatedNextHop,
425
+ targetAddress: address
426
+ };
427
+ }
428
+
429
+ isInternal(address: oAddress, node: oCore): boolean {
430
+ // Determine if address is internal to this node
431
+ return address.root === node.address.root;
432
+ }
433
+
434
+ async route(request: oRouterRequest, node: oCore): Promise<RouteResponse> {
435
+ // Handle routing requests
436
+ }
437
+ }
438
+ ```
439
+
440
+ **📖 For advanced routing patterns, custom resolvers, and hierarchical routing strategies, see the [Router System documentation](./src/router/README.md).**
441
+
442
+ ### Error Handling
443
+
444
+ ```typescript
445
+ import { oError, oErrorCodes } from '@olane/o-core';
446
+
447
+ // In your execute method
448
+ async execute(request: oRequest): Promise<any> {
449
+ if (!isValid(request.params)) {
450
+ throw new oError(
451
+ oErrorCodes.INVALID_PARAMS,
452
+ 'Invalid parameters provided'
453
+ );
454
+ }
455
+
456
+ try {
457
+ return await processRequest(request);
458
+ } catch (error) {
459
+ throw new oError(
460
+ oErrorCodes.EXECUTION_ERROR,
461
+ error.message
462
+ );
463
+ }
464
+ }
465
+ ```
466
+
467
+ ### Graceful Shutdown
468
+
469
+ ```typescript
470
+ import { setupGracefulShutdown } from '@olane/o-core';
471
+
472
+ const toolNode = new MyToolNode({ address: new oAddress('o://my-toolnode') });
473
+ await toolNode.start();
474
+
475
+ // Setup graceful shutdown handlers
476
+ setupGracefulShutdown(async () => {
477
+ console.log('Shutting down gracefully...');
478
+ await toolNode.stop();
479
+ });
480
+
481
+ // Tool node will automatically stop on SIGINT/SIGTERM
482
+ ```
483
+
484
+ ## API Reference
485
+
486
+ ### oCore Class
487
+
488
+ Abstract base class for building tool nodes.
489
+
490
+ #### Properties
491
+ - `address: oAddress` - The tool node's hierarchical address
492
+ - `state: NodeState` - Current lifecycle state
493
+ - `metrics: oMetrics` - Performance and usage metrics
494
+ - `hierarchyManager: oHierarchyManager` - Manages child nodes
495
+ - `router: oRouter` - Routing logic
496
+ - `connectionManager: oConnectionManager` - Connection pooling
497
+
498
+ #### Methods
499
+ - `async start(): Promise<void>` - Start the tool node
500
+ - `async stop(): Promise<void>` - Stop the tool node gracefully
501
+ - `async use(address: oAddress, data?: UseDataConfig, options?: UseOptions): Promise<oResponse>` - Communicate with another tool node (IPC). The `options` parameter supports `noRouting`, `isStream`, `onChunk`, `readTimeoutMs`, `drainTimeoutMs`, and `abortSignal`.
502
+ - `async useDirect(address: oAddress, data?: UseDataConfig): Promise<oResponse>` - Send a request without routing (equivalent to `use()` with `{ noRouting: true }`)
503
+ - `async useStream(address: oAddress, data: UseDataConfig, options: UseStreamOptions): Promise<oResponse>` - Send a streaming request to another tool node
504
+ - `async execute(request): Promise<any>` - Execute a request (abstract - you implement this)
505
+ - `addChildNode(node): void` - Add a child tool node
506
+ - `removeChildNode(node): void` - Remove a child tool node
507
+ - `async whoami(): Promise<any>` - Get tool node information
508
+
509
+ ### oAddress Class
510
+
511
+ #### Methods
512
+ - `validate(): boolean` - Validate address format
513
+ - `toStaticAddress(): oAddress` - Convert to static address
514
+ - `toString(): string` - Get string representation
515
+ - `equals(other): boolean` - Compare addresses
516
+ - `async toCID(): Promise<CID>` - Convert to Content ID
517
+
518
+ ### oError Class
519
+
520
+ #### Constructor
521
+ ```typescript
522
+ new oError(code: oErrorCodes, message: string, data?: any)
523
+ ```
524
+
525
+ #### Methods
526
+ - `toJSON(): object` - Serialize error
527
+ - `static fromJSON(json): oError` - Deserialize error
528
+
529
+ ## Testing
530
+
531
+ ```bash
532
+ # Run tests
533
+ pnpm test
534
+
535
+ # Run tests in Node.js
536
+ pnpm run test:node
537
+
538
+ # Run tests in browser
539
+ pnpm run test:browser
540
+ ```
541
+
542
+ ## Development
543
+
544
+ ```bash
545
+ # Install dependencies
546
+ pnpm install
547
+
548
+ # Build the package
549
+ pnpm run build
550
+
551
+ # Run in development mode
552
+ pnpm run dev
553
+
554
+ # Lint the code
555
+ pnpm run lint
556
+ ```
557
+
558
+ ## Use Cases
559
+
560
+ o-core enables you to:
561
+
562
+ 1. **Build Specialized Tool Nodes** with unique o:// addresses and capabilities
563
+ 2. **Create Hierarchical Tool Networks** that AI agents discover and use
564
+ 3. **Route Requests Intelligently** through tool node hierarchies
565
+ 4. **Manage Tool Node Lifecycles** with automatic cleanup and error handling
566
+ 5. **Share Knowledge and Capabilities** across tool networks through addressable resources
567
+
568
+ ## What o-core is NOT
569
+
570
+ - ❌ **Not a network framework** - It's the OS kernel for tool nodes
571
+ - ❌ **Not an orchestration tool** - It enables emergent coordination, not explicit workflows
572
+ - ❌ **Not a REST API** - It's a runtime for inter-process communication (IPC)
573
+ - ❌ **Not a complete solution** - It's an abstract foundation; use o-node for production
574
+ - ❌ **Not what you use directly** - Extend it or use higher-level packages (o-node, o-tool, o-lane)
575
+
576
+ ## Related Packages
577
+
578
+ - `@olane/o-protocol` - Protocol definitions and types
579
+ - `@olane/o-node` - Complete node implementation (extends o-core)
580
+ - `@olane/o-tool` - Tool system for agent capabilities
581
+ - `@olane/o-storage` - Storage layer for agent state
582
+ - `@olane/o-network-cli` - CLI for managing agent networks
583
+
584
+ ## Component Documentation
585
+
586
+ For in-depth documentation on specific o-core components, see:
587
+
588
+ - **[Router System](./src/router/README.md)** - Deep dive into the `o://` protocol, address resolution, routing logic, and custom resolvers
589
+ - **[Connection System](./src/connection/README.md)** - Complete guide to IPC, JSON-RPC messaging, connection pooling, and transport implementations
590
+
591
+ ## Documentation
592
+
593
+ - [Full Documentation](https://olane.com/docs)
594
+ - [Quickstart Guide](https://olane.com/docs/quickstart)
595
+ - [Architecture Overview](https://olane.com/docs/architecture/overview)
596
+ - [API Reference](https://olane.com/docs/api)
597
+
598
+ ## Support
599
+
600
+ - [GitHub Issues](https://github.com/olane-labs/olane/issues)
601
+ - [Community Forum](https://olane.com/community)
602
+ - [Email Support](mailto:support@olane.com)
603
+
604
+ ## Contributing
605
+
606
+ We welcome contributions! Please see our [Contributing Guide](../../CONTRIBUTING.md) for details.
607
+
608
+ ## License
609
+
610
+ ISC © Olane Inc.
611
+
612
+ ---
613
+
614
+ **Part of the Olane OS ecosystem** - An agentic operating system where AI agents are the users and you build tool nodes as applications.
@@ -0,0 +1,3 @@
1
+ export { createOContext } from './o-context.node.js';
2
+ export type { OContext } from './o-context.node.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,4 @@
1
+ // Main entry point — tsc compiles this for the `node` condition.
2
+ // The `default` (browser/RN) condition points directly at o-context.browser.js
3
+ // via conditional exports in package.json, so this file is never loaded there.
4
+ export { createOContext } from './o-context.node.js';
@@ -0,0 +1,11 @@
1
+ import type { OContext } from './o-context.js';
2
+ export type { OContext } from './o-context.js';
3
+ /**
4
+ * Create an `OContext<T>` using a simple variable swap.
5
+ *
6
+ * Safe for single-user environments (browsers, React Native) where there are
7
+ * no concurrent requests. Contains zero `node:` imports so bundlers like
8
+ * Metro will never try to resolve Node-only modules.
9
+ */
10
+ export declare function createOContext<T>(): OContext<T>;
11
+ //# sourceMappingURL=o-context.browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-context.browser.d.ts","sourceRoot":"","sources":["../../src/o-context.browser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,YAAY,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAyB/C"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Create an `OContext<T>` using a simple variable swap.
3
+ *
4
+ * Safe for single-user environments (browsers, React Native) where there are
5
+ * no concurrent requests. Contains zero `node:` imports so bundlers like
6
+ * Metro will never try to resolve Node-only modules.
7
+ */
8
+ export function createOContext() {
9
+ let currentStore;
10
+ return {
11
+ run(store, fn) {
12
+ const prev = currentStore;
13
+ currentStore = store;
14
+ try {
15
+ const result = fn();
16
+ if (result instanceof Promise) {
17
+ return result.finally(() => {
18
+ currentStore = prev;
19
+ });
20
+ }
21
+ currentStore = prev;
22
+ return result;
23
+ }
24
+ catch (e) {
25
+ currentStore = prev;
26
+ throw e;
27
+ }
28
+ },
29
+ getStore() {
30
+ return currentStore;
31
+ },
32
+ };
33
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Generic async context primitive.
3
+ *
4
+ * `run()` establishes a store for the duration of `fn` (and any async work it
5
+ * spawns). `getStore()` retrieves the current store from anywhere inside that
6
+ * call tree.
7
+ *
8
+ * Platform-specific implementations live in `o-context.node.ts` (AsyncLocalStorage)
9
+ * and `o-context.browser.ts` (simple variable swap).
10
+ */
11
+ export interface OContext<T> {
12
+ run<R>(store: T, fn: () => R): R;
13
+ getStore(): T | undefined;
14
+ }
15
+ //# sourceMappingURL=o-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-context.d.ts","sourceRoot":"","sources":["../../src/o-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IACjC,QAAQ,IAAI,CAAC,GAAG,SAAS,CAAC;CAC3B"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { OContext } from './o-context.js';
2
+ export type { OContext } from './o-context.js';
3
+ /**
4
+ * Create an `OContext<T>` backed by Node.js `AsyncLocalStorage`.
5
+ *
6
+ * Each async call tree started via `run()` gets its own isolated store,
7
+ * making this safe for concurrent requests on a server.
8
+ */
9
+ export declare function createOContext<T>(): OContext<T>;
10
+ //# sourceMappingURL=o-context.node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-context.node.d.ts","sourceRoot":"","sources":["../../src/o-context.node.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,YAAY,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAW/C"}
@@ -0,0 +1,18 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ /**
3
+ * Create an `OContext<T>` backed by Node.js `AsyncLocalStorage`.
4
+ *
5
+ * Each async call tree started via `run()` gets its own isolated store,
6
+ * making this safe for concurrent requests on a server.
7
+ */
8
+ export function createOContext() {
9
+ const als = new AsyncLocalStorage();
10
+ return {
11
+ run(store, fn) {
12
+ return als.run(store, fn);
13
+ },
14
+ getStore() {
15
+ return als.getStore();
16
+ },
17
+ };
18
+ }
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@olane/o-context",
3
+ "version": "0.8.9",
4
+ "type": "module",
5
+ "main": "dist/src/index.js",
6
+ "types": "dist/src/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/src/index.d.ts",
10
+ "node": "./dist/src/index.js",
11
+ "default": "./dist/src/o-context.browser.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist/**/*",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "scripts": {
20
+ "test": "aegir test",
21
+ "test:node": "aegir test -t node",
22
+ "test:browser": "aegir test -t browser",
23
+ "deep:clean": "rm -rf node_modules && rm package-lock.json",
24
+ "build": "rm -rf dist && tsc",
25
+ "start:prod": "node dist/index.js",
26
+ "prepublishOnly": "npm run build",
27
+ "lint": "aegir lint"
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/olane-labs/olane.git"
32
+ },
33
+ "author": "Olane Inc.",
34
+ "license": "(MIT OR Apache-2.0)",
35
+ "description": "Generic async context primitive with platform-specific implementations (AsyncLocalStorage for Node, variable swap for browser/RN)",
36
+ "devDependencies": {
37
+ "@eslint/eslintrc": "^3.3.1",
38
+ "@eslint/js": "^9.29.0",
39
+ "@tsconfig/node20": "^20.1.6",
40
+ "@types/jest": "^30.0.0",
41
+ "@types/uuid": "^10.0.0",
42
+ "@typescript-eslint/eslint-plugin": "^8.34.1",
43
+ "@typescript-eslint/parser": "^8.34.1",
44
+ "aegir": "^47.0.21",
45
+ "eslint": "^9.29.0",
46
+ "eslint-config-prettier": "^10.1.6",
47
+ "eslint-plugin-prettier": "^5.5.0",
48
+ "globals": "^16.2.0",
49
+ "jest": "^30.0.0",
50
+ "prettier": "^3.5.3",
51
+ "ts-jest": "^29.4.0",
52
+ "ts-node": "^10.9.2",
53
+ "tsconfig-paths": "^4.2.0",
54
+ "tsx": "^4.20.3",
55
+ "typescript": "^5.8.3"
56
+ },
57
+ "gitHead": "982373dd4827ee23bdb0fcba913a718d4bc64f1a"
58
+ }