okai 0.0.24 → 0.0.25

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.
@@ -0,0 +1,240 @@
1
+ import { pick, toCamelCase, toPascalCase } from "./utils.js";
2
+ // Tranforms that are only applied once on AI TypeScript AST
3
+ export function createTdAstFromAIAst(tsAst) {
4
+ mergeInterfacesAndClasses(tsAst);
5
+ rewriteToPascalCase(tsAst);
6
+ replaceReferences(tsAst);
7
+ replaceIds(tsAst);
8
+ tsAst.classes.forEach(cls => {
9
+ // replaceUserRefs(cls)
10
+ rewriteDuplicateTypePropNames(cls);
11
+ rewriteSelfReferencingIds(cls);
12
+ });
13
+ changeUserRefsToAuditBase(tsAst);
14
+ return tsAst;
15
+ }
16
+ /*
17
+ function replaceUserRefs(type:ParsedClass) {
18
+ type.name = toPascalCase(type.name)
19
+ type.properties?.forEach(prop => {
20
+ prop.name = toCamelCase(prop.name)
21
+ if (prop.type === 'User' || prop.name === 'userId') {
22
+ type.extends = 'AuditBase'
23
+ }
24
+
25
+ if (prop.type.startsWith('Array<')) {
26
+ const elType = prop.type.slice('Array<'.length, -1)
27
+ prop.type = elType + '[]'
28
+ }
29
+ if (prop.type === 'User') {
30
+ prop.name = 'userId'
31
+ prop.type = 'string'
32
+ }
33
+ if (prop.type === 'User[]') {
34
+ if (prop.name.endsWith('s')) {
35
+ prop.name = prop.name.slice(0, -1) + 'Ids'
36
+ }
37
+ prop.type = 'string[]'
38
+ }
39
+ })
40
+ }
41
+ */
42
+ // Replace User Tables and FKs with AuditBase tables and
43
+ export function transformUserRefs(tsAst, info) {
44
+ const addClasses = [];
45
+ for (const cls of tsAst.classes) {
46
+ const removeProps = [];
47
+ for (const prop of cls.properties) {
48
+ const propLower = prop.name.toLowerCase();
49
+ if (propLower === 'userid') {
50
+ removeProps.push(prop.name);
51
+ }
52
+ if (prop.type === 'User') {
53
+ cls.extends = 'AuditBase';
54
+ // Replace with local User Type
55
+ /*
56
+ [Reference(SelfId = nameof(CreatedBy), RefId = nameof(User.UserName), RefLabel = nameof(User.DisplayName))]
57
+ public User UserRef { get; set; }
58
+ */
59
+ if (info.userType)
60
+ prop.type = info.userType;
61
+ if (!prop.annotations)
62
+ prop.annotations = [];
63
+ const attr = {
64
+ name: 'reference',
65
+ args: {
66
+ selfId: 'createdBy',
67
+ refId: 'userName',
68
+ }
69
+ };
70
+ if (info.userLabel)
71
+ attr.args.refLabel = info.userLabel;
72
+ prop.annotations.push(attr);
73
+ }
74
+ if (prop.type === 'User[]') {
75
+ if (info.userType) {
76
+ prop.type = info.userType + '[]';
77
+ if (!prop.annotations)
78
+ prop.annotations = [];
79
+ prop.annotations.push({ name: 'reference' });
80
+ const idPropType = cls.properties.find(x => x.name.toLowerCase() === 'id')?.type ?? 'number';
81
+ // Add Many to Many User Table
82
+ addClasses.push({
83
+ name: cls.name + 'User',
84
+ properties: [
85
+ { name: 'id', type: 'number' },
86
+ { name: toCamelCase(cls.name) + 'Id', type: idPropType },
87
+ { name: toCamelCase(info.userType) + 'Id', type: info.userIdType ?? 'string' },
88
+ ]
89
+ });
90
+ }
91
+ }
92
+ }
93
+ if (removeProps.length) {
94
+ cls.extends = 'AuditBase';
95
+ cls.properties = cls.properties.filter(x => !removeProps.includes(x.name));
96
+ }
97
+ }
98
+ if (addClasses.length) {
99
+ tsAst.classes.push(...addClasses);
100
+ }
101
+ // Remove User Table if local User Table exists
102
+ if (info.userType) {
103
+ tsAst.classes = tsAst.classes.filter(x => x.name !== 'User');
104
+ }
105
+ }
106
+ function rewriteDuplicateTypePropNames(type) {
107
+ const duplicateTypePropMap = {
108
+ note: 'content',
109
+ };
110
+ const duplicateProp = type.properties?.find(x => toPascalCase(x.name) === type.name);
111
+ if (duplicateProp) {
112
+ const newName = duplicateTypePropMap[duplicateProp.name] ?? 'value';
113
+ duplicateProp.name = newName;
114
+ }
115
+ }
116
+ function rewriteSelfReferencingIds(type) {
117
+ const selfRefId = type.properties?.find(x => x.name.toLowerCase() === `${type.name}id`.toLowerCase());
118
+ if (selfRefId) {
119
+ selfRefId.name = `parentId`;
120
+ }
121
+ }
122
+ function rewriteToPascalCase(ast) {
123
+ ast?.classes.forEach(t => {
124
+ t.name = toPascalCase(t.name);
125
+ t.properties?.forEach(p => p.name = toCamelCase(p.name));
126
+ });
127
+ ast.enums?.forEach(e => {
128
+ e.name = toPascalCase(e.name);
129
+ e.members?.forEach(m => {
130
+ m.name = toPascalCase(m.name);
131
+ });
132
+ });
133
+ }
134
+ function changeUserRefsToAuditBase(ast) {
135
+ const user = ast.classes?.find(x => x.name === 'User') ?? ast.interfaces?.find(x => x.name === 'User');
136
+ if (user) {
137
+ user.properties?.forEach(prop => {
138
+ // If User Model references any other model, chnage it to extend AuditBase
139
+ const ref = ast.classes?.find(x => x.name === prop.type)
140
+ ?? ast.interfaces?.find(x => x.name === prop.type);
141
+ if (ref) {
142
+ ref.extends = 'AuditBase';
143
+ }
144
+ // If User Model references any other model[], chnage it to extend AuditBase
145
+ const refs = ast.classes?.find(x => prop.type.endsWith('[]') && x.name === prop.type.substring(0, prop.type.length - 2))
146
+ ?? ast.interfaces?.find(x => prop.type.endsWith('[]') && x.name === prop.type.substring(0, prop.type.length - 2));
147
+ if (refs) {
148
+ refs.extends = 'AuditBase';
149
+ }
150
+ });
151
+ }
152
+ }
153
+ function mergeInterfacesAndClasses(ast) {
154
+ const classes = [];
155
+ for (const iface of ast.interfaces) {
156
+ const cls = interfaceToClass(iface);
157
+ classes.push(cls);
158
+ }
159
+ for (const cls of ast.classes) {
160
+ classes.push(cls);
161
+ }
162
+ ast.classes = classes;
163
+ ast.interfaces = [];
164
+ }
165
+ function interfaceToClass(ast) {
166
+ return pick(ast, ['name', 'extends', 'comment', 'properties', 'annotations']);
167
+ }
168
+ export function replaceReferences(tsAst) {
169
+ const references = [
170
+ 'Service',
171
+ ];
172
+ // The most important types are the ones with the most references
173
+ const refCount = (t) => t.properties?.filter(p => tsAst.classes.find(x => x.name === p.type)).length || 0;
174
+ const importantTypes = tsAst.classes.sort((x, y) => refCount(y) - refCount(x));
175
+ for (const cls of tsAst.classes) {
176
+ if (references.includes(cls.name)) {
177
+ const importantType = importantTypes.find(x => x.properties?.some(p => p.type === cls.name));
178
+ if (importantType) {
179
+ const newName = `${importantType.name}${cls.name}`;
180
+ replaceReference(tsAst, cls.name, newName);
181
+ }
182
+ }
183
+ }
184
+ }
185
+ export function replaceReference(gen, fromType, toType) {
186
+ for (const cls of gen.classes) {
187
+ if (cls.name === fromType) {
188
+ cls.name = toType;
189
+ }
190
+ if (cls.properties) {
191
+ for (const prop of cls.properties) {
192
+ if (prop.type === fromType) {
193
+ prop.type = toType;
194
+ }
195
+ if (prop.type === `${fromType}[]`) {
196
+ prop.type = `${toType}[]`;
197
+ }
198
+ 2;
199
+ if (prop.name === fromType) {
200
+ prop.name = toType;
201
+ }
202
+ if (prop.name === `${fromType}Id`) {
203
+ prop.name = `${toType}Id`;
204
+ }
205
+ }
206
+ }
207
+ }
208
+ }
209
+ export function replaceIds(gen) {
210
+ for (const type of gen.classes) {
211
+ const explicitIdProp = type.properties?.find(x => x.name.toLowerCase() === `${type.name}Id`.toLowerCase());
212
+ if (explicitIdProp) {
213
+ const hasId = type.properties.find(x => x.name === 'id');
214
+ if (hasId) {
215
+ explicitIdProp.name = 'parentId';
216
+ explicitIdProp.optional = true;
217
+ }
218
+ else {
219
+ explicitIdProp.name = 'id';
220
+ }
221
+ }
222
+ else {
223
+ // If using a shortened id for the type e.g. (PerformanceReview, ReviewId)
224
+ const firstProp = type.properties?.[0];
225
+ if (firstProp?.name.endsWith('Id') && type.name.toLowerCase().includes(firstProp.name.substring(0, firstProp.name.length - 2).toLowerCase())) {
226
+ firstProp.name = 'id';
227
+ }
228
+ }
229
+ }
230
+ // Replace all string Ids with int Ids
231
+ const anyIntPks = gen.classes.some(x => x.properties?.some(p => p.name === 'id' && p.type === 'number'));
232
+ if (!anyIntPks) {
233
+ for (const type of gen.classes) {
234
+ const idProp = type.properties?.find(x => x.name === 'id');
235
+ if (idProp) {
236
+ idProp.type = 'number';
237
+ }
238
+ }
239
+ }
240
+ }
package/dist/ts-parser.js CHANGED
@@ -1,15 +1,20 @@
1
+ import { lastLeftPart, leftPart, rightPart } from "./utils.js";
1
2
  export class TypeScriptParser {
2
3
  static CLASS_PATTERN = /class\s+(\w+)(?:\s+extends\s+(\w+))?(?:\s+implements\s+([\w,\s]+))?\s*{/g;
3
4
  static INTERFACE_PATTERN = /interface\s+(\w+)(?:\s+extends\s+(\w+))?\s*{/g;
4
5
  static ENUM_PATTERN = /enum\s+(\w+)\s*{([^}]*)}/g;
5
6
  static PROPERTY_PATTERN = /(?:(?<modifier>private|public|protected|readonly)\s+)*(?<name>\w+)(?<optional>\?)?\s*:\s*(?<type>[\w<>[\],\s]+)(?<union>\|\s*[\w<>[\],|,\s]+)?\s*;?/;
6
7
  static ENUM_MEMBER_PATTERN = /(\w+)\s*(?:=\s*("[^"]*"|'[^']*'|\d+|[^,\n]+))?\s*/;
7
- // private static readonly ANNOTATION_PATTERN = /@(\w+\.?\w*)\s*\((.*)\)/
8
- static ANNOTATION_PATTERN = /@([A-Za-z_][A-Za-z0-9_]*\.?[A-Za-z_]?[A-Za-z0-9_]*)\s*\((.*)\)/;
8
+ static ANNOTATION_PATTERN = /^\s*@([A-Za-z_][A-Za-z0-9_]*\.?[A-Za-z_]?[A-Za-z0-9_]*)/;
9
+ static REFERENCE_PATTERN = /\/\/\/\s*<reference\s+path="([^"]+)"\s*\/>/g;
9
10
  classes = [];
10
11
  interfaces = [];
11
12
  enums = [];
13
+ references = [];
12
14
  getLineComment(line) {
15
+ if (line.match(TypeScriptParser.REFERENCE_PATTERN)) {
16
+ return undefined;
17
+ }
13
18
  // Check for single line comment at end of line
14
19
  const singleLineMatch = line.match(/.*?\/\/\s*(.+)$/);
15
20
  if (singleLineMatch) {
@@ -27,7 +32,8 @@ export class TypeScriptParser {
27
32
  const lineNumber = beforePosition.split('\n').length;
28
33
  if (lineNumber > 0) {
29
34
  const lines = content.split('\n');
30
- return lines[lineNumber - 2]; // -2 because array is 0-based and we want previous line
35
+ const ret = lines[lineNumber - 2]; // -2 because array is 0-based and we want previous line
36
+ return ret;
31
37
  }
32
38
  return undefined;
33
39
  }
@@ -39,36 +45,19 @@ export class TypeScriptParser {
39
45
  while (previousLine && (!previousLine.match(TypeScriptParser.PROPERTY_PATTERN) || previousLine.match(ANNOTATION))) {
40
46
  const annotation = previousLine.match(ANNOTATION) ? parseAnnotation(previousLine) : undefined;
41
47
  if (annotation) {
42
- if (previousLine.trimStart().startsWith('//')) {
43
- annotation.comment = true;
44
- }
45
48
  annotations.push(annotation);
46
49
  }
47
50
  else {
48
- const comment = this.getLineComment(previousLine);
51
+ const comment = this.isComment(previousLine) ? this.getLineComment(previousLine) : null;
49
52
  if (comment) {
50
- const annotation = comment.match(ANNOTATION) ? parseAnnotation(comment) : undefined;
51
- if (annotation) {
52
- annotation.comment = true;
53
- annotations.push(annotation);
54
- }
55
- else {
56
- commments.unshift(comment);
57
- }
53
+ commments.unshift(comment);
58
54
  }
59
55
  }
60
56
  previousLine = this.getPreviousLine(body, body.indexOf(previousLine));
61
57
  }
62
58
  const lineComment = this.getLineComment(line);
63
59
  if (lineComment) {
64
- const annotation = lineComment.match(ANNOTATION) ? parseAnnotation(lineComment) : undefined;
65
- if (annotation) {
66
- annotation.comment = true;
67
- annotations.push(annotation);
68
- }
69
- else {
70
- commments.push(lineComment);
71
- }
60
+ commments.push(lineComment);
72
61
  }
73
62
  else if (line.match(ANNOTATION)) {
74
63
  const annotation = parseAnnotation(line);
@@ -190,6 +179,12 @@ export class TypeScriptParser {
190
179
  this.classes.push(cls);
191
180
  }
192
181
  }
182
+ parseReferences(content) {
183
+ let match;
184
+ while ((match = TypeScriptParser.REFERENCE_PATTERN.exec(content))) {
185
+ this.references.push({ path: match[1] });
186
+ }
187
+ }
193
188
  parseEnumMembers(enumBody) {
194
189
  const members = [];
195
190
  const lines = enumBody.split('\n')
@@ -215,7 +210,7 @@ export class TypeScriptParser {
215
210
  prevIntValue = member.value;
216
211
  }
217
212
  const previousLine = this.getPreviousLine(enumBody, enumBody.indexOf(line));
218
- if (previousLine) {
213
+ if (previousLine && this.isComment(previousLine)) {
219
214
  member.comment = this.getLineComment(previousLine);
220
215
  }
221
216
  const lineComment = this.getLineComment(line);
@@ -227,6 +222,12 @@ export class TypeScriptParser {
227
222
  });
228
223
  return members;
229
224
  }
225
+ isComment(s) {
226
+ if (!s)
227
+ return false;
228
+ s = s.trim();
229
+ return s.startsWith('//') || s.startsWith('/*');
230
+ }
230
231
  parseEnums(content) {
231
232
  let match;
232
233
  while ((match = TypeScriptParser.ENUM_PATTERN.exec(content))) {
@@ -249,10 +250,12 @@ export class TypeScriptParser {
249
250
  this.classes = [];
250
251
  this.interfaces = [];
251
252
  this.enums = [];
253
+ this.parseReferences(sourceCode);
252
254
  this.parseInterfaces(sourceCode);
253
255
  this.parseClasses(sourceCode);
254
256
  this.parseEnums(sourceCode);
255
257
  return {
258
+ references: this.references,
256
259
  classes: this.classes,
257
260
  interfaces: this.interfaces,
258
261
  enums: this.enums
@@ -260,12 +263,18 @@ export class TypeScriptParser {
260
263
  }
261
264
  }
262
265
  export function parseAnnotation(annotation) {
263
- // Match @name and everything inside ()
264
- const regex = /@(\w+\.?\w*)\s*\((.*)\)/;
266
+ const regex = TypeScriptParser.ANNOTATION_PATTERN;
267
+ if (annotation.includes('//')) {
268
+ annotation = leftPart(annotation, '//');
269
+ }
265
270
  const match = annotation.match(regex);
266
271
  if (!match)
267
272
  return null;
268
- const [, name, paramsStr] = match;
273
+ const [, name] = match;
274
+ // Extract parameters if they exist
275
+ const paramsStr = annotation.includes('(') && annotation.includes(')')
276
+ ? lastLeftPart(rightPart(annotation, '('), ')')
277
+ : '';
269
278
  try {
270
279
  // Handle multiple arguments by splitting on commas outside quotes/braces
271
280
  const rawArgs = splitArgs(paramsStr);
package/dist/tsd-gen.js CHANGED
@@ -1,35 +1,24 @@
1
- import { toPascalCase, toCamelCase } from "./utils.js";
2
1
  export class TsdGenerator {
3
2
  interfaces = [];
4
3
  enums = [];
5
- ast = { classes: [], interfaces: [], enums: [] };
6
- clsToInterface(ast) {
7
- const to = {
8
- name: ast.name,
9
- extends: ast.extends,
10
- comment: ast.comment,
11
- properties: ast.properties,
12
- annotations: ast.annotations,
13
- };
14
- return to;
15
- }
4
+ ast = { references: [], classes: [], interfaces: [], enums: [] };
16
5
  attrValue(type, value) {
17
6
  return type === 'string' ? `"${value}"` : value;
18
7
  }
19
8
  toAttr(attr) {
20
- const sbArgs = [];
9
+ const sbCtorArgs = [];
21
10
  if (attr?.constructorArgs?.length) {
22
11
  for (const arg of attr.constructorArgs) {
23
- sbArgs.push(this.attrValue(typeof arg, arg));
12
+ sbCtorArgs.push(this.attrValue(typeof arg, arg));
24
13
  }
25
14
  }
15
+ const sbArgs = [];
26
16
  if (attr.args) {
27
17
  for (const [name, value] of Object.entries(attr.args)) {
28
- sbArgs.push(`${name}=${this.attrValue(typeof value, value)}`);
18
+ sbArgs.push(`${name}:${this.attrValue(typeof value, value)}`);
29
19
  }
30
20
  }
31
- const prefix = attr.comment ? '// ' : '';
32
- return `${prefix}@${attr.name}(${sbArgs.join(',')})`;
21
+ return `@${attr.name}(${sbCtorArgs.join(',')}${sbCtorArgs.length && sbArgs.length ? ',' : ''}${sbArgs.length ? `{${sbArgs.join(',')}}` : ''})`;
33
22
  }
34
23
  toInterface(ast) {
35
24
  return this.toType(ast, 'interface');
@@ -82,84 +71,32 @@ export class TsdGenerator {
82
71
  sb.push('}');
83
72
  return sb.join('\n');
84
73
  }
85
- generate(ast, type = 'interface') {
74
+ generate(ast) {
86
75
  this.ast = ast;
87
76
  const sb = [];
77
+ if (ast.references?.length) {
78
+ for (const ref of ast.references) {
79
+ sb.push(`/// <reference path="${ref.path}" />`);
80
+ }
81
+ sb.push('');
82
+ }
88
83
  for (const cls of ast.enums ?? []) {
89
84
  sb.push(this.toEnum(cls));
90
85
  sb.push('');
91
86
  }
92
87
  for (const cls of ast.interfaces ?? []) {
93
- sb.push(this.toType(cls, type));
88
+ sb.push(this.toType(cls, "interface"));
94
89
  sb.push('');
95
90
  }
96
91
  for (const cls of ast.classes ?? []) {
97
- const iface = this.clsToInterface(cls);
98
- sb.push(this.toType(iface, type));
92
+ sb.push(this.toType(cls, "class"));
99
93
  sb.push('');
100
94
  }
101
95
  const tsd = sb.join('\n');
102
96
  return tsd;
103
97
  }
104
98
  }
105
- export class TsdDataModelGenerator extends TsdGenerator {
106
- duplicateTypePropMap = {
107
- note: 'content',
108
- };
109
- convertType(type) {
110
- type.name = toPascalCase(type.name);
111
- type.properties?.forEach(prop => {
112
- prop.name = toCamelCase(prop.name);
113
- if (prop.type.startsWith('Array<')) {
114
- const elType = prop.type.slice('Array<'.length, -1);
115
- prop.type = elType + '[]';
116
- }
117
- if (prop.type === 'User') {
118
- prop.name = 'userId';
119
- prop.type = 'string';
120
- }
121
- if (prop.type === 'User[]') {
122
- if (prop.name.endsWith('s')) {
123
- prop.name = prop.name.slice(0, -1) + 'Ids';
124
- }
125
- prop.type = 'string[]';
126
- }
127
- });
128
- this.rewriteDuplicateTypePropNames(type);
129
- this.rewriteSelfReferencingIds(type);
130
- }
131
- rewriteDuplicateTypePropNames(type) {
132
- const duplicateProp = type.properties?.find(x => toPascalCase(x.name) === type.name);
133
- if (duplicateProp) {
134
- const newName = this.duplicateTypePropMap[duplicateProp.name] ?? 'value';
135
- duplicateProp.name = newName;
136
- }
137
- }
138
- rewriteSelfReferencingIds(type) {
139
- const selfRefId = type.properties?.find(x => x.name.toLowerCase() === `${type.name}id`.toLowerCase());
140
- if (selfRefId) {
141
- selfRefId.name = `parentId`;
142
- }
143
- }
144
- generate(ast) {
145
- ast.classes?.forEach(cls => {
146
- this.convertType(cls);
147
- });
148
- ast.interfaces?.forEach(cls => {
149
- this.convertType(cls);
150
- });
151
- ast.enums?.forEach(e => {
152
- e.name = toPascalCase(e.name);
153
- e.members?.forEach(m => {
154
- m.name = toPascalCase(m.name);
155
- });
156
- });
157
- if (ast.classes) {
158
- ast.classes = ast.classes.filter(x => x.name !== 'User');
159
- }
160
- if (ast.interfaces) {
161
- ast.interfaces = ast.interfaces.filter(x => x.name !== 'User');
162
- }
163
- return super.generate(ast, "class");
164
- }
99
+ export function toTsd(tsAst) {
100
+ const gen = new TsdGenerator();
101
+ return gen.generate(tsAst);
165
102
  }
package/dist/utils.js CHANGED
@@ -121,9 +121,34 @@ export function rightPart(s, needle) {
121
121
  ? s
122
122
  : s.substring(pos + needle.length);
123
123
  }
124
+ export function lastLeftPart(s, needle) {
125
+ if (s == null)
126
+ return null;
127
+ let pos = s.lastIndexOf(needle);
128
+ return pos == -1
129
+ ? s
130
+ : s.substring(0, pos);
131
+ }
132
+ export function lastRightPart(s, needle) {
133
+ if (s == null)
134
+ return null;
135
+ let pos = s.lastIndexOf(needle);
136
+ return pos == -1
137
+ ? s
138
+ : s.substring(pos + needle.length);
139
+ }
124
140
  export function splitCase(t) {
125
141
  return typeof t != 'string' ? t : t.replace(/([A-Z]|[0-9]+)/g, ' $1').replace(/_/g, ' ').trim();
126
142
  }
143
+ export function pick(o, keys) {
144
+ const to = {};
145
+ Object.keys(o).forEach(k => {
146
+ if (keys.indexOf(k) >= 0) {
147
+ to[k] = o[k];
148
+ }
149
+ });
150
+ return to;
151
+ }
127
152
  export function refCount(t) {
128
153
  return t.properties?.filter(x => x.attributes?.some(x => x.name === 'References')).length || 0;
129
154
  }
@@ -140,7 +165,7 @@ export function tsdWithoutPrompt(tsd) {
140
165
  }
141
166
  export function parseTsdHeader(tsd) {
142
167
  const header = tsd.includes('/*prompt:')
143
- ? leftPart(rightPart(tsd, '/*prompt:'), '*/').trim()
168
+ ? leftPart(rightPart(tsd, '/*prompt:') ?? '', '*/').trim()
144
169
  : null;
145
170
  if (!header)
146
171
  return null;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "okai",
3
3
  "type": "module",
4
- "version": "0.0.24",
4
+ "version": "0.0.25",
5
5
  "bin": "./dist/okai.js",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",