@openspecui/server 1.1.0 → 1.1.2
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/index.mjs +91 -264
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { serve } from "@hono/node-server";
|
|
2
|
-
import {
|
|
2
|
+
import { CliExecutor, ConfigManager, OpenSpecAdapter, OpenSpecWatcher, OpsxKernel, PtyClientMessageSchema, ReactiveContext, getAllTools, getAvailableTools, getConfiguredTools, getDefaultCliCommandString, initWatcherPool, isWatcherPoolInitialized, sniffGlobalCli } from "@openspecui/core";
|
|
3
3
|
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
|
|
4
4
|
import { applyWSSHandler } from "@trpc/server/adapters/ws";
|
|
5
5
|
import { Hono } from "hono";
|
|
@@ -12,9 +12,8 @@ import { SearchQuerySchema } from "@openspecui/search";
|
|
|
12
12
|
import { initTRPC } from "@trpc/server";
|
|
13
13
|
import { observable } from "@trpc/server/observable";
|
|
14
14
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
15
|
-
import { dirname, join,
|
|
15
|
+
import { dirname, join, resolve, sep } from "node:path";
|
|
16
16
|
import { z } from "zod";
|
|
17
|
-
import { parse } from "yaml";
|
|
18
17
|
import { EventEmitter as EventEmitter$1 } from "node:events";
|
|
19
18
|
import { NodeWorkerSearchProvider } from "@openspecui/search/node";
|
|
20
19
|
|
|
@@ -465,53 +464,6 @@ function createCliStreamObservable(startStream) {
|
|
|
465
464
|
});
|
|
466
465
|
}
|
|
467
466
|
|
|
468
|
-
//#endregion
|
|
469
|
-
//#region src/opsx-schema.ts
|
|
470
|
-
const SchemaYamlArtifactSchema = z.object({
|
|
471
|
-
id: z.string(),
|
|
472
|
-
generates: z.string(),
|
|
473
|
-
description: z.string().optional(),
|
|
474
|
-
template: z.string().optional(),
|
|
475
|
-
instruction: z.string().optional(),
|
|
476
|
-
requires: z.array(z.string()).optional()
|
|
477
|
-
});
|
|
478
|
-
const SchemaYamlSchema = z.object({
|
|
479
|
-
name: z.string(),
|
|
480
|
-
version: z.union([z.string(), z.number()]).optional(),
|
|
481
|
-
description: z.string().optional(),
|
|
482
|
-
artifacts: z.array(SchemaYamlArtifactSchema),
|
|
483
|
-
apply: z.object({
|
|
484
|
-
requires: z.array(z.string()).optional(),
|
|
485
|
-
tracks: z.string().optional(),
|
|
486
|
-
instruction: z.string().optional()
|
|
487
|
-
}).optional()
|
|
488
|
-
});
|
|
489
|
-
function parseSchemaYaml(content) {
|
|
490
|
-
const raw = parse(content);
|
|
491
|
-
const parsed = SchemaYamlSchema.safeParse(raw);
|
|
492
|
-
if (!parsed.success) throw new Error(`Invalid schema.yaml: ${parsed.error.message}`);
|
|
493
|
-
const { artifacts, apply, name, description, version } = parsed.data;
|
|
494
|
-
const detail = {
|
|
495
|
-
name,
|
|
496
|
-
description,
|
|
497
|
-
version,
|
|
498
|
-
artifacts: artifacts.map((artifact) => ({
|
|
499
|
-
id: artifact.id,
|
|
500
|
-
outputPath: artifact.generates,
|
|
501
|
-
description: artifact.description,
|
|
502
|
-
template: artifact.template,
|
|
503
|
-
instruction: artifact.instruction,
|
|
504
|
-
requires: artifact.requires ?? []
|
|
505
|
-
})),
|
|
506
|
-
applyRequires: apply?.requires ?? [],
|
|
507
|
-
applyTracks: apply?.tracks,
|
|
508
|
-
applyInstruction: apply?.instruction
|
|
509
|
-
};
|
|
510
|
-
const validated = SchemaDetailSchema.safeParse(detail);
|
|
511
|
-
if (!validated.success) throw new Error(`Invalid schema detail: ${validated.error.message}`);
|
|
512
|
-
return validated.data;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
467
|
//#endregion
|
|
516
468
|
//#region src/reactive-kv.ts
|
|
517
469
|
/**
|
|
@@ -639,20 +591,6 @@ function requireChangeId(changeId) {
|
|
|
639
591
|
function ensureEditableSource(source, label) {
|
|
640
592
|
if (source === "package") throw new Error(`${label} is read-only (package source)`);
|
|
641
593
|
}
|
|
642
|
-
function parseCliJson(raw, schema, label) {
|
|
643
|
-
const trimmed = raw.trim();
|
|
644
|
-
if (!trimmed) throw new Error(`${label} returned empty output`);
|
|
645
|
-
let parsed;
|
|
646
|
-
try {
|
|
647
|
-
parsed = JSON.parse(trimmed);
|
|
648
|
-
} catch (err) {
|
|
649
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
650
|
-
throw new Error(`${label} returned invalid JSON: ${message}`);
|
|
651
|
-
}
|
|
652
|
-
const result = schema.safeParse(parsed);
|
|
653
|
-
if (!result.success) throw new Error(`${label} returned unexpected JSON: ${result.error.message}`);
|
|
654
|
-
return result.data;
|
|
655
|
-
}
|
|
656
594
|
function resolveEntryPath(root, entryPath) {
|
|
657
595
|
const normalizedRoot = resolve(root);
|
|
658
596
|
const resolvedPath = resolve(normalizedRoot, entryPath);
|
|
@@ -660,153 +598,62 @@ function resolveEntryPath(root, entryPath) {
|
|
|
660
598
|
if (resolvedPath !== normalizedRoot && !resolvedPath.startsWith(rootPrefix)) throw new Error("Invalid path: outside schema root");
|
|
661
599
|
return resolvedPath;
|
|
662
600
|
}
|
|
663
|
-
function toRelativePath(root, absolutePath) {
|
|
664
|
-
return relative(root, absolutePath).split(sep).join("/");
|
|
665
|
-
}
|
|
666
|
-
async function readEntriesUnderRoot(root) {
|
|
667
|
-
if (!(await reactiveStat(root))?.isDirectory) return [];
|
|
668
|
-
const collectEntries = async (dir) => {
|
|
669
|
-
const names = await reactiveReadDir(dir, { includeHidden: false });
|
|
670
|
-
const entries = [];
|
|
671
|
-
for (const name of names) {
|
|
672
|
-
const fullPath = join(dir, name);
|
|
673
|
-
const statInfo = await reactiveStat(fullPath);
|
|
674
|
-
if (!statInfo) continue;
|
|
675
|
-
const relativePath = toRelativePath(root, fullPath);
|
|
676
|
-
if (statInfo.isDirectory) {
|
|
677
|
-
entries.push({
|
|
678
|
-
path: relativePath,
|
|
679
|
-
type: "directory"
|
|
680
|
-
});
|
|
681
|
-
entries.push(...await collectEntries(fullPath));
|
|
682
|
-
} else {
|
|
683
|
-
const content = await reactiveReadFile(fullPath);
|
|
684
|
-
const size = content ? Buffer.byteLength(content, "utf-8") : void 0;
|
|
685
|
-
entries.push({
|
|
686
|
-
path: relativePath,
|
|
687
|
-
type: "file",
|
|
688
|
-
content: content ?? void 0,
|
|
689
|
-
size
|
|
690
|
-
});
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
return entries;
|
|
694
|
-
};
|
|
695
|
-
return collectEntries(root);
|
|
696
|
-
}
|
|
697
|
-
async function touchOpsxProjectDeps(projectDir) {
|
|
698
|
-
const openspecDir = join(projectDir, "openspec");
|
|
699
|
-
await reactiveReadFile(join(openspecDir, "config.yaml"));
|
|
700
|
-
const schemaRoot = join(openspecDir, "schemas");
|
|
701
|
-
const schemaDirs = await reactiveReadDir(schemaRoot, {
|
|
702
|
-
directoriesOnly: true,
|
|
703
|
-
includeHidden: true
|
|
704
|
-
});
|
|
705
|
-
await Promise.all(schemaDirs.map((name) => reactiveReadFile(join(schemaRoot, name, "schema.yaml"))));
|
|
706
|
-
await reactiveReadDir(join(openspecDir, "changes"), {
|
|
707
|
-
directoriesOnly: true,
|
|
708
|
-
includeHidden: true,
|
|
709
|
-
exclude: ["archive"]
|
|
710
|
-
});
|
|
711
|
-
}
|
|
712
|
-
async function touchOpsxChangeDeps(projectDir, changeId) {
|
|
713
|
-
const changeDir = join(projectDir, "openspec", "changes", changeId);
|
|
714
|
-
await reactiveReadDir(changeDir, { includeHidden: true });
|
|
715
|
-
await reactiveReadFile(join(changeDir, ".openspec.yaml"));
|
|
716
|
-
}
|
|
717
|
-
async function readGlobArtifactFiles(projectDir, changeId, outputPath) {
|
|
718
|
-
return (await readEntriesUnderRoot(join(projectDir, "openspec", "changes", changeId))).filter((entry) => entry.type === "file" && matchesGlob(entry.path, outputPath)).map((entry) => ({
|
|
719
|
-
path: entry.path,
|
|
720
|
-
type: "file",
|
|
721
|
-
content: entry.content ?? ""
|
|
722
|
-
}));
|
|
723
|
-
}
|
|
724
601
|
async function fetchOpsxStatus(ctx, input) {
|
|
725
602
|
const changeId = requireChangeId(input.change);
|
|
726
|
-
await
|
|
727
|
-
await
|
|
728
|
-
|
|
729
|
-
"status",
|
|
730
|
-
"--json",
|
|
731
|
-
"--change",
|
|
732
|
-
changeId
|
|
733
|
-
];
|
|
734
|
-
if (input.schema) args.push("--schema", input.schema);
|
|
735
|
-
const result = await ctx.cliExecutor.execute(args);
|
|
736
|
-
if (!result.success) throw new Error(result.stderr || `openspec status failed (exit ${result.exitCode ?? "null"})`);
|
|
737
|
-
const status = parseCliJson(result.stdout, ChangeStatusSchema, "openspec status");
|
|
738
|
-
const changeRelDir = `openspec/changes/${changeId}`;
|
|
739
|
-
for (const artifact of status.artifacts) artifact.relativePath = `${changeRelDir}/${artifact.outputPath}`;
|
|
740
|
-
return status;
|
|
603
|
+
await ctx.kernel.waitForWarmup();
|
|
604
|
+
await ctx.kernel.ensureStatus(changeId, input.schema);
|
|
605
|
+
return ctx.kernel.getStatus(changeId, input.schema);
|
|
741
606
|
}
|
|
742
607
|
async function fetchOpsxStatusList(ctx) {
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
exclude: ["archive"]
|
|
747
|
-
});
|
|
748
|
-
return await Promise.all(changeIds.map((changeId) => fetchOpsxStatus(ctx, { change: changeId })));
|
|
608
|
+
await ctx.kernel.waitForWarmup();
|
|
609
|
+
await ctx.kernel.ensureStatusList();
|
|
610
|
+
return ctx.kernel.getStatusList();
|
|
749
611
|
}
|
|
750
612
|
async function fetchOpsxInstructions(ctx, input) {
|
|
751
613
|
const changeId = requireChangeId(input.change);
|
|
752
|
-
await
|
|
753
|
-
await
|
|
754
|
-
|
|
755
|
-
"instructions",
|
|
756
|
-
input.artifact,
|
|
757
|
-
"--json",
|
|
758
|
-
"--change",
|
|
759
|
-
changeId
|
|
760
|
-
];
|
|
761
|
-
if (input.schema) args.push("--schema", input.schema);
|
|
762
|
-
const result = await ctx.cliExecutor.execute(args);
|
|
763
|
-
if (!result.success) throw new Error(result.stderr || `openspec instructions failed (exit ${result.exitCode ?? "null"})`);
|
|
764
|
-
return parseCliJson(result.stdout, ArtifactInstructionsSchema, "openspec instructions");
|
|
614
|
+
await ctx.kernel.waitForWarmup();
|
|
615
|
+
await ctx.kernel.ensureInstructions(changeId, input.artifact, input.schema);
|
|
616
|
+
return ctx.kernel.getInstructions(changeId, input.artifact, input.schema);
|
|
765
617
|
}
|
|
766
618
|
async function fetchOpsxApplyInstructions(ctx, input) {
|
|
767
619
|
const changeId = requireChangeId(input.change);
|
|
768
|
-
await
|
|
769
|
-
await
|
|
770
|
-
|
|
771
|
-
"instructions",
|
|
772
|
-
"apply",
|
|
773
|
-
"--json",
|
|
774
|
-
"--change",
|
|
775
|
-
changeId
|
|
776
|
-
];
|
|
777
|
-
if (input.schema) args.push("--schema", input.schema);
|
|
778
|
-
const result = await ctx.cliExecutor.execute(args);
|
|
779
|
-
if (!result.success) throw new Error(result.stderr || `openspec instructions apply failed (exit ${result.exitCode ?? "null"})`);
|
|
780
|
-
return parseCliJson(result.stdout, ApplyInstructionsSchema, "openspec instructions apply");
|
|
620
|
+
await ctx.kernel.waitForWarmup();
|
|
621
|
+
await ctx.kernel.ensureApplyInstructions(changeId, input.schema);
|
|
622
|
+
return ctx.kernel.getApplyInstructions(changeId, input.schema);
|
|
781
623
|
}
|
|
782
|
-
async function
|
|
783
|
-
await
|
|
784
|
-
const
|
|
785
|
-
|
|
786
|
-
|
|
624
|
+
async function fetchOpsxConfigBundle(ctx) {
|
|
625
|
+
await ctx.kernel.ensureSchemas();
|
|
626
|
+
const schemas = ctx.kernel.getSchemas();
|
|
627
|
+
for (const schema of schemas) {
|
|
628
|
+
ctx.kernel.ensureSchemaDetail(schema.name).catch(() => {});
|
|
629
|
+
ctx.kernel.ensureSchemaResolution(schema.name).catch(() => {});
|
|
630
|
+
}
|
|
631
|
+
const schemaDetails = {};
|
|
632
|
+
const schemaResolutions = {};
|
|
633
|
+
for (const schema of schemas) {
|
|
634
|
+
schemaDetails[schema.name] = ctx.kernel.peekSchemaDetail(schema.name);
|
|
635
|
+
schemaResolutions[schema.name] = ctx.kernel.peekSchemaResolution(schema.name);
|
|
636
|
+
}
|
|
637
|
+
return {
|
|
638
|
+
schemas,
|
|
639
|
+
schemaDetails,
|
|
640
|
+
schemaResolutions
|
|
641
|
+
};
|
|
787
642
|
}
|
|
788
643
|
async function fetchOpsxSchemaResolution(ctx, name) {
|
|
789
|
-
await
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
return parseCliJson(result.stdout, SchemaResolutionSchema, "openspec schema which");
|
|
644
|
+
await ctx.kernel.waitForWarmup();
|
|
645
|
+
await ctx.kernel.ensureSchemaResolution(name);
|
|
646
|
+
return ctx.kernel.getSchemaResolution(name);
|
|
793
647
|
}
|
|
794
648
|
async function fetchOpsxTemplates(ctx, schema) {
|
|
795
|
-
await
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
return parseCliJson(result.stdout, TemplatesSchema, "openspec templates");
|
|
649
|
+
await ctx.kernel.waitForWarmup();
|
|
650
|
+
await ctx.kernel.ensureTemplates(schema);
|
|
651
|
+
return ctx.kernel.getTemplates(schema);
|
|
799
652
|
}
|
|
800
653
|
async function fetchOpsxTemplateContents(ctx, schema) {
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
content: await reactiveReadFile(info.path),
|
|
805
|
-
path: info.path,
|
|
806
|
-
source: info.source
|
|
807
|
-
}];
|
|
808
|
-
}));
|
|
809
|
-
return Object.fromEntries(entries);
|
|
654
|
+
await ctx.kernel.waitForWarmup();
|
|
655
|
+
await ctx.kernel.ensureTemplateContents(schema);
|
|
656
|
+
return ctx.kernel.getTemplateContents(schema);
|
|
810
657
|
}
|
|
811
658
|
/**
|
|
812
659
|
* Spec router - spec CRUD operations
|
|
@@ -1196,11 +1043,11 @@ const opsxRouter = router({
|
|
|
1196
1043
|
})).subscription(({ ctx, input }) => {
|
|
1197
1044
|
return createReactiveSubscription(() => fetchOpsxApplyInstructions(ctx, input));
|
|
1198
1045
|
}),
|
|
1199
|
-
|
|
1200
|
-
return
|
|
1046
|
+
configBundle: publicProcedure.query(async ({ ctx }) => {
|
|
1047
|
+
return fetchOpsxConfigBundle(ctx);
|
|
1201
1048
|
}),
|
|
1202
|
-
|
|
1203
|
-
return createReactiveSubscription(() =>
|
|
1049
|
+
subscribeConfigBundle: publicProcedure.subscription(({ ctx }) => {
|
|
1050
|
+
return createReactiveSubscription(() => fetchOpsxConfigBundle(ctx));
|
|
1204
1051
|
}),
|
|
1205
1052
|
templates: publicProcedure.input(z.object({ schema: z.string().optional() }).optional()).query(async ({ ctx, input }) => {
|
|
1206
1053
|
return fetchOpsxTemplates(ctx, input?.schema);
|
|
@@ -1214,53 +1061,34 @@ const opsxRouter = router({
|
|
|
1214
1061
|
subscribeTemplateContents: publicProcedure.input(z.object({ schema: z.string().optional() }).optional()).subscription(({ ctx, input }) => {
|
|
1215
1062
|
return createReactiveSubscription(() => fetchOpsxTemplateContents(ctx, input?.schema));
|
|
1216
1063
|
}),
|
|
1217
|
-
schemaResolution: publicProcedure.input(z.object({ name: z.string() })).query(async ({ ctx, input }) => {
|
|
1218
|
-
return fetchOpsxSchemaResolution(ctx, input.name);
|
|
1219
|
-
}),
|
|
1220
|
-
subscribeSchemaResolution: publicProcedure.input(z.object({ name: z.string() })).subscription(({ ctx, input }) => {
|
|
1221
|
-
return createReactiveSubscription(() => fetchOpsxSchemaResolution(ctx, input.name));
|
|
1222
|
-
}),
|
|
1223
|
-
schemaDetail: publicProcedure.input(z.object({ name: z.string() })).query(async ({ ctx, input }) => {
|
|
1224
|
-
await touchOpsxProjectDeps(ctx.projectDir);
|
|
1225
|
-
const schemaPath = join((await fetchOpsxSchemaResolution(ctx, input.name)).path, "schema.yaml");
|
|
1226
|
-
const content = await reactiveReadFile(schemaPath);
|
|
1227
|
-
if (!content) throw new Error(`schema.yaml not found at ${schemaPath}`);
|
|
1228
|
-
return parseSchemaYaml(content);
|
|
1229
|
-
}),
|
|
1230
|
-
subscribeSchemaDetail: publicProcedure.input(z.object({ name: z.string() })).subscription(({ ctx, input }) => {
|
|
1231
|
-
return createReactiveSubscription(async () => {
|
|
1232
|
-
await touchOpsxProjectDeps(ctx.projectDir);
|
|
1233
|
-
const schemaPath = join((await fetchOpsxSchemaResolution(ctx, input.name)).path, "schema.yaml");
|
|
1234
|
-
const content = await reactiveReadFile(schemaPath);
|
|
1235
|
-
if (!content) throw new Error(`schema.yaml not found at ${schemaPath}`);
|
|
1236
|
-
return parseSchemaYaml(content);
|
|
1237
|
-
});
|
|
1238
|
-
}),
|
|
1239
1064
|
schemaFiles: publicProcedure.input(z.object({ name: z.string() })).query(async ({ ctx, input }) => {
|
|
1240
|
-
await
|
|
1241
|
-
|
|
1065
|
+
await ctx.kernel.waitForWarmup();
|
|
1066
|
+
await ctx.kernel.ensureSchemaFiles(input.name);
|
|
1067
|
+
return ctx.kernel.getSchemaFiles(input.name);
|
|
1242
1068
|
}),
|
|
1243
1069
|
subscribeSchemaFiles: publicProcedure.input(z.object({ name: z.string() })).subscription(({ ctx, input }) => {
|
|
1244
1070
|
return createReactiveSubscription(async () => {
|
|
1245
|
-
await
|
|
1246
|
-
|
|
1071
|
+
await ctx.kernel.waitForWarmup();
|
|
1072
|
+
await ctx.kernel.ensureSchemaFiles(input.name);
|
|
1073
|
+
return ctx.kernel.getSchemaFiles(input.name);
|
|
1247
1074
|
});
|
|
1248
1075
|
}),
|
|
1249
1076
|
schemaYaml: publicProcedure.input(z.object({ name: z.string() })).query(async ({ ctx, input }) => {
|
|
1250
|
-
await
|
|
1251
|
-
|
|
1077
|
+
await ctx.kernel.waitForWarmup();
|
|
1078
|
+
await ctx.kernel.ensureSchemaYaml(input.name);
|
|
1079
|
+
return ctx.kernel.getSchemaYaml(input.name);
|
|
1252
1080
|
}),
|
|
1253
1081
|
subscribeSchemaYaml: publicProcedure.input(z.object({ name: z.string() })).subscription(({ ctx, input }) => {
|
|
1254
1082
|
return createReactiveSubscription(async () => {
|
|
1255
|
-
await
|
|
1256
|
-
|
|
1083
|
+
await ctx.kernel.waitForWarmup();
|
|
1084
|
+
await ctx.kernel.ensureSchemaYaml(input.name);
|
|
1085
|
+
return ctx.kernel.getSchemaYaml(input.name);
|
|
1257
1086
|
});
|
|
1258
1087
|
}),
|
|
1259
1088
|
writeSchemaYaml: publicProcedure.input(z.object({
|
|
1260
1089
|
name: z.string(),
|
|
1261
1090
|
content: z.string()
|
|
1262
1091
|
})).mutation(async ({ ctx, input }) => {
|
|
1263
|
-
await touchOpsxProjectDeps(ctx.projectDir);
|
|
1264
1092
|
const resolution = await fetchOpsxSchemaResolution(ctx, input.name);
|
|
1265
1093
|
ensureEditableSource(resolution.source, "schema.yaml");
|
|
1266
1094
|
const schemaPath = join(resolution.path, "schema.yaml");
|
|
@@ -1273,7 +1101,6 @@ const opsxRouter = router({
|
|
|
1273
1101
|
path: z.string(),
|
|
1274
1102
|
content: z.string()
|
|
1275
1103
|
})).mutation(async ({ ctx, input }) => {
|
|
1276
|
-
await touchOpsxProjectDeps(ctx.projectDir);
|
|
1277
1104
|
const resolution = await fetchOpsxSchemaResolution(ctx, input.schema);
|
|
1278
1105
|
ensureEditableSource(resolution.source, "schema file");
|
|
1279
1106
|
if (!input.path.trim()) throw new Error("path is required");
|
|
@@ -1287,7 +1114,6 @@ const opsxRouter = router({
|
|
|
1287
1114
|
path: z.string(),
|
|
1288
1115
|
content: z.string().optional()
|
|
1289
1116
|
})).mutation(async ({ ctx, input }) => {
|
|
1290
|
-
await touchOpsxProjectDeps(ctx.projectDir);
|
|
1291
1117
|
const resolution = await fetchOpsxSchemaResolution(ctx, input.schema);
|
|
1292
1118
|
ensureEditableSource(resolution.source, "schema file");
|
|
1293
1119
|
if (!input.path.trim()) throw new Error("path is required");
|
|
@@ -1300,7 +1126,6 @@ const opsxRouter = router({
|
|
|
1300
1126
|
schema: z.string(),
|
|
1301
1127
|
path: z.string()
|
|
1302
1128
|
})).mutation(async ({ ctx, input }) => {
|
|
1303
|
-
await touchOpsxProjectDeps(ctx.projectDir);
|
|
1304
1129
|
const resolution = await fetchOpsxSchemaResolution(ctx, input.schema);
|
|
1305
1130
|
ensureEditableSource(resolution.source, "schema directory");
|
|
1306
1131
|
if (!input.path.trim()) throw new Error("path is required");
|
|
@@ -1311,7 +1136,6 @@ const opsxRouter = router({
|
|
|
1311
1136
|
schema: z.string(),
|
|
1312
1137
|
path: z.string()
|
|
1313
1138
|
})).mutation(async ({ ctx, input }) => {
|
|
1314
|
-
await touchOpsxProjectDeps(ctx.projectDir);
|
|
1315
1139
|
const resolution = await fetchOpsxSchemaResolution(ctx, input.schema);
|
|
1316
1140
|
ensureEditableSource(resolution.source, "schema entry");
|
|
1317
1141
|
if (!input.path.trim()) throw new Error("path is required");
|
|
@@ -1327,26 +1151,18 @@ const opsxRouter = router({
|
|
|
1327
1151
|
schema: z.string(),
|
|
1328
1152
|
artifactId: z.string()
|
|
1329
1153
|
})).query(async ({ ctx, input }) => {
|
|
1330
|
-
const info = (await
|
|
1154
|
+
const info = (await fetchOpsxTemplateContents(ctx, input.schema))[input.artifactId];
|
|
1331
1155
|
if (!info) throw new Error(`Template not found for ${input.schema}:${input.artifactId}`);
|
|
1332
|
-
return
|
|
1333
|
-
content: await reactiveReadFile(info.path),
|
|
1334
|
-
path: info.path,
|
|
1335
|
-
source: info.source
|
|
1336
|
-
};
|
|
1156
|
+
return info;
|
|
1337
1157
|
}),
|
|
1338
1158
|
subscribeTemplateContent: publicProcedure.input(z.object({
|
|
1339
1159
|
schema: z.string(),
|
|
1340
1160
|
artifactId: z.string()
|
|
1341
1161
|
})).subscription(({ ctx, input }) => {
|
|
1342
1162
|
return createReactiveSubscription(async () => {
|
|
1343
|
-
const info = (await
|
|
1163
|
+
const info = (await fetchOpsxTemplateContents(ctx, input.schema))[input.artifactId];
|
|
1344
1164
|
if (!info) throw new Error(`Template not found for ${input.schema}:${input.artifactId}`);
|
|
1345
|
-
return
|
|
1346
|
-
content: await reactiveReadFile(info.path),
|
|
1347
|
-
path: info.path,
|
|
1348
|
-
source: info.source
|
|
1349
|
-
};
|
|
1165
|
+
return info;
|
|
1350
1166
|
});
|
|
1351
1167
|
}),
|
|
1352
1168
|
writeTemplateContent: publicProcedure.input(z.object({
|
|
@@ -1362,7 +1178,6 @@ const opsxRouter = router({
|
|
|
1362
1178
|
return { success: true };
|
|
1363
1179
|
}),
|
|
1364
1180
|
deleteSchema: publicProcedure.input(z.object({ name: z.string() })).mutation(async ({ ctx, input }) => {
|
|
1365
|
-
await touchOpsxProjectDeps(ctx.projectDir);
|
|
1366
1181
|
const resolution = await fetchOpsxSchemaResolution(ctx, input.name);
|
|
1367
1182
|
ensureEditableSource(resolution.source, "schema");
|
|
1368
1183
|
await rm(resolution.path, {
|
|
@@ -1372,11 +1187,15 @@ const opsxRouter = router({
|
|
|
1372
1187
|
return { success: true };
|
|
1373
1188
|
}),
|
|
1374
1189
|
projectConfig: publicProcedure.query(async ({ ctx }) => {
|
|
1375
|
-
|
|
1190
|
+
await ctx.kernel.waitForWarmup();
|
|
1191
|
+
await ctx.kernel.ensureProjectConfig();
|
|
1192
|
+
return ctx.kernel.getProjectConfig();
|
|
1376
1193
|
}),
|
|
1377
1194
|
subscribeProjectConfig: publicProcedure.subscription(({ ctx }) => {
|
|
1378
1195
|
return createReactiveSubscription(async () => {
|
|
1379
|
-
|
|
1196
|
+
await ctx.kernel.waitForWarmup();
|
|
1197
|
+
await ctx.kernel.ensureProjectConfig();
|
|
1198
|
+
return ctx.kernel.getProjectConfig();
|
|
1380
1199
|
});
|
|
1381
1200
|
}),
|
|
1382
1201
|
writeProjectConfig: publicProcedure.input(z.object({ content: z.string() })).mutation(async ({ ctx, input }) => {
|
|
@@ -1386,55 +1205,63 @@ const opsxRouter = router({
|
|
|
1386
1205
|
return { success: true };
|
|
1387
1206
|
}),
|
|
1388
1207
|
listChanges: publicProcedure.query(async ({ ctx }) => {
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
includeHidden: false
|
|
1393
|
-
});
|
|
1208
|
+
await ctx.kernel.waitForWarmup();
|
|
1209
|
+
await ctx.kernel.ensureChangeIds();
|
|
1210
|
+
return ctx.kernel.getChangeIds();
|
|
1394
1211
|
}),
|
|
1395
1212
|
subscribeChanges: publicProcedure.subscription(({ ctx }) => {
|
|
1396
1213
|
return createReactiveSubscription(async () => {
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
includeHidden: false
|
|
1401
|
-
});
|
|
1214
|
+
await ctx.kernel.waitForWarmup();
|
|
1215
|
+
await ctx.kernel.ensureChangeIds();
|
|
1216
|
+
return ctx.kernel.getChangeIds();
|
|
1402
1217
|
});
|
|
1403
1218
|
}),
|
|
1404
1219
|
changeMetadata: publicProcedure.input(z.object({ changeId: z.string() })).query(async ({ ctx, input }) => {
|
|
1405
|
-
|
|
1220
|
+
await ctx.kernel.waitForWarmup();
|
|
1221
|
+
await ctx.kernel.ensureChangeMetadata(input.changeId);
|
|
1222
|
+
return ctx.kernel.getChangeMetadata(input.changeId);
|
|
1406
1223
|
}),
|
|
1407
1224
|
subscribeChangeMetadata: publicProcedure.input(z.object({ changeId: z.string() })).subscription(({ ctx, input }) => {
|
|
1408
1225
|
return createReactiveSubscription(async () => {
|
|
1409
|
-
|
|
1226
|
+
await ctx.kernel.waitForWarmup();
|
|
1227
|
+
await ctx.kernel.ensureChangeMetadata(input.changeId);
|
|
1228
|
+
return ctx.kernel.getChangeMetadata(input.changeId);
|
|
1410
1229
|
});
|
|
1411
1230
|
}),
|
|
1412
1231
|
readArtifactOutput: publicProcedure.input(z.object({
|
|
1413
1232
|
changeId: z.string(),
|
|
1414
1233
|
outputPath: z.string()
|
|
1415
1234
|
})).query(async ({ ctx, input }) => {
|
|
1416
|
-
|
|
1235
|
+
await ctx.kernel.waitForWarmup();
|
|
1236
|
+
await ctx.kernel.ensureArtifactOutput(input.changeId, input.outputPath);
|
|
1237
|
+
return ctx.kernel.getArtifactOutput(input.changeId, input.outputPath);
|
|
1417
1238
|
}),
|
|
1418
1239
|
subscribeArtifactOutput: publicProcedure.input(z.object({
|
|
1419
1240
|
changeId: z.string(),
|
|
1420
1241
|
outputPath: z.string()
|
|
1421
1242
|
})).subscription(({ ctx, input }) => {
|
|
1422
1243
|
return createReactiveSubscription(async () => {
|
|
1423
|
-
|
|
1244
|
+
await ctx.kernel.waitForWarmup();
|
|
1245
|
+
await ctx.kernel.ensureArtifactOutput(input.changeId, input.outputPath);
|
|
1246
|
+
return ctx.kernel.getArtifactOutput(input.changeId, input.outputPath);
|
|
1424
1247
|
});
|
|
1425
1248
|
}),
|
|
1426
1249
|
readGlobArtifactFiles: publicProcedure.input(z.object({
|
|
1427
1250
|
changeId: z.string(),
|
|
1428
1251
|
outputPath: z.string()
|
|
1429
1252
|
})).query(async ({ ctx, input }) => {
|
|
1430
|
-
|
|
1253
|
+
await ctx.kernel.waitForWarmup();
|
|
1254
|
+
await ctx.kernel.ensureGlobArtifactFiles(input.changeId, input.outputPath);
|
|
1255
|
+
return ctx.kernel.getGlobArtifactFiles(input.changeId, input.outputPath);
|
|
1431
1256
|
}),
|
|
1432
1257
|
subscribeGlobArtifactFiles: publicProcedure.input(z.object({
|
|
1433
1258
|
changeId: z.string(),
|
|
1434
1259
|
outputPath: z.string()
|
|
1435
1260
|
})).subscription(({ ctx, input }) => {
|
|
1436
1261
|
return createReactiveSubscription(async () => {
|
|
1437
|
-
|
|
1262
|
+
await ctx.kernel.waitForWarmup();
|
|
1263
|
+
await ctx.kernel.ensureGlobArtifactFiles(input.changeId, input.outputPath);
|
|
1264
|
+
return ctx.kernel.getGlobArtifactFiles(input.changeId, input.outputPath);
|
|
1438
1265
|
});
|
|
1439
1266
|
}),
|
|
1440
1267
|
writeArtifactOutput: publicProcedure.input(z.object({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openspecui/server",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.mjs",
|
|
6
6
|
"exports": {
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"yaml": "^2.8.0",
|
|
21
21
|
"yargs": "^18.0.0",
|
|
22
22
|
"zod": "^3.24.1",
|
|
23
|
-
"@openspecui/
|
|
24
|
-
"@openspecui/
|
|
23
|
+
"@openspecui/core": "1.1.2",
|
|
24
|
+
"@openspecui/search": "1.1.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^22.10.2",
|