okai 0.0.27 → 0.0.29
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/dist/cs-ast.js +2 -2
- package/dist/index.js +107 -49
- package/dist/info.js +4 -0
- package/dist/ui-mjs.js +70 -0
- package/dist/utils.js +6 -0
- package/package.json +1 -1
package/dist/cs-ast.js
CHANGED
@@ -182,12 +182,12 @@ export class CSharpAst {
|
|
182
182
|
// Ignore properties with these attributes on APIs
|
183
183
|
ignoreCreateProps = [
|
184
184
|
'autoIncrement',
|
185
|
-
'
|
185
|
+
'reference',
|
186
186
|
'compute',
|
187
187
|
'computed',
|
188
188
|
].map(x => x.toLowerCase());
|
189
189
|
ignoreUpdateProps = [
|
190
|
-
'
|
190
|
+
'reference',
|
191
191
|
'compute',
|
192
192
|
'computed',
|
193
193
|
].map(x => x.toLowerCase());
|
package/dist/index.js
CHANGED
@@ -8,6 +8,7 @@ import { CSharpApiGenerator } from "./cs-apis.js";
|
|
8
8
|
import { CSharpMigrationGenerator } from "./cs-migrations.js";
|
9
9
|
import { getFileContent } from "./client.js";
|
10
10
|
import { toTsd } from "./tsd-gen.js";
|
11
|
+
import { UiMjsGroupGenerator, UiMjsIndexGenerator } from "./ui-mjs.js";
|
11
12
|
function normalizeSwitches(cmd) { return cmd.replace(/^-+/, '/'); }
|
12
13
|
function parseArgs(...args) {
|
13
14
|
const ret = {
|
@@ -50,6 +51,9 @@ function parseArgs(...args) {
|
|
50
51
|
case "/cached":
|
51
52
|
ret.cached = true;
|
52
53
|
break;
|
54
|
+
case "/system":
|
55
|
+
ret.system = args[++i];
|
56
|
+
break;
|
53
57
|
default:
|
54
58
|
ret.unknown = ret.unknown || [];
|
55
59
|
ret.unknown.push(arg);
|
@@ -94,6 +98,10 @@ function parseArgs(...args) {
|
|
94
98
|
ret.accept = args[++i];
|
95
99
|
}
|
96
100
|
}
|
101
|
+
else if (arg == "chat") {
|
102
|
+
ret.type = "chat";
|
103
|
+
ret.chat = args[++i];
|
104
|
+
}
|
97
105
|
else if (arg.endsWith('.d.ts')) {
|
98
106
|
if (ret.type == "help")
|
99
107
|
ret.type = "update";
|
@@ -147,6 +155,7 @@ export async function cli(cmdArgs) {
|
|
147
155
|
migrationsDir: "/path/to/MyApp/Migrations",
|
148
156
|
serviceModelDir: "/path/to/MyApp.ServiceModel",
|
149
157
|
serviceInterfaceDir: "/path/to/MyApp.ServiceInterfaces",
|
158
|
+
uiMjsDir: "/path/to/MyApp/wwwroot/admin/sections",
|
150
159
|
};
|
151
160
|
fs.writeFileSync('okai.json', JSON.stringify(info, undefined, 2));
|
152
161
|
console.log(`Added: okai.json`);
|
@@ -172,6 +181,8 @@ ${bin} ls models Display list of available premium LLM models
|
|
172
181
|
${bin} init Initialize okai.json with project info to override default paths
|
173
182
|
${bin} init <model> Create an empty <model>.d.ts file for the specified model
|
174
183
|
${bin} info Display current project info
|
184
|
+
${bin} chat <prompt> Submit a new OpenAI chat request with the specified prompt
|
185
|
+
-system <prompt> Specify a system prompt
|
175
186
|
|
176
187
|
Options:
|
177
188
|
-v, -verbose Display verbose logging
|
@@ -239,10 +250,14 @@ Options:
|
|
239
250
|
tsdAst.references.push({ path: './api.d.ts' });
|
240
251
|
}
|
241
252
|
tsd = toTsd(tsdAst);
|
253
|
+
let uiFileName = info.uiMjsDir
|
254
|
+
? path.join(info.uiMjsDir, `${groupName}.mjs`)
|
255
|
+
: null;
|
242
256
|
const tsdContent = createTsdFile(info, {
|
243
257
|
prompt: `New ${model}`,
|
244
258
|
apiFileName: `${groupName}.cs`,
|
245
259
|
tsd,
|
260
|
+
uiFileName,
|
246
261
|
});
|
247
262
|
command.type = "update"; // let update handle the rest
|
248
263
|
command.tsdFile = groupName + '.d.ts';
|
@@ -280,15 +295,10 @@ Options:
|
|
280
295
|
}
|
281
296
|
return tsdPath;
|
282
297
|
}
|
283
|
-
function
|
284
|
-
return
|
285
|
-
? path.join(info.slnDir, trimStart(
|
286
|
-
: path.join(process.cwd(),
|
287
|
-
}
|
288
|
-
function resolveApiFile(apiPath) {
|
289
|
-
return apiPath.startsWith('~/')
|
290
|
-
? path.join(info.slnDir, trimStart(apiPath, '~/'))
|
291
|
-
: path.join(process.cwd(), apiPath);
|
298
|
+
function resolveFile(filePath) {
|
299
|
+
return filePath.startsWith('~/')
|
300
|
+
? path.join(info.slnDir, trimStart(filePath, '~/'))
|
301
|
+
: path.join(process.cwd(), filePath);
|
292
302
|
}
|
293
303
|
if (command.type === "update") {
|
294
304
|
let tsdPath = assertTsdPath(command.tsdFile);
|
@@ -304,7 +314,7 @@ Options:
|
|
304
314
|
const genApis = new CSharpApiGenerator();
|
305
315
|
const csApiFiles = genApis.generate(result.csAst);
|
306
316
|
const apiContent = replaceMyApp(csApiFiles[Object.keys(csApiFiles)[0]], info.projectName);
|
307
|
-
const apiPath =
|
317
|
+
const apiPath = resolveFile(header.api);
|
308
318
|
console.log(`${logPrefix}${apiPath}`);
|
309
319
|
fs.writeFileSync(apiPath, apiContent, { encoding: 'utf-8' });
|
310
320
|
if (header?.migration) {
|
@@ -312,10 +322,23 @@ Options:
|
|
312
322
|
const getMigrations = new CSharpMigrationGenerator();
|
313
323
|
const csMigrationFiles = getMigrations.generate(result.csAst);
|
314
324
|
const migrationContent = replaceMyApp(csMigrationFiles[Object.keys(csMigrationFiles)[0]].replaceAll('Migration1000', migrationCls), info.projectName);
|
315
|
-
const migrationPath =
|
325
|
+
const migrationPath = resolveFile(header.migration);
|
316
326
|
console.log(`${logPrefix}${migrationPath}`);
|
317
327
|
fs.writeFileSync(migrationPath, migrationContent, { encoding: 'utf-8' });
|
318
328
|
}
|
329
|
+
if (header?.uiMjs) {
|
330
|
+
const uiMjsGroupPath = resolveFile(header.uiMjs);
|
331
|
+
const uiMjsGroupGen = new UiMjsGroupGenerator();
|
332
|
+
const uiMjsGroup = uiMjsGroupGen.generate(result.csAst, result.groupName);
|
333
|
+
console.log(`${logPrefix}${uiMjsGroupPath}`);
|
334
|
+
fs.writeFileSync(uiMjsGroupPath, uiMjsGroup, { encoding: 'utf-8' });
|
335
|
+
const uiMjsDir = path.dirname(uiMjsGroupPath);
|
336
|
+
const uiMjsIndexGen = new UiMjsIndexGenerator();
|
337
|
+
const uiMjsIndex = uiMjsIndexGen.generate(fs.readdirSync(uiMjsDir));
|
338
|
+
const uiMjsIndexPath = path.join(uiMjsDir, 'index.mjs');
|
339
|
+
console.log(`${logPrefix}${uiMjsIndexPath}`);
|
340
|
+
fs.writeFileSync(uiMjsIndexPath, uiMjsIndex, { encoding: 'utf-8' });
|
341
|
+
}
|
319
342
|
console.log(`${logPrefix}${tsdPath}`);
|
320
343
|
const newTsdContent = toTsdHeader(header) + (tsdContent.startsWith('///') ? '' : '\n\n') + tsdContent;
|
321
344
|
fs.writeFileSync(tsdPath, newTsdContent, { encoding: 'utf-8' });
|
@@ -353,7 +376,7 @@ Options:
|
|
353
376
|
if (command.verbose)
|
354
377
|
console.log(JSON.stringify(header, undefined, 2));
|
355
378
|
if (header?.migration) {
|
356
|
-
const migrationPath =
|
379
|
+
const migrationPath = resolveFile(header.migration);
|
357
380
|
if (fs.existsSync(migrationPath)) {
|
358
381
|
fs.unlinkSync(migrationPath);
|
359
382
|
console.log(`Removed: ${migrationPath}`);
|
@@ -363,7 +386,7 @@ Options:
|
|
363
386
|
}
|
364
387
|
}
|
365
388
|
if (header?.api) {
|
366
|
-
const apiPath =
|
389
|
+
const apiPath = resolveFile(header.api);
|
367
390
|
if (fs.existsSync(apiPath)) {
|
368
391
|
fs.unlinkSync(apiPath);
|
369
392
|
console.log(`Removed: ${apiPath}`);
|
@@ -372,6 +395,21 @@ Options:
|
|
372
395
|
console.log(`APIs .cs file not found: ${apiPath}`);
|
373
396
|
}
|
374
397
|
}
|
398
|
+
if (header?.uiMjs) {
|
399
|
+
const uiMjsGroupPath = resolveFile(header.uiMjs);
|
400
|
+
if (fs.existsSync(uiMjsGroupPath)) {
|
401
|
+
fs.unlinkSync(uiMjsGroupPath);
|
402
|
+
console.log(`Removed: ${uiMjsGroupPath}`);
|
403
|
+
const uiMjsDir = path.dirname(uiMjsGroupPath);
|
404
|
+
const uiMjsIndexGen = new UiMjsIndexGenerator();
|
405
|
+
const uiMjsIndex = uiMjsIndexGen.generate(fs.readdirSync(uiMjsDir));
|
406
|
+
const uiMjsIndexPath = path.join(uiMjsDir, 'index.mjs');
|
407
|
+
fs.writeFileSync(uiMjsIndexPath, uiMjsIndex, { encoding: 'utf-8' });
|
408
|
+
}
|
409
|
+
else {
|
410
|
+
console.log(`UI .mjs file not found: ${uiMjsGroupPath}`);
|
411
|
+
}
|
412
|
+
}
|
375
413
|
fs.unlinkSync(tsdPath);
|
376
414
|
console.log(`Removed: ${tsdPath}`);
|
377
415
|
const serviceModelDir = path.dirname(tsdPath);
|
@@ -387,6 +425,41 @@ Options:
|
|
387
425
|
await acceptGist(command, command.accept);
|
388
426
|
process.exit(0);
|
389
427
|
}
|
428
|
+
if (command.type === "chat") {
|
429
|
+
try {
|
430
|
+
const url = new URL('/chat', command.baseUrl);
|
431
|
+
const formData = new FormData();
|
432
|
+
formData.append('prompt', command.chat);
|
433
|
+
if (command.system) {
|
434
|
+
formData.append('system', command.system);
|
435
|
+
}
|
436
|
+
if (command.models) {
|
437
|
+
formData.append('model', command.models);
|
438
|
+
if (command.license) {
|
439
|
+
formData.append('license', command.license);
|
440
|
+
}
|
441
|
+
}
|
442
|
+
if (command.verbose)
|
443
|
+
console.log(`POST: ${url}`);
|
444
|
+
const res = await fetch(url, {
|
445
|
+
method: 'POST',
|
446
|
+
body: formData,
|
447
|
+
});
|
448
|
+
if (!res.ok) {
|
449
|
+
console.log(`Failed to chat: ${res.statusText}`);
|
450
|
+
process.exit(1);
|
451
|
+
}
|
452
|
+
const response = await res.json();
|
453
|
+
if (command.verbose)
|
454
|
+
console.log(JSON.stringify(response, undefined, 2));
|
455
|
+
const content = response.choices[response.choices.length - 1]?.message?.content;
|
456
|
+
console.log(content);
|
457
|
+
}
|
458
|
+
catch (err) {
|
459
|
+
console.error(err);
|
460
|
+
}
|
461
|
+
process.exit(0);
|
462
|
+
}
|
390
463
|
if (command.type === "prompt") {
|
391
464
|
try {
|
392
465
|
if (!info.serviceModelDir)
|
@@ -669,10 +742,22 @@ function chooseFile(ctx, info, gist, comamnd) {
|
|
669
742
|
const apiTypesPath = path.join(info.slnDir, relativeServiceModelDir, `api.d.ts`);
|
670
743
|
const apiFile = path.join(import.meta.dirname, 'api.d.ts');
|
671
744
|
fs.writeFileSync(apiTypesPath, fs.readFileSync(apiFile, 'utf-8'));
|
745
|
+
let uiFileName = null;
|
746
|
+
if (info.uiMjsDir) {
|
747
|
+
uiFileName = `${res.groupName}.mjs`;
|
748
|
+
const uiGroupPath = path.join(info.uiMjsDir, uiFileName);
|
749
|
+
const uiVueGen = new UiMjsGroupGenerator();
|
750
|
+
const uiGroupSrc = uiVueGen.generate(res.csAst, res.groupName);
|
751
|
+
fs.writeFileSync(uiGroupPath, uiGroupSrc);
|
752
|
+
const uiIndexGen = new UiMjsIndexGenerator();
|
753
|
+
const uiIndexSrc = uiIndexGen.generate(fs.readdirSync(info.uiMjsDir));
|
754
|
+
fs.writeFileSync(path.join(info.uiMjsDir, `index.mjs`), uiIndexSrc);
|
755
|
+
}
|
672
756
|
const tsdContent = createTsdFile(info, {
|
673
757
|
prompt: titleBar.content.replaceAll('/*', '').replaceAll('*/', ''),
|
674
758
|
apiFileName,
|
675
759
|
tsd: res.tsd,
|
760
|
+
uiFileName,
|
676
761
|
});
|
677
762
|
const tsdFileName = `${res.groupName}.d.ts`;
|
678
763
|
const fullTsdPath = path.join(info.slnDir, relativeServiceModelDir, tsdFileName);
|
@@ -680,7 +765,7 @@ function chooseFile(ctx, info, gist, comamnd) {
|
|
680
765
|
const fullMigrationPath = path.join(info.slnDir, relativeMigrationDir, migrationFileName);
|
681
766
|
if (!fs.existsSync(path.dirname(fullTsdPath))) {
|
682
767
|
console.log(`Directory does not exist: ${path.dirname(fullTsdPath)}`);
|
683
|
-
process.exit(
|
768
|
+
process.exit(1);
|
684
769
|
}
|
685
770
|
console.log(`\nSelected '${result.selectedFile}' data models`);
|
686
771
|
fs.writeFileSync(fullTsdPath, tsdContent, { encoding: 'utf-8' });
|
@@ -692,6 +777,7 @@ function chooseFile(ctx, info, gist, comamnd) {
|
|
692
777
|
if (fs.existsSync(path.dirname(fullMigrationPath))) {
|
693
778
|
fs.writeFileSync(fullMigrationPath, migrationContent, { encoding: 'utf-8' });
|
694
779
|
console.log(`Saved: ${fullMigrationPath}`);
|
780
|
+
console.log(`\nRun 'dotnet run --AppTasks=migrate' to apply the new migration and create the new tables`);
|
695
781
|
}
|
696
782
|
const script = path.basename(process.argv[1]);
|
697
783
|
console.log(`\nTo regenerate classes, update '${tsdFileName}' then run:`);
|
@@ -706,7 +792,7 @@ function chooseFile(ctx, info, gist, comamnd) {
|
|
706
792
|
.catch((err) => {
|
707
793
|
if (comamnd.verbose)
|
708
794
|
console.log(`ERROR: ${err.message ?? err}`);
|
709
|
-
process.exit(
|
795
|
+
process.exit(1);
|
710
796
|
});
|
711
797
|
}
|
712
798
|
else {
|
@@ -773,6 +859,9 @@ function createTsdFile(info, opt) {
|
|
773
859
|
const relativeMigrationDir = info.migrationsDir && fs.existsSync(info.migrationsDir)
|
774
860
|
? trimStart(info.migrationsDir.substring(info.slnDir.length), '~/')
|
775
861
|
: null;
|
862
|
+
const relativeUiVueDir = opt.uiFileName && info.uiMjsDir && fs.existsSync(info.uiMjsDir)
|
863
|
+
? trimStart(info.uiMjsDir.substring(info.slnDir.length), '~/')
|
864
|
+
: null;
|
776
865
|
const sb = [
|
777
866
|
`/*prompt: ${opt.prompt}`,
|
778
867
|
`api: ~/${path.join(relativeServiceModelDir, opt.apiFileName)}`,
|
@@ -780,41 +869,10 @@ function createTsdFile(info, opt) {
|
|
780
869
|
if (relativeMigrationDir) {
|
781
870
|
sb.push(`migration: ~/${path.join(relativeMigrationDir, migrationFileName)}`);
|
782
871
|
}
|
872
|
+
if (relativeUiVueDir) {
|
873
|
+
sb.push(`ui.mjs: ~/${path.join(relativeUiVueDir, opt.uiFileName)}`);
|
874
|
+
}
|
783
875
|
sb.push('*/');
|
784
876
|
sb.push('');
|
785
877
|
return sb.join('\n') + (opt.tsd.startsWith('///') ? '' : '\n\n') + opt.tsd;
|
786
878
|
}
|
787
|
-
function applyCSharpGist(ctx, info, gist, { accept = false, acceptAll = false, discard = false }) {
|
788
|
-
const { screen, titleBar, fileList, preview, statusBar, result } = ctx;
|
789
|
-
function removeSelected() {
|
790
|
-
delete gist.files[result.selectedFile];
|
791
|
-
fileList.removeItem(result.selectedFile);
|
792
|
-
const nextFile = Object.keys(gist.files)[0];
|
793
|
-
if (nextFile) {
|
794
|
-
result.selectedFile = nextFile;
|
795
|
-
const nextFileIndex = fileList.getItemIndex(nextFile);
|
796
|
-
fileList.select(nextFileIndex);
|
797
|
-
preview.setContent(gist.files[nextFile].content);
|
798
|
-
}
|
799
|
-
screen.render();
|
800
|
-
if (Object.keys(gist.files).length === 0) {
|
801
|
-
//screen.destroy()
|
802
|
-
exit(screen, info, gist);
|
803
|
-
}
|
804
|
-
}
|
805
|
-
if (discard) {
|
806
|
-
const file = gist.files[result.selectedFile];
|
807
|
-
removeSelected();
|
808
|
-
}
|
809
|
-
else if (accept) {
|
810
|
-
const file = gist.files[result.selectedFile];
|
811
|
-
writeFile(info, result.selectedFile, file.content);
|
812
|
-
removeSelected();
|
813
|
-
}
|
814
|
-
else if (acceptAll) {
|
815
|
-
for (const [filename, file] of Object.entries(gist.files)) {
|
816
|
-
writeFile(info, filename, file.content);
|
817
|
-
}
|
818
|
-
exit(screen, info, gist);
|
819
|
-
}
|
820
|
-
}
|
package/dist/info.js
CHANGED
@@ -53,6 +53,10 @@ export function projectInfo(cwd) {
|
|
53
53
|
serviceModelDir,
|
54
54
|
serviceInterfaceDir,
|
55
55
|
};
|
56
|
+
const uiVueDir = path.join(hostDir, "wwwroot", "admin", "sections");
|
57
|
+
if (fs.existsSync(uiVueDir)) {
|
58
|
+
info.uiMjsDir = uiVueDir;
|
59
|
+
}
|
56
60
|
for (const file of walk(serviceInterfaceDir, [], {
|
57
61
|
include: (path) => path.endsWith(".cs"),
|
58
62
|
excludeDirs: ["obj", "bin"]
|
package/dist/ui-mjs.js
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
import { getGroupName, plural, toCamelCase } from "./utils.js";
|
2
|
+
/*
|
3
|
+
export default {
|
4
|
+
group: "Bookings",
|
5
|
+
items: {
|
6
|
+
Bookings: {
|
7
|
+
type: 'Booking',
|
8
|
+
component: {
|
9
|
+
template:`<AutoQueryGrid :type="type"
|
10
|
+
selected-columns="id,name,roomType,roomNumber,bookingStartDate,bookingEndDate,cost,couponId,discount" />`,
|
11
|
+
},
|
12
|
+
},
|
13
|
+
Coupons: {
|
14
|
+
type: 'Coupon',
|
15
|
+
component: {
|
16
|
+
template:`<AutoQueryGrid :type="type"
|
17
|
+
selected-columns="id,name,description,discount,expiryDate" />`,
|
18
|
+
},
|
19
|
+
},
|
20
|
+
},
|
21
|
+
}
|
22
|
+
*/
|
23
|
+
export class UiMjsGroupGenerator {
|
24
|
+
generate(ast, groupLabel) {
|
25
|
+
if (!groupLabel) {
|
26
|
+
const groupName = getGroupName(ast);
|
27
|
+
groupLabel = plural(groupName);
|
28
|
+
}
|
29
|
+
const sb = [
|
30
|
+
`export default {`,
|
31
|
+
` group: "${groupLabel}",`,
|
32
|
+
` items: {`,
|
33
|
+
...ast.types.filter(x => !x.isEnum && !x.isInterface).map(x => {
|
34
|
+
return [
|
35
|
+
` ${plural(x.name)}: {`,
|
36
|
+
` type: '${x.name}',`,
|
37
|
+
` component: {`,
|
38
|
+
` template:\`<AutoQueryGrid :type="type"`,
|
39
|
+
` selected-columns="${x.properties.map(x => toCamelCase(x.name)).join(',')}" />\`,`,
|
40
|
+
` },`,
|
41
|
+
` },`,
|
42
|
+
].join('\n');
|
43
|
+
}),
|
44
|
+
` }`,
|
45
|
+
`}`,
|
46
|
+
];
|
47
|
+
const src = sb.join('\n');
|
48
|
+
return src;
|
49
|
+
}
|
50
|
+
}
|
51
|
+
/*
|
52
|
+
import Bookings from './Bookings.mjs'
|
53
|
+
export {
|
54
|
+
Bookings,
|
55
|
+
}
|
56
|
+
*/
|
57
|
+
export class UiMjsIndexGenerator {
|
58
|
+
generate(files) {
|
59
|
+
const imports = [];
|
60
|
+
const exports = ['export {'];
|
61
|
+
files.filter(x => x != 'index.mjs').forEach(x => {
|
62
|
+
const name = x.replace('.mjs', '');
|
63
|
+
imports.push(`import ${name} from './${name}.mjs'`);
|
64
|
+
exports.push(` ${name},`);
|
65
|
+
});
|
66
|
+
exports.push('}');
|
67
|
+
const src = imports.join('\n') + '\n' + exports.join('\n');
|
68
|
+
return src;
|
69
|
+
}
|
70
|
+
}
|
package/dist/utils.js
CHANGED
@@ -178,6 +178,9 @@ export function parseTsdHeader(tsd) {
|
|
178
178
|
else if (line.startsWith('migration:')) {
|
179
179
|
to.migration = line.replace('migration:', '').trim();
|
180
180
|
}
|
181
|
+
else if (line.startsWith('ui.mjs:')) {
|
182
|
+
to.uiMjs = line.replace('ui.mjs:', '').trim();
|
183
|
+
}
|
181
184
|
else if (!to.api && !to.migration && line.trim()) {
|
182
185
|
to.prompt += line.trim() + '\n';
|
183
186
|
}
|
@@ -198,6 +201,9 @@ export function toTsdHeader(header) {
|
|
198
201
|
if (header.migration) {
|
199
202
|
sb.push(`migration: ${header.migration}`);
|
200
203
|
}
|
204
|
+
if (header.uiMjs) {
|
205
|
+
sb.push(`ui.mjs: ${header.uiMjs}`);
|
206
|
+
}
|
201
207
|
sb.push('*/');
|
202
208
|
sb.push('');
|
203
209
|
return sb.join('\n');
|