@indra.ai/deva 1.0.27
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 +21 -0
- package/README.md +391 -0
- package/examples/hello-world.js +61 -0
- package/index.js +528 -0
- package/package.json +34 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Quinn Michaels
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
# DEVA
|
|
2
|
+
Deva is a lightweight class object that provides events and object management with inherited properties.
|
|
3
|
+
|
|
4
|
+
## Install
|
|
5
|
+
```bash
|
|
6
|
+
$> npm i @feecting/deva
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Basic Structure
|
|
10
|
+
```javascript
|
|
11
|
+
// include the main Deva class
|
|
12
|
+
const Deva = require('feecting/deva');
|
|
13
|
+
|
|
14
|
+
// setup the Deva object
|
|
15
|
+
const deva = new Deva({
|
|
16
|
+
agent: {
|
|
17
|
+
uid: '*uinique identifier*'
|
|
18
|
+
key: '*DEVA KEY*',
|
|
19
|
+
name: '*DEVA NAME*',
|
|
20
|
+
describe: '*DEVA LONG DESCRIPTION*',
|
|
21
|
+
prompt: {
|
|
22
|
+
emoji: '🐶',
|
|
23
|
+
text: '*DEVA*',
|
|
24
|
+
color: 'white',
|
|
25
|
+
},
|
|
26
|
+
voice: {
|
|
27
|
+
speech: 'Alex',
|
|
28
|
+
speed: 1
|
|
29
|
+
},
|
|
30
|
+
profile: {
|
|
31
|
+
emoji: 'the graphic emoji the agent travels with. 50px x 50px'
|
|
32
|
+
avatar: 'the graphic avatar the agent travels with 150px x 150px',
|
|
33
|
+
background: 'a background asset for page displays for th eagent',
|
|
34
|
+
describe: 'the profile description for the agent that is used in displays.',
|
|
35
|
+
gender: 'the preferred gender string for the agent',
|
|
36
|
+
},
|
|
37
|
+
translate(input) {
|
|
38
|
+
return input.trim();
|
|
39
|
+
},
|
|
40
|
+
parse(input) {
|
|
41
|
+
return input.trim();
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
vars: {},
|
|
45
|
+
listeners: {},
|
|
46
|
+
modules: {},
|
|
47
|
+
func: {},
|
|
48
|
+
methods: {},
|
|
49
|
+
deva: {},
|
|
50
|
+
onStart() {},
|
|
51
|
+
onStop() {},
|
|
52
|
+
onEnter() {},
|
|
53
|
+
onExit() {},
|
|
54
|
+
onDone() {},
|
|
55
|
+
onInit() {},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// initialize the class
|
|
59
|
+
deva.init();
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Breakdown
|
|
64
|
+
### Agent
|
|
65
|
+
```javascript
|
|
66
|
+
this.agent
|
|
67
|
+
```
|
|
68
|
+
The "me" object contains the profile information for the DEVA.
|
|
69
|
+
##### Data Attributes
|
|
70
|
+
- **uid:** The unique id for the Deva.
|
|
71
|
+
- **key:** The unique key for the Deva.
|
|
72
|
+
- **name:** The name of the Deva.
|
|
73
|
+
- **description:** A description of what the Deva does.
|
|
74
|
+
- **prompt:** Define how prompt displays.
|
|
75
|
+
- **emoji:** The emoji for use as a prompt indicator.
|
|
76
|
+
- **text:** Short text for prompt display.
|
|
77
|
+
- **color:** The color of the prompt for the Deva.
|
|
78
|
+
- **voice:** Voice properties of the Deva.
|
|
79
|
+
- **speech:** The name of the voice speech to use.
|
|
80
|
+
- **speed:** The speed of the voice.
|
|
81
|
+
- **profile:** Public Profile Information
|
|
82
|
+
- **emoji:** The emoji for the Deva
|
|
83
|
+
- **avatar:** The avatar for the Deva
|
|
84
|
+
- **background:** The background image for the Deva
|
|
85
|
+
- **gender:** The gender of the Deva
|
|
86
|
+
- **describe:** A short description of the deva 100 characters or less.
|
|
87
|
+
|
|
88
|
+
### Vars
|
|
89
|
+
```javascript
|
|
90
|
+
this.vars
|
|
91
|
+
```
|
|
92
|
+
The vars can be use to set local variables for the deva that need to be used in your program.
|
|
93
|
+
|
|
94
|
+
There are no default variables, so the scope is for you and your imagination to figure out.
|
|
95
|
+
|
|
96
|
+
##### Example
|
|
97
|
+
```javascript
|
|
98
|
+
...
|
|
99
|
+
vars: {
|
|
100
|
+
foo: 'bar',
|
|
101
|
+
steps: 10,
|
|
102
|
+
strings: 'Some variable string',
|
|
103
|
+
adding: 1 + 9 + 11,
|
|
104
|
+
objects: {
|
|
105
|
+
key: 'key value'
|
|
106
|
+
},
|
|
107
|
+
arrays: [
|
|
108
|
+
'value 1',
|
|
109
|
+
'value 2',
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
...
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
### Listeners
|
|
116
|
+
Listeners are what you setup that allow your Deva to communicate with other Deva or parts of your application/system.
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
this.listeners
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### Default Listeners
|
|
123
|
+
|
|
124
|
+
Each Deva comes with a set of default listeners to provide basic functionality.
|
|
125
|
+
|
|
126
|
+
##### Question
|
|
127
|
+
The question event is the functionality that exposes the methods to the outside world. When a deva asks a question the string is parsed into a question format so that commands to access various methods can be exposed.
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
const question = await this.question(`#*agent_key* *method*:*params* *question string*`);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
##### Start
|
|
134
|
+
This will trigger an event to start the Deva.
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
this.talk(`*agent_key*:start`);
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
##### Stop
|
|
141
|
+
This will trigger an event to stop the Deva.
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
this.talk(`*agent_key*:stop`);
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
##### Status
|
|
148
|
+
This will trigger an event to broadcast the Deva status.
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
this.talk(`*agent_key*:status`);
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Deva
|
|
155
|
+
```javascript
|
|
156
|
+
this.deva
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The main object for Deva that are bwlow this Deva.
|
|
160
|
+
|
|
161
|
+
### Modules
|
|
162
|
+
The external modules that your Deva might require to function.
|
|
163
|
+
|
|
164
|
+
```javascript
|
|
165
|
+
this.modules
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
### Func
|
|
170
|
+
The functions that your deva uses to operate. Functions are not exposed through
|
|
171
|
+
the api to public access.
|
|
172
|
+
|
|
173
|
+
```javascript
|
|
174
|
+
this.func
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Methods
|
|
178
|
+
```javascript
|
|
179
|
+
this.methods
|
|
180
|
+
```
|
|
181
|
+
The methods are exposed publicly through the question event that parses a string
|
|
182
|
+
and sends a request to the question method that then interacts with functions, modules, and variables.
|
|
183
|
+
|
|
184
|
+
### State Functions
|
|
185
|
+
Provided are a set of state functions that trigger when a Deva is at various states of starting/stopping.
|
|
186
|
+
|
|
187
|
+
#### onStart()
|
|
188
|
+
|
|
189
|
+
The `onStart()` function runs after the `start` function has completed.
|
|
190
|
+
|
|
191
|
+
```javascript
|
|
192
|
+
this.onStart() {
|
|
193
|
+
// some code to run when the deva starts.
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
#### onStop()
|
|
198
|
+
|
|
199
|
+
The `onStop()` function runs after the `stop` function has completed.
|
|
200
|
+
|
|
201
|
+
```javascript
|
|
202
|
+
this.onStop() {
|
|
203
|
+
// some code to run when the deva stops
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
#### onEnter()
|
|
209
|
+
|
|
210
|
+
The `onEnter()` function runs after the `enter` event has fired.
|
|
211
|
+
|
|
212
|
+
```javascript
|
|
213
|
+
this.onEnter() {
|
|
214
|
+
// some code to run when the deva is loaded
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
#### onExit()
|
|
220
|
+
|
|
221
|
+
The `onExit()`function runs after the `exit` event has fired.
|
|
222
|
+
|
|
223
|
+
```javascript
|
|
224
|
+
this.onExit() {
|
|
225
|
+
// some code to run when the deva logs out.
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
#### onDone()
|
|
230
|
+
|
|
231
|
+
The `onDone()`function runs after the `done` event has fired.
|
|
232
|
+
|
|
233
|
+
```javascript
|
|
234
|
+
this.onDone() {
|
|
235
|
+
// some code to run when the deva logs out.
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
#### onInit()
|
|
241
|
+
|
|
242
|
+
The `onInit()` function runs after the `init()` function has completed.
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
this.onInit() {
|
|
246
|
+
// some code to run when the Deva initializes.
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Utility Functions
|
|
251
|
+
|
|
252
|
+
### uid()
|
|
253
|
+
Generates a unique ID that is used in packet transfer and other various ways.
|
|
254
|
+
|
|
255
|
+
```javascript
|
|
256
|
+
this.uid() // inside the object
|
|
257
|
+
deva.uid() // outside the object
|
|
258
|
+
|
|
259
|
+
// example
|
|
260
|
+
this.vars.id = this.uid()
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### talk(evt, resource=false)
|
|
265
|
+
|
|
266
|
+
The `talk()` function is used when your Deva needs to broadcast an event that other Deva
|
|
267
|
+
or functions would be listening for.
|
|
268
|
+
|
|
269
|
+
```javascript
|
|
270
|
+
this.talk('event', resource); // inside the object
|
|
271
|
+
deva.talk('event', resource); // outside the object
|
|
272
|
+
|
|
273
|
+
// example
|
|
274
|
+
const evt_id = this.uid();
|
|
275
|
+
const evt_data = {
|
|
276
|
+
task_id: 1,
|
|
277
|
+
task_name: 'this is blank data',
|
|
278
|
+
task_contact: 'joe@schmo.com',
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
this.talk('big-event', {
|
|
282
|
+
id: evt_id,
|
|
283
|
+
key: this.me.key,
|
|
284
|
+
q: {
|
|
285
|
+
bot: this.me,
|
|
286
|
+
text: 'text to send to the event',
|
|
287
|
+
data: evt_data,
|
|
288
|
+
},
|
|
289
|
+
created: Date.now(),
|
|
290
|
+
});
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### listen(evt callback)
|
|
294
|
+
|
|
295
|
+
The `listen` function can assign listeners to the Deva and designate which `callback`
|
|
296
|
+
function to run when an event is fired.
|
|
297
|
+
|
|
298
|
+
Listeners can be set up individually this way or also added to the listeners object
|
|
299
|
+
independently.
|
|
300
|
+
|
|
301
|
+
```javascript
|
|
302
|
+
this.listen('some-event', this.func.listener);
|
|
303
|
+
|
|
304
|
+
this.func.listenter = packet => {
|
|
305
|
+
console.log('some-event-fired');
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### once(evt, callback)
|
|
311
|
+
|
|
312
|
+
The `once()` function can assign a one-time listener to a function. This is useful when returning data with an id that one Deva has submitted to another Deva. Also very useful for submit responses that are unique to the request.
|
|
313
|
+
|
|
314
|
+
```javascript
|
|
315
|
+
this.once(`some-once-event`, this.func.listener)
|
|
316
|
+
this.func.listener = packet => {
|
|
317
|
+
console.log('some-once-event-fired');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### ignore(evt, callback)
|
|
323
|
+
|
|
324
|
+
The `ignore()` function removes a listener from the designated event. This is useful for adding and removing events dynamically or as needed.
|
|
325
|
+
|
|
326
|
+
```javascript
|
|
327
|
+
this.ignore('ignore-event', this.func.listener);
|
|
328
|
+
this.func.listener = packet => {
|
|
329
|
+
console.log('ignore-event-fired');
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
### Load(agent, opts)
|
|
335
|
+
|
|
336
|
+
To add a Deva dynamically use the `load()` function. This can be utilized to add Deva to an existing Deva after the object has already been created.
|
|
337
|
+
|
|
338
|
+
```javascript
|
|
339
|
+
const opts = {
|
|
340
|
+
me: {...},
|
|
341
|
+
vars: {...},
|
|
342
|
+
listeners: {...},
|
|
343
|
+
deva: {...},
|
|
344
|
+
func: {...},
|
|
345
|
+
onStart() {},
|
|
346
|
+
onStop() {},
|
|
347
|
+
onEnter() {},
|
|
348
|
+
onExit() {},
|
|
349
|
+
}
|
|
350
|
+
this.load('deva-name', opts);
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### unload(agent)
|
|
354
|
+
To delete a Deva for any reason use `unload()`. This will delete the Deva and all it's parts from the current Deva.
|
|
355
|
+
|
|
356
|
+
```javascript
|
|
357
|
+
|
|
358
|
+
this.unload('deva-key');
|
|
359
|
+
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### question(packet)
|
|
363
|
+
The `question(packet)` function is a default function that allows the system to ask questions of itself or other Deva.
|
|
364
|
+
|
|
365
|
+
The function checks the beginning of a string for a `#` to determine wether to issue a command to run a specific method.
|
|
366
|
+
|
|
367
|
+
See [Question Listener](#question) for usage.
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
#deva method:params message
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
### status()
|
|
375
|
+
The `status()` function will return the running status of the current Deva.
|
|
376
|
+
|
|
377
|
+
### start()
|
|
378
|
+
The `start()` function will start the Deva and run the `onStart()` state function.
|
|
379
|
+
|
|
380
|
+
### stop()
|
|
381
|
+
The `stop()` function will stop the Deva and run the `onStop()` state function.
|
|
382
|
+
|
|
383
|
+
### init(deva=false)
|
|
384
|
+
The `init()` function will initialize the Deva and run the `onInit()` state function.
|
|
385
|
+
|
|
386
|
+
### initDeva()
|
|
387
|
+
The `initDeva()` function will initialize the Deva located under the current Deva set. To be used in instances of a main Deva parent situation.
|
|
388
|
+
|
|
389
|
+
-
|
|
390
|
+
|
|
391
|
+
©2021 Quinn Michaels; All Rights Reserved.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Copyright (c)2021 Quinn Michaels
|
|
2
|
+
// Distributed under the MIT software license, see the accompanying
|
|
3
|
+
// file LICENSE.md or http://www.opensource.org/licenses/mit-license.php.
|
|
4
|
+
const Deva = require('../index');
|
|
5
|
+
const HelloWorld = new Deva({
|
|
6
|
+
agent: {
|
|
7
|
+
key: 'hello',
|
|
8
|
+
name: 'Hello World',
|
|
9
|
+
description: 'The most over complex Hello World in the Universe',
|
|
10
|
+
prompt: {
|
|
11
|
+
emoji: '🐶',
|
|
12
|
+
text: 'hello',
|
|
13
|
+
color: 'white',
|
|
14
|
+
},
|
|
15
|
+
voice: {
|
|
16
|
+
speech: 'Alex',
|
|
17
|
+
speed: 1
|
|
18
|
+
},
|
|
19
|
+
profile: {
|
|
20
|
+
avatar: '',
|
|
21
|
+
background: '',
|
|
22
|
+
describe: 'Hello World Deva',
|
|
23
|
+
gender: 'N',
|
|
24
|
+
},
|
|
25
|
+
translate(input) {
|
|
26
|
+
return input.trim();
|
|
27
|
+
},
|
|
28
|
+
parse(input) {
|
|
29
|
+
return input.trim();
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
vars: {
|
|
33
|
+
hello: 'Hello World'
|
|
34
|
+
},
|
|
35
|
+
listeners: {},
|
|
36
|
+
deva: {},
|
|
37
|
+
modules: {},
|
|
38
|
+
func: {
|
|
39
|
+
hello() {
|
|
40
|
+
return this.agent.translate(this.vars.hello);
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
methods: {
|
|
44
|
+
hello() {
|
|
45
|
+
return this.func.hello();
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
onStart() {
|
|
50
|
+
console.log(this.methods.hello());
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
onStop() {},
|
|
54
|
+
onEnter() {},
|
|
55
|
+
onExit() {},
|
|
56
|
+
onDone() {},
|
|
57
|
+
onInit() {
|
|
58
|
+
this.start();
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
HelloWorld.init();
|
package/index.js
ADDED
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
// Copyright (c)2021 Quinn Michaels
|
|
2
|
+
// Distributed under the MIT software license, see the accompanying
|
|
3
|
+
// file LICENSE.md or http://www.opensource.org/licenses/mit-license.php.
|
|
4
|
+
const {EventEmitter} = require('events');
|
|
5
|
+
class Deva {
|
|
6
|
+
constructor(opts) {
|
|
7
|
+
opts = opts || {};
|
|
8
|
+
this._uid = this.uid(); // the unique id assigned to the agent at load
|
|
9
|
+
this.state = 'offline'; // current state of agent.
|
|
10
|
+
this.active = false; // the active/birth date.
|
|
11
|
+
this.security = false; // inherited Security features.
|
|
12
|
+
this.config = opts.config || {}; // local Config Object
|
|
13
|
+
this.events = opts.events || new EventEmitter({}); // Event Bus
|
|
14
|
+
this.lib = opts.lib || {}; // used for loading library functions
|
|
15
|
+
this.agent = opts.agent || false; // Agent profile object
|
|
16
|
+
this.client = opts.client || false; // Client profile object
|
|
17
|
+
this.devas = opts.devas || {}; // Devas which are loaded
|
|
18
|
+
this.vars = opts.vars || {}; // Variables object
|
|
19
|
+
this.listeners = opts.listeners || {}; // local Listeners
|
|
20
|
+
this.modules = opts.modules || {}; // 3rd Party Modules
|
|
21
|
+
this.func = opts.func || {}; // local Functions
|
|
22
|
+
this.methods = opts.methods || {}; // local Methods
|
|
23
|
+
this.maxListeners = opts.maxListenners || 0; // set the local maxListeners
|
|
24
|
+
|
|
25
|
+
for (var opt in opts) {
|
|
26
|
+
if (!this[opt]) this[opt] = opts[opt]; // set any remaining opts to this.
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
this.cmdChr = '!';
|
|
30
|
+
this.askChr = '#';
|
|
31
|
+
this.inherit = ["events", "config", "lib", "security", "client"];
|
|
32
|
+
this.bind = ["listeners", "methods", "func", "lib", "security", "agent", "client"];
|
|
33
|
+
this.states = {
|
|
34
|
+
offline: 'OFFLINE',
|
|
35
|
+
init: 'INITIALIZE',
|
|
36
|
+
start: 'START',
|
|
37
|
+
stop: 'STOP',
|
|
38
|
+
enter: 'ENTER',
|
|
39
|
+
exit: 'EXIT',
|
|
40
|
+
done: 'DONE',
|
|
41
|
+
wait: 'WAITING',
|
|
42
|
+
ask: 'ASK',
|
|
43
|
+
question: 'QUESTION',
|
|
44
|
+
answer: 'ANSWER',
|
|
45
|
+
error: 'ERROR',
|
|
46
|
+
security: 'SECURITY',
|
|
47
|
+
medic: 'MEDICAL',
|
|
48
|
+
};
|
|
49
|
+
this.messages = {
|
|
50
|
+
offline: 'AGENT OFFLINE',
|
|
51
|
+
loaded: 'DEVAS LOADED',
|
|
52
|
+
stopped: 'DEVAS STOPPED',
|
|
53
|
+
notext: 'NO TEXT',
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// set the state of the agent with the passed value to match the valid keys.
|
|
58
|
+
// this will also talk a global state event with the agent data and state.
|
|
59
|
+
// then security can watch all the glorious state change events.
|
|
60
|
+
set _state(st) {
|
|
61
|
+
this.state = this.states[st];
|
|
62
|
+
this.talk(`state`,{
|
|
63
|
+
uid: this.uid(),
|
|
64
|
+
agent: this.agent,
|
|
65
|
+
state: this.state,
|
|
66
|
+
created: Date.now(),
|
|
67
|
+
});
|
|
68
|
+
this.prompt(this.state);
|
|
69
|
+
}
|
|
70
|
+
// Called from the init function to bind the elements defined in the this.bind variable.
|
|
71
|
+
// the assign bind ensures that the *this* scope is available to child elements/functions.
|
|
72
|
+
_assignBind() {
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
try {
|
|
75
|
+
this.bind.forEach(bind => {
|
|
76
|
+
if (this[bind]) for (let x in this[bind]) {
|
|
77
|
+
if (typeof this[bind][x] === 'function') {
|
|
78
|
+
this[bind][x] = this[bind][x].bind(this);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
// bind translate
|
|
83
|
+
const translate = this.agent && this.agent.translate && typeof this.agent.translate === 'function';
|
|
84
|
+
if (translate) this.agent.translate = this.agent.translate.bind(this);
|
|
85
|
+
// bind parser
|
|
86
|
+
const parse = this.agent && this.agent.parse && typeof this.agent.parse === 'function';
|
|
87
|
+
if (parse) this.agent.parse = this.agent.parse.bind(this);
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
return reject(e);
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
return resolve();
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Called from the init function to assign the listeners to various states.
|
|
99
|
+
// when the listener fires it will call the associated named function.
|
|
100
|
+
_assignListeners() {
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
try {
|
|
103
|
+
// set the default listeners for the states of the agent.
|
|
104
|
+
for (let state in this.states) {
|
|
105
|
+
this.events.on(`${this.agent.key}:${state}`, packet => {
|
|
106
|
+
return this[state](packet);
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
// set the assigned listeners for the agent.
|
|
110
|
+
for (let listener in this.listeners) {
|
|
111
|
+
this.events.on(listener, packet => {
|
|
112
|
+
return this.listeners[listener](packet);
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
return reject(e);
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
return resolve();
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Some elements will inherit the data of the parent. this object will loop over
|
|
126
|
+
// any children data that theis deva has and assign the inherited information.
|
|
127
|
+
_assignInherit() {
|
|
128
|
+
return new Promise((resolve, reject) => {
|
|
129
|
+
try {
|
|
130
|
+
for (let d in this.devas) {
|
|
131
|
+
this.inherit.forEach(inherit => {
|
|
132
|
+
this.devas[d][inherit] = this[inherit];
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch (e) {
|
|
137
|
+
return reject(e);
|
|
138
|
+
}
|
|
139
|
+
finally {
|
|
140
|
+
return resolve();
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// General handler for when a method is NOT found from a user command.
|
|
146
|
+
_methodNotFound(packet) {
|
|
147
|
+
packet.a = {
|
|
148
|
+
agent: this.agent || false,
|
|
149
|
+
client: this.client || false,
|
|
150
|
+
text: `${packet.q.meta.method} is NOT a valid method.`,
|
|
151
|
+
meta: {
|
|
152
|
+
key: this.agent.key,
|
|
153
|
+
method: packet.q.meta.method,
|
|
154
|
+
},
|
|
155
|
+
created: Date.now(),
|
|
156
|
+
};
|
|
157
|
+
return packet;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// A simple interface to generate a unique id for the agent. As agents will
|
|
161
|
+
// quite oftne have to key their transactions. This will provide all agents
|
|
162
|
+
// with the same key generator which can also be modified to link into a remote
|
|
163
|
+
// generator or some other solution if needed.
|
|
164
|
+
uid() {
|
|
165
|
+
const min = Math.floor(Date.now() - (Date.now() / Math.PI));
|
|
166
|
+
const max = Math.floor(Date.now() + (Date.now() * Math.PI));
|
|
167
|
+
return Math.floor(Math.random() * (max - min)) + min;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// The talk interface binds to the events emitter to allow agents to perform a
|
|
171
|
+
// this.talk(*) feature.
|
|
172
|
+
talk(evt, resource=false) {
|
|
173
|
+
return this.events.emit(evt, resource);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// the listen interface binds to the event emitter to allow agents to listen
|
|
177
|
+
// this.listen(*) feature.
|
|
178
|
+
listen(evt, callback) {
|
|
179
|
+
return this.events.on(evt, callback);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Instances where listening for only one unique keyed event is required
|
|
183
|
+
// this interface is provided for the this.once(*) feature.
|
|
184
|
+
once(evt, callback) {
|
|
185
|
+
return this.events.once(evt, callback);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// where an agent needs to ignore events or remove a lisatener this interface
|
|
189
|
+
// serves the this.ignore(*) feature.
|
|
190
|
+
ignore(evt, callback) {
|
|
191
|
+
return this.events.removeListener(evt, callback);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Used when loading a Deva dynamically into the current set.
|
|
195
|
+
load(opts) {
|
|
196
|
+
this.devas[opts.key] = opts;
|
|
197
|
+
// inherit the data to the new deva.
|
|
198
|
+
this.inherit.forEach(inherit => {
|
|
199
|
+
this.devas[agent][inherit] = this[inherit];
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
return Promise.resolve();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Used when unloading a deva dynamically from the set.
|
|
206
|
+
unload(agent) {
|
|
207
|
+
delete this.devas[agent];
|
|
208
|
+
return Promise.resolve();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Askign a question to another deva in the set besides itself. If the question
|
|
212
|
+
// interface detects the action is to ask another deva a question with
|
|
213
|
+
// this.askChr variable match. Then an answer packet is generated and the
|
|
214
|
+
// deva is asked to process the question asked and return it's proper data set
|
|
215
|
+
// from the requested method.
|
|
216
|
+
// this is an event function that relies on talk/listen
|
|
217
|
+
|
|
218
|
+
ask(packet) {
|
|
219
|
+
if (!this.active) return Promise.resolve(this.messages.offline);
|
|
220
|
+
|
|
221
|
+
this._state = this.states.ask;
|
|
222
|
+
packet.a = {
|
|
223
|
+
agent: this.agent || false,
|
|
224
|
+
client: this.client || false,
|
|
225
|
+
meta: {
|
|
226
|
+
key: this.agent.key,
|
|
227
|
+
method: packet.q.meta.method,
|
|
228
|
+
params: packet.q.meta.params,
|
|
229
|
+
},
|
|
230
|
+
text: false,
|
|
231
|
+
html: false,
|
|
232
|
+
data: false,
|
|
233
|
+
created: Date.now(),
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
if (this.methods[packet.q.meta.method] === undefined) {
|
|
238
|
+
return setImmediate(() => {
|
|
239
|
+
packet.a.text = `INVALID METHOD (${packet.q.meta.method})`;
|
|
240
|
+
this.talk(`${this.agent.key}:ask:${packet.id}`, packet);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// The method is parsed and depending on what method is asked for it returns
|
|
245
|
+
// the response based on the passed through packet.
|
|
246
|
+
this.methods[packet.q.meta.method](packet).then(result => {
|
|
247
|
+
if (typeof result === 'object') {
|
|
248
|
+
packet.a.text = result.text || false;
|
|
249
|
+
packet.a.html = result.html || false;
|
|
250
|
+
packet.a.data = result.data || false;
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
packet.a.text = result;
|
|
254
|
+
}
|
|
255
|
+
// talk back to the once event with the ask key.
|
|
256
|
+
this.talk(`${this.agent.key}:ask:${packet.id}`, packet);
|
|
257
|
+
}).catch(err => {
|
|
258
|
+
this._state = this.states.error;
|
|
259
|
+
// If the ask method fails then a reject error is returned from the this.error
|
|
260
|
+
// interface.
|
|
261
|
+
this.talk(`${this.agent.key}:ask:${packet.id}`, {error:err.toString()});
|
|
262
|
+
return this.error(err, packet);
|
|
263
|
+
})
|
|
264
|
+
}
|
|
265
|
+
catch (e) {
|
|
266
|
+
this._state = this.states.error;
|
|
267
|
+
// if any error is caught in the processing of the ask then it returns and
|
|
268
|
+
// executes the this.error(*) interface.
|
|
269
|
+
this.talk(`${this.agent.key}:ask:${packet.id}`, {error:e.toString()});
|
|
270
|
+
return this.error(e, packet)
|
|
271
|
+
}
|
|
272
|
+
// now when we ask the meta params[0] should be the method
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// general question interface.
|
|
276
|
+
// accepts two arguments a *TEXT* and *DATA* object.
|
|
277
|
+
// if the question being asked is a simple text command then
|
|
278
|
+
// this.question('#*agent.key *method* *text*')
|
|
279
|
+
// if the question is a data object
|
|
280
|
+
// this.question('#*agent.key* *method* *properties*', {*data*});
|
|
281
|
+
question(TEXT=false, DATA=false) {
|
|
282
|
+
this._state = this.states.question;
|
|
283
|
+
const id = this.uid();
|
|
284
|
+
const t_split = TEXT.split(' ');
|
|
285
|
+
const isAsk = t_split[0].startsWith(this.askChr) ? t_split[0].substring(1) : false;
|
|
286
|
+
const isCmd = t_split[0].startsWith(this.cmdChr) ? t_split[0].substring(1) : false;
|
|
287
|
+
// Format the packet for return on the request.
|
|
288
|
+
const orig = TEXT;
|
|
289
|
+
const data = DATA;
|
|
290
|
+
const packet = {
|
|
291
|
+
id,
|
|
292
|
+
q: {},
|
|
293
|
+
a: {},
|
|
294
|
+
created: Date.now(),
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
let text = TEXT,
|
|
298
|
+
params = false,
|
|
299
|
+
method = 'question',
|
|
300
|
+
key = this.agent.key;
|
|
301
|
+
|
|
302
|
+
return new Promise((resolve, reject) => {
|
|
303
|
+
if (!TEXT) return reject(this.messages.notext);
|
|
304
|
+
try {
|
|
305
|
+
if (!this.active) return reject(this.messages.offline);
|
|
306
|
+
|
|
307
|
+
// *: send just a string of text
|
|
308
|
+
// !: send a command to the local agent
|
|
309
|
+
// #: ask another agent a question
|
|
310
|
+
// #agent method:param1:param2 with text strings for proccessing
|
|
311
|
+
// !method param:list:parse for the local agent
|
|
312
|
+
// if is an ask then we format one way
|
|
313
|
+
if (isAsk) {
|
|
314
|
+
params = t_split[1] ? t_split[1].split(':') : false;
|
|
315
|
+
method = params[0];
|
|
316
|
+
text = t_split.slice(2).join(' ').trim();
|
|
317
|
+
key = isAsk;
|
|
318
|
+
}
|
|
319
|
+
else if (isCmd) {
|
|
320
|
+
params = t_split[1] ? t_split[1].split(':') : false;
|
|
321
|
+
method = isCmd;
|
|
322
|
+
text = t_split.slice(1).join(' ').trim()
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
packet.q = {
|
|
326
|
+
agent: this.agent || false,
|
|
327
|
+
client: this.client || false,
|
|
328
|
+
meta: {
|
|
329
|
+
key,
|
|
330
|
+
orig,
|
|
331
|
+
method,
|
|
332
|
+
params,
|
|
333
|
+
},
|
|
334
|
+
text,
|
|
335
|
+
data,
|
|
336
|
+
created: Date.now(),
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// if is a command then we format another way
|
|
340
|
+
// if the user asks a question to another deva '#' then issue the talk/once
|
|
341
|
+
// event combination.
|
|
342
|
+
if (isAsk) {
|
|
343
|
+
this._state = this.states.ask;
|
|
344
|
+
this.talk(`${isAsk}:ask`, packet);
|
|
345
|
+
this.once(`${isAsk}:ask:${packet.id}`, answer => {
|
|
346
|
+
return resolve(answer);
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
// if the user sends a local command '$' then it will ask of the self.
|
|
350
|
+
else {
|
|
351
|
+
if (typeof this.methods[method] !== 'function') return resolve(this._methodNotFound(packet));
|
|
352
|
+
this.methods[method](packet).then(result => {
|
|
353
|
+
const text = typeof result === 'object' ? result.text : result;
|
|
354
|
+
const html = typeof result === 'object' ? result.html : result;
|
|
355
|
+
const data = typeof result === 'object' ? result.data : false;
|
|
356
|
+
packet.a = {
|
|
357
|
+
agent: this.agent || false,
|
|
358
|
+
client: this.client || false,
|
|
359
|
+
meta: {
|
|
360
|
+
key: this.agent.key,
|
|
361
|
+
method,
|
|
362
|
+
},
|
|
363
|
+
text,
|
|
364
|
+
html,
|
|
365
|
+
data,
|
|
366
|
+
created: Date.now(),
|
|
367
|
+
};
|
|
368
|
+
this._state = this.states.answer;
|
|
369
|
+
return resolve(packet);
|
|
370
|
+
}).catch(err => {
|
|
371
|
+
return this.error(err, packet);
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
catch(e) {
|
|
376
|
+
return this.error(e);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
// The main init interface where the chain begins.
|
|
383
|
+
// a set of options is passed into the init function which is the configuration
|
|
384
|
+
// object. from this opts object the system is built. After the opts object is processed
|
|
385
|
+
// the inherit is assigned and then bind then listners then
|
|
386
|
+
// opts: The options object containing the necessary vaules to build a Deva.
|
|
387
|
+
init() {
|
|
388
|
+
// set client
|
|
389
|
+
this._state = this.states.init;
|
|
390
|
+
return new Promise((resolve, reject) => {
|
|
391
|
+
this.events.setMaxListeners(this.maxListeners);
|
|
392
|
+
this._assignInherit().then(() => {
|
|
393
|
+
return this._assignBind();
|
|
394
|
+
}).then(() => {
|
|
395
|
+
return this._assignListeners();
|
|
396
|
+
}).then(() => {
|
|
397
|
+
return this.onInit ? this.onInit() : this.start();
|
|
398
|
+
}).then(started => {
|
|
399
|
+
return resolve(started)
|
|
400
|
+
}).catch(err => {
|
|
401
|
+
return reject(err);
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Interface for unified error reporting within all devas.
|
|
407
|
+
// this.error(*error*, *packet*) can be issued at time of any error.
|
|
408
|
+
// e: is the error to pass into the interface.
|
|
409
|
+
// packet: the packet that caused the error.
|
|
410
|
+
error(err,packet=false,reject=false) {
|
|
411
|
+
this._state = 'error';
|
|
412
|
+
// broadcast a global uniform error event.
|
|
413
|
+
this.talk('error', {
|
|
414
|
+
id: this.uid(),
|
|
415
|
+
agent: this.agent,
|
|
416
|
+
client: this.client,
|
|
417
|
+
error: err.toString('utf8'),
|
|
418
|
+
data: packet,
|
|
419
|
+
created: Date.now(),
|
|
420
|
+
});
|
|
421
|
+
// call the onError if there is a logcal one.
|
|
422
|
+
// if there is no local error return a promise reject.
|
|
423
|
+
if (this.onError) return this.onError(err, packet, reject);
|
|
424
|
+
return reject ? reject(err) : false;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// start the deva then return the 'onStart' function.
|
|
428
|
+
start() {
|
|
429
|
+
if (this.active) return;
|
|
430
|
+
this._state = 'start';
|
|
431
|
+
this.active = Date.now();
|
|
432
|
+
return this.onStart ? this.onStart() : this.enter();
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// stop teh deva then return the onStop function.
|
|
436
|
+
stop() {
|
|
437
|
+
if (!this.active) return Promise.resolve(this.messages.offline);
|
|
438
|
+
this.active = false;
|
|
439
|
+
this._state = 'stop';
|
|
440
|
+
return this.onStop ? this.onStop() : this.exit();
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// enter the deva then return the onEnter function.
|
|
444
|
+
enter() {
|
|
445
|
+
if (!this.active) return Promise.resolve(this.messages.offline);
|
|
446
|
+
this._state = 'enter';
|
|
447
|
+
return this.onEnter ? this.onEnter() : this.done(this.state)
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// exit the deva then return the onExit function.
|
|
451
|
+
exit() {
|
|
452
|
+
if (!this.active) return Promise.resolve(this.messages.offline);
|
|
453
|
+
this._state = 'exit';
|
|
454
|
+
return this.onExit ? this.onExit() : this.done(this.state)
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// set the deva as done then return the oDone function.
|
|
458
|
+
done(msg=false) {
|
|
459
|
+
if (!this.active) return Promise.resolve(this.messages.offline);
|
|
460
|
+
this._state = 'done';
|
|
461
|
+
msg = msg ? msg : this.state;
|
|
462
|
+
return this.onDone ? this.onDone() : Promise.resolve({msg,agent:this.agent})
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// interface to return the status of the current deva with the time/date requested.
|
|
466
|
+
status(addtl=false) {
|
|
467
|
+
if (!this.active) return Promise.resolve(this.messages.offline);
|
|
468
|
+
const id = this.uid();
|
|
469
|
+
const dateFormat = new Intl.DateTimeFormat('en-US', { dateStyle: 'medium', timeStyle: 'medium' }).format(this.active);
|
|
470
|
+
let text = `${this.agent.name} is ONLINE since ${dateFormat}`;
|
|
471
|
+
if (addtl) text = text + `\n${addtl}`;
|
|
472
|
+
return Promise.resolve({text});
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// universal prompt emitter
|
|
476
|
+
prompt(text) {
|
|
477
|
+
this.talk('prompt', {text, prompt:this.agent.prompt});
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// universal hash builder
|
|
481
|
+
hash(packet) {
|
|
482
|
+
if (!this.vars.hash) this.vars.hash = '0x';
|
|
483
|
+
// setup basic hashing
|
|
484
|
+
// what type of hash depends on param 1
|
|
485
|
+
return new Promise((resolve, reject) => {
|
|
486
|
+
if (!packet) return reject('NO PACKET');
|
|
487
|
+
const params = packet.q.text.split(' ');
|
|
488
|
+
const hashType = params[0] ? params[0] : 'view';
|
|
489
|
+
switch (hashType) {
|
|
490
|
+
case 'clear':
|
|
491
|
+
this.vars.hash = '0x';
|
|
492
|
+
break;
|
|
493
|
+
case 'add':
|
|
494
|
+
this.vars.hash = `${this.vars.hash}${params[1]}`;
|
|
495
|
+
break;
|
|
496
|
+
}
|
|
497
|
+
return resolve({
|
|
498
|
+
text:this.vars.hash,
|
|
499
|
+
html:`<div class="hash">${this.vars.hash}</div>`
|
|
500
|
+
});
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
// initDeva interface is to initialize devas that this deva is a parent of.
|
|
504
|
+
// This feature allows a Deva to be a parent of a parent of a parent etc....
|
|
505
|
+
initDevas() {
|
|
506
|
+
return new Promise((resolve, reject) => {
|
|
507
|
+
const devas = [];
|
|
508
|
+
for (let x in this.devas) {
|
|
509
|
+
devas.push(this.devas[x].init());
|
|
510
|
+
}
|
|
511
|
+
Promise.all(devas).then(() => {
|
|
512
|
+
return resolve(this.messages.loaded);
|
|
513
|
+
}).catch(reject);
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
stopDevas() {
|
|
517
|
+
return new Promise((resolve, reject) => {
|
|
518
|
+
const devas = [];
|
|
519
|
+
for (let x in this.devas) {
|
|
520
|
+
devas.push(this.devas[x].stop());
|
|
521
|
+
}
|
|
522
|
+
Promise.all(devas).then(() => {
|
|
523
|
+
return resolve(this.messages.stopped);
|
|
524
|
+
}).catch(reject);
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
module.exports = Deva;
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@indra.ai/deva",
|
|
3
|
+
"version": "1.0.27",
|
|
4
|
+
"description": "The Deva Core",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/indraai/deva.git"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"indra",
|
|
15
|
+
"deva",
|
|
16
|
+
"ai"
|
|
17
|
+
],
|
|
18
|
+
"author": "Quinn Michaels",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/indraai/deva/issues"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/indraai/deva#readme",
|
|
24
|
+
"eslintConfig": {
|
|
25
|
+
"parserOptions": {
|
|
26
|
+
"ecmaVersion": 6
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"npm": ">=6.0.0",
|
|
31
|
+
"node": ">=10.0.0"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {}
|
|
34
|
+
}
|