@openspecui/server 1.1.0 → 1.2.0
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 +106 -266
- 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
|
|
|
@@ -81,6 +80,8 @@ var PtySession = class extends EventEmitter {
|
|
|
81
80
|
command;
|
|
82
81
|
args;
|
|
83
82
|
platform;
|
|
83
|
+
closeTip;
|
|
84
|
+
closeCallbackUrl;
|
|
84
85
|
createdAt;
|
|
85
86
|
process;
|
|
86
87
|
titleInterval = null;
|
|
@@ -104,6 +105,8 @@ var PtySession = class extends EventEmitter {
|
|
|
104
105
|
this.command = resolvedCommand.command;
|
|
105
106
|
this.args = resolvedCommand.args;
|
|
106
107
|
this.platform = opts.platform;
|
|
108
|
+
this.closeTip = opts.closeTip;
|
|
109
|
+
this.closeCallbackUrl = opts.closeCallbackUrl;
|
|
107
110
|
this.maxBufferLines = opts.scrollback ?? DEFAULT_SCROLLBACK;
|
|
108
111
|
this.maxBufferBytes = opts.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES;
|
|
109
112
|
this.process = pty.spawn(this.command, this.args, {
|
|
@@ -184,6 +187,8 @@ var PtySession = class extends EventEmitter {
|
|
|
184
187
|
platform: this.platform,
|
|
185
188
|
isExited: this.isExited,
|
|
186
189
|
exitCode: this.exitCode,
|
|
190
|
+
closeTip: this.closeTip,
|
|
191
|
+
closeCallbackUrl: this.closeCallbackUrl,
|
|
187
192
|
createdAt: this.createdAt
|
|
188
193
|
};
|
|
189
194
|
}
|
|
@@ -203,6 +208,8 @@ var PtyManager = class {
|
|
|
203
208
|
rows: opts.rows,
|
|
204
209
|
command: opts.command,
|
|
205
210
|
args: opts.args,
|
|
211
|
+
closeTip: opts.closeTip,
|
|
212
|
+
closeCallbackUrl: opts.closeCallbackUrl,
|
|
206
213
|
cwd: this.defaultCwd,
|
|
207
214
|
scrollback: opts.scrollback,
|
|
208
215
|
maxBufferBytes: opts.maxBufferBytes,
|
|
@@ -307,11 +314,14 @@ function createPtyWebSocketHandler(ptyManager) {
|
|
|
307
314
|
switch (msg.type) {
|
|
308
315
|
case "create":
|
|
309
316
|
try {
|
|
317
|
+
const createMessage = msg;
|
|
310
318
|
const session = ptyManager.create({
|
|
311
319
|
cols: msg.cols,
|
|
312
320
|
rows: msg.rows,
|
|
313
321
|
command: msg.command,
|
|
314
|
-
args: msg.args
|
|
322
|
+
args: msg.args,
|
|
323
|
+
closeTip: createMessage.closeTip,
|
|
324
|
+
closeCallbackUrl: createMessage.closeCallbackUrl
|
|
315
325
|
});
|
|
316
326
|
send({
|
|
317
327
|
type: "created",
|
|
@@ -367,7 +377,9 @@ function createPtyWebSocketHandler(ptyManager) {
|
|
|
367
377
|
args: s.args,
|
|
368
378
|
platform: s.platform,
|
|
369
379
|
isExited: s.isExited,
|
|
370
|
-
exitCode: s.exitCode
|
|
380
|
+
exitCode: s.exitCode,
|
|
381
|
+
closeTip: s.closeTip,
|
|
382
|
+
closeCallbackUrl: s.closeCallbackUrl
|
|
371
383
|
}))
|
|
372
384
|
});
|
|
373
385
|
break;
|
|
@@ -465,53 +477,6 @@ function createCliStreamObservable(startStream) {
|
|
|
465
477
|
});
|
|
466
478
|
}
|
|
467
479
|
|
|
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
480
|
//#endregion
|
|
516
481
|
//#region src/reactive-kv.ts
|
|
517
482
|
/**
|
|
@@ -639,20 +604,6 @@ function requireChangeId(changeId) {
|
|
|
639
604
|
function ensureEditableSource(source, label) {
|
|
640
605
|
if (source === "package") throw new Error(`${label} is read-only (package source)`);
|
|
641
606
|
}
|
|
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
607
|
function resolveEntryPath(root, entryPath) {
|
|
657
608
|
const normalizedRoot = resolve(root);
|
|
658
609
|
const resolvedPath = resolve(normalizedRoot, entryPath);
|
|
@@ -660,153 +611,62 @@ function resolveEntryPath(root, entryPath) {
|
|
|
660
611
|
if (resolvedPath !== normalizedRoot && !resolvedPath.startsWith(rootPrefix)) throw new Error("Invalid path: outside schema root");
|
|
661
612
|
return resolvedPath;
|
|
662
613
|
}
|
|
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
614
|
async function fetchOpsxStatus(ctx, input) {
|
|
725
615
|
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;
|
|
616
|
+
await ctx.kernel.waitForWarmup();
|
|
617
|
+
await ctx.kernel.ensureStatus(changeId, input.schema);
|
|
618
|
+
return ctx.kernel.getStatus(changeId, input.schema);
|
|
741
619
|
}
|
|
742
620
|
async function fetchOpsxStatusList(ctx) {
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
exclude: ["archive"]
|
|
747
|
-
});
|
|
748
|
-
return await Promise.all(changeIds.map((changeId) => fetchOpsxStatus(ctx, { change: changeId })));
|
|
621
|
+
await ctx.kernel.waitForWarmup();
|
|
622
|
+
await ctx.kernel.ensureStatusList();
|
|
623
|
+
return ctx.kernel.getStatusList();
|
|
749
624
|
}
|
|
750
625
|
async function fetchOpsxInstructions(ctx, input) {
|
|
751
626
|
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");
|
|
627
|
+
await ctx.kernel.waitForWarmup();
|
|
628
|
+
await ctx.kernel.ensureInstructions(changeId, input.artifact, input.schema);
|
|
629
|
+
return ctx.kernel.getInstructions(changeId, input.artifact, input.schema);
|
|
765
630
|
}
|
|
766
631
|
async function fetchOpsxApplyInstructions(ctx, input) {
|
|
767
632
|
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");
|
|
633
|
+
await ctx.kernel.waitForWarmup();
|
|
634
|
+
await ctx.kernel.ensureApplyInstructions(changeId, input.schema);
|
|
635
|
+
return ctx.kernel.getApplyInstructions(changeId, input.schema);
|
|
781
636
|
}
|
|
782
|
-
async function
|
|
783
|
-
await
|
|
784
|
-
const
|
|
785
|
-
|
|
786
|
-
|
|
637
|
+
async function fetchOpsxConfigBundle(ctx) {
|
|
638
|
+
await ctx.kernel.ensureSchemas();
|
|
639
|
+
const schemas = ctx.kernel.getSchemas();
|
|
640
|
+
for (const schema of schemas) {
|
|
641
|
+
ctx.kernel.ensureSchemaDetail(schema.name).catch(() => {});
|
|
642
|
+
ctx.kernel.ensureSchemaResolution(schema.name).catch(() => {});
|
|
643
|
+
}
|
|
644
|
+
const schemaDetails = {};
|
|
645
|
+
const schemaResolutions = {};
|
|
646
|
+
for (const schema of schemas) {
|
|
647
|
+
schemaDetails[schema.name] = ctx.kernel.peekSchemaDetail(schema.name);
|
|
648
|
+
schemaResolutions[schema.name] = ctx.kernel.peekSchemaResolution(schema.name);
|
|
649
|
+
}
|
|
650
|
+
return {
|
|
651
|
+
schemas,
|
|
652
|
+
schemaDetails,
|
|
653
|
+
schemaResolutions
|
|
654
|
+
};
|
|
787
655
|
}
|
|
788
656
|
async function fetchOpsxSchemaResolution(ctx, name) {
|
|
789
|
-
await
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
return parseCliJson(result.stdout, SchemaResolutionSchema, "openspec schema which");
|
|
657
|
+
await ctx.kernel.waitForWarmup();
|
|
658
|
+
await ctx.kernel.ensureSchemaResolution(name);
|
|
659
|
+
return ctx.kernel.getSchemaResolution(name);
|
|
793
660
|
}
|
|
794
661
|
async function fetchOpsxTemplates(ctx, schema) {
|
|
795
|
-
await
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
return parseCliJson(result.stdout, TemplatesSchema, "openspec templates");
|
|
662
|
+
await ctx.kernel.waitForWarmup();
|
|
663
|
+
await ctx.kernel.ensureTemplates(schema);
|
|
664
|
+
return ctx.kernel.getTemplates(schema);
|
|
799
665
|
}
|
|
800
666
|
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);
|
|
667
|
+
await ctx.kernel.waitForWarmup();
|
|
668
|
+
await ctx.kernel.ensureTemplateContents(schema);
|
|
669
|
+
return ctx.kernel.getTemplateContents(schema);
|
|
810
670
|
}
|
|
811
671
|
/**
|
|
812
672
|
* Spec router - spec CRUD operations
|
|
@@ -1196,11 +1056,11 @@ const opsxRouter = router({
|
|
|
1196
1056
|
})).subscription(({ ctx, input }) => {
|
|
1197
1057
|
return createReactiveSubscription(() => fetchOpsxApplyInstructions(ctx, input));
|
|
1198
1058
|
}),
|
|
1199
|
-
|
|
1200
|
-
return
|
|
1059
|
+
configBundle: publicProcedure.query(async ({ ctx }) => {
|
|
1060
|
+
return fetchOpsxConfigBundle(ctx);
|
|
1201
1061
|
}),
|
|
1202
|
-
|
|
1203
|
-
return createReactiveSubscription(() =>
|
|
1062
|
+
subscribeConfigBundle: publicProcedure.subscription(({ ctx }) => {
|
|
1063
|
+
return createReactiveSubscription(() => fetchOpsxConfigBundle(ctx));
|
|
1204
1064
|
}),
|
|
1205
1065
|
templates: publicProcedure.input(z.object({ schema: z.string().optional() }).optional()).query(async ({ ctx, input }) => {
|
|
1206
1066
|
return fetchOpsxTemplates(ctx, input?.schema);
|
|
@@ -1214,53 +1074,34 @@ const opsxRouter = router({
|
|
|
1214
1074
|
subscribeTemplateContents: publicProcedure.input(z.object({ schema: z.string().optional() }).optional()).subscription(({ ctx, input }) => {
|
|
1215
1075
|
return createReactiveSubscription(() => fetchOpsxTemplateContents(ctx, input?.schema));
|
|
1216
1076
|
}),
|
|
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
1077
|
schemaFiles: publicProcedure.input(z.object({ name: z.string() })).query(async ({ ctx, input }) => {
|
|
1240
|
-
await
|
|
1241
|
-
|
|
1078
|
+
await ctx.kernel.waitForWarmup();
|
|
1079
|
+
await ctx.kernel.ensureSchemaFiles(input.name);
|
|
1080
|
+
return ctx.kernel.getSchemaFiles(input.name);
|
|
1242
1081
|
}),
|
|
1243
1082
|
subscribeSchemaFiles: publicProcedure.input(z.object({ name: z.string() })).subscription(({ ctx, input }) => {
|
|
1244
1083
|
return createReactiveSubscription(async () => {
|
|
1245
|
-
await
|
|
1246
|
-
|
|
1084
|
+
await ctx.kernel.waitForWarmup();
|
|
1085
|
+
await ctx.kernel.ensureSchemaFiles(input.name);
|
|
1086
|
+
return ctx.kernel.getSchemaFiles(input.name);
|
|
1247
1087
|
});
|
|
1248
1088
|
}),
|
|
1249
1089
|
schemaYaml: publicProcedure.input(z.object({ name: z.string() })).query(async ({ ctx, input }) => {
|
|
1250
|
-
await
|
|
1251
|
-
|
|
1090
|
+
await ctx.kernel.waitForWarmup();
|
|
1091
|
+
await ctx.kernel.ensureSchemaYaml(input.name);
|
|
1092
|
+
return ctx.kernel.getSchemaYaml(input.name);
|
|
1252
1093
|
}),
|
|
1253
1094
|
subscribeSchemaYaml: publicProcedure.input(z.object({ name: z.string() })).subscription(({ ctx, input }) => {
|
|
1254
1095
|
return createReactiveSubscription(async () => {
|
|
1255
|
-
await
|
|
1256
|
-
|
|
1096
|
+
await ctx.kernel.waitForWarmup();
|
|
1097
|
+
await ctx.kernel.ensureSchemaYaml(input.name);
|
|
1098
|
+
return ctx.kernel.getSchemaYaml(input.name);
|
|
1257
1099
|
});
|
|
1258
1100
|
}),
|
|
1259
1101
|
writeSchemaYaml: publicProcedure.input(z.object({
|
|
1260
1102
|
name: z.string(),
|
|
1261
1103
|
content: z.string()
|
|
1262
1104
|
})).mutation(async ({ ctx, input }) => {
|
|
1263
|
-
await touchOpsxProjectDeps(ctx.projectDir);
|
|
1264
1105
|
const resolution = await fetchOpsxSchemaResolution(ctx, input.name);
|
|
1265
1106
|
ensureEditableSource(resolution.source, "schema.yaml");
|
|
1266
1107
|
const schemaPath = join(resolution.path, "schema.yaml");
|
|
@@ -1273,7 +1114,6 @@ const opsxRouter = router({
|
|
|
1273
1114
|
path: z.string(),
|
|
1274
1115
|
content: z.string()
|
|
1275
1116
|
})).mutation(async ({ ctx, input }) => {
|
|
1276
|
-
await touchOpsxProjectDeps(ctx.projectDir);
|
|
1277
1117
|
const resolution = await fetchOpsxSchemaResolution(ctx, input.schema);
|
|
1278
1118
|
ensureEditableSource(resolution.source, "schema file");
|
|
1279
1119
|
if (!input.path.trim()) throw new Error("path is required");
|
|
@@ -1287,7 +1127,6 @@ const opsxRouter = router({
|
|
|
1287
1127
|
path: z.string(),
|
|
1288
1128
|
content: z.string().optional()
|
|
1289
1129
|
})).mutation(async ({ ctx, input }) => {
|
|
1290
|
-
await touchOpsxProjectDeps(ctx.projectDir);
|
|
1291
1130
|
const resolution = await fetchOpsxSchemaResolution(ctx, input.schema);
|
|
1292
1131
|
ensureEditableSource(resolution.source, "schema file");
|
|
1293
1132
|
if (!input.path.trim()) throw new Error("path is required");
|
|
@@ -1300,7 +1139,6 @@ const opsxRouter = router({
|
|
|
1300
1139
|
schema: z.string(),
|
|
1301
1140
|
path: z.string()
|
|
1302
1141
|
})).mutation(async ({ ctx, input }) => {
|
|
1303
|
-
await touchOpsxProjectDeps(ctx.projectDir);
|
|
1304
1142
|
const resolution = await fetchOpsxSchemaResolution(ctx, input.schema);
|
|
1305
1143
|
ensureEditableSource(resolution.source, "schema directory");
|
|
1306
1144
|
if (!input.path.trim()) throw new Error("path is required");
|
|
@@ -1311,7 +1149,6 @@ const opsxRouter = router({
|
|
|
1311
1149
|
schema: z.string(),
|
|
1312
1150
|
path: z.string()
|
|
1313
1151
|
})).mutation(async ({ ctx, input }) => {
|
|
1314
|
-
await touchOpsxProjectDeps(ctx.projectDir);
|
|
1315
1152
|
const resolution = await fetchOpsxSchemaResolution(ctx, input.schema);
|
|
1316
1153
|
ensureEditableSource(resolution.source, "schema entry");
|
|
1317
1154
|
if (!input.path.trim()) throw new Error("path is required");
|
|
@@ -1327,26 +1164,18 @@ const opsxRouter = router({
|
|
|
1327
1164
|
schema: z.string(),
|
|
1328
1165
|
artifactId: z.string()
|
|
1329
1166
|
})).query(async ({ ctx, input }) => {
|
|
1330
|
-
const info = (await
|
|
1167
|
+
const info = (await fetchOpsxTemplateContents(ctx, input.schema))[input.artifactId];
|
|
1331
1168
|
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
|
-
};
|
|
1169
|
+
return info;
|
|
1337
1170
|
}),
|
|
1338
1171
|
subscribeTemplateContent: publicProcedure.input(z.object({
|
|
1339
1172
|
schema: z.string(),
|
|
1340
1173
|
artifactId: z.string()
|
|
1341
1174
|
})).subscription(({ ctx, input }) => {
|
|
1342
1175
|
return createReactiveSubscription(async () => {
|
|
1343
|
-
const info = (await
|
|
1176
|
+
const info = (await fetchOpsxTemplateContents(ctx, input.schema))[input.artifactId];
|
|
1344
1177
|
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
|
-
};
|
|
1178
|
+
return info;
|
|
1350
1179
|
});
|
|
1351
1180
|
}),
|
|
1352
1181
|
writeTemplateContent: publicProcedure.input(z.object({
|
|
@@ -1362,7 +1191,6 @@ const opsxRouter = router({
|
|
|
1362
1191
|
return { success: true };
|
|
1363
1192
|
}),
|
|
1364
1193
|
deleteSchema: publicProcedure.input(z.object({ name: z.string() })).mutation(async ({ ctx, input }) => {
|
|
1365
|
-
await touchOpsxProjectDeps(ctx.projectDir);
|
|
1366
1194
|
const resolution = await fetchOpsxSchemaResolution(ctx, input.name);
|
|
1367
1195
|
ensureEditableSource(resolution.source, "schema");
|
|
1368
1196
|
await rm(resolution.path, {
|
|
@@ -1372,11 +1200,15 @@ const opsxRouter = router({
|
|
|
1372
1200
|
return { success: true };
|
|
1373
1201
|
}),
|
|
1374
1202
|
projectConfig: publicProcedure.query(async ({ ctx }) => {
|
|
1375
|
-
|
|
1203
|
+
await ctx.kernel.waitForWarmup();
|
|
1204
|
+
await ctx.kernel.ensureProjectConfig();
|
|
1205
|
+
return ctx.kernel.getProjectConfig();
|
|
1376
1206
|
}),
|
|
1377
1207
|
subscribeProjectConfig: publicProcedure.subscription(({ ctx }) => {
|
|
1378
1208
|
return createReactiveSubscription(async () => {
|
|
1379
|
-
|
|
1209
|
+
await ctx.kernel.waitForWarmup();
|
|
1210
|
+
await ctx.kernel.ensureProjectConfig();
|
|
1211
|
+
return ctx.kernel.getProjectConfig();
|
|
1380
1212
|
});
|
|
1381
1213
|
}),
|
|
1382
1214
|
writeProjectConfig: publicProcedure.input(z.object({ content: z.string() })).mutation(async ({ ctx, input }) => {
|
|
@@ -1386,55 +1218,63 @@ const opsxRouter = router({
|
|
|
1386
1218
|
return { success: true };
|
|
1387
1219
|
}),
|
|
1388
1220
|
listChanges: publicProcedure.query(async ({ ctx }) => {
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
includeHidden: false
|
|
1393
|
-
});
|
|
1221
|
+
await ctx.kernel.waitForWarmup();
|
|
1222
|
+
await ctx.kernel.ensureChangeIds();
|
|
1223
|
+
return ctx.kernel.getChangeIds();
|
|
1394
1224
|
}),
|
|
1395
1225
|
subscribeChanges: publicProcedure.subscription(({ ctx }) => {
|
|
1396
1226
|
return createReactiveSubscription(async () => {
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
includeHidden: false
|
|
1401
|
-
});
|
|
1227
|
+
await ctx.kernel.waitForWarmup();
|
|
1228
|
+
await ctx.kernel.ensureChangeIds();
|
|
1229
|
+
return ctx.kernel.getChangeIds();
|
|
1402
1230
|
});
|
|
1403
1231
|
}),
|
|
1404
1232
|
changeMetadata: publicProcedure.input(z.object({ changeId: z.string() })).query(async ({ ctx, input }) => {
|
|
1405
|
-
|
|
1233
|
+
await ctx.kernel.waitForWarmup();
|
|
1234
|
+
await ctx.kernel.ensureChangeMetadata(input.changeId);
|
|
1235
|
+
return ctx.kernel.getChangeMetadata(input.changeId);
|
|
1406
1236
|
}),
|
|
1407
1237
|
subscribeChangeMetadata: publicProcedure.input(z.object({ changeId: z.string() })).subscription(({ ctx, input }) => {
|
|
1408
1238
|
return createReactiveSubscription(async () => {
|
|
1409
|
-
|
|
1239
|
+
await ctx.kernel.waitForWarmup();
|
|
1240
|
+
await ctx.kernel.ensureChangeMetadata(input.changeId);
|
|
1241
|
+
return ctx.kernel.getChangeMetadata(input.changeId);
|
|
1410
1242
|
});
|
|
1411
1243
|
}),
|
|
1412
1244
|
readArtifactOutput: publicProcedure.input(z.object({
|
|
1413
1245
|
changeId: z.string(),
|
|
1414
1246
|
outputPath: z.string()
|
|
1415
1247
|
})).query(async ({ ctx, input }) => {
|
|
1416
|
-
|
|
1248
|
+
await ctx.kernel.waitForWarmup();
|
|
1249
|
+
await ctx.kernel.ensureArtifactOutput(input.changeId, input.outputPath);
|
|
1250
|
+
return ctx.kernel.getArtifactOutput(input.changeId, input.outputPath);
|
|
1417
1251
|
}),
|
|
1418
1252
|
subscribeArtifactOutput: publicProcedure.input(z.object({
|
|
1419
1253
|
changeId: z.string(),
|
|
1420
1254
|
outputPath: z.string()
|
|
1421
1255
|
})).subscription(({ ctx, input }) => {
|
|
1422
1256
|
return createReactiveSubscription(async () => {
|
|
1423
|
-
|
|
1257
|
+
await ctx.kernel.waitForWarmup();
|
|
1258
|
+
await ctx.kernel.ensureArtifactOutput(input.changeId, input.outputPath);
|
|
1259
|
+
return ctx.kernel.getArtifactOutput(input.changeId, input.outputPath);
|
|
1424
1260
|
});
|
|
1425
1261
|
}),
|
|
1426
1262
|
readGlobArtifactFiles: publicProcedure.input(z.object({
|
|
1427
1263
|
changeId: z.string(),
|
|
1428
1264
|
outputPath: z.string()
|
|
1429
1265
|
})).query(async ({ ctx, input }) => {
|
|
1430
|
-
|
|
1266
|
+
await ctx.kernel.waitForWarmup();
|
|
1267
|
+
await ctx.kernel.ensureGlobArtifactFiles(input.changeId, input.outputPath);
|
|
1268
|
+
return ctx.kernel.getGlobArtifactFiles(input.changeId, input.outputPath);
|
|
1431
1269
|
}),
|
|
1432
1270
|
subscribeGlobArtifactFiles: publicProcedure.input(z.object({
|
|
1433
1271
|
changeId: z.string(),
|
|
1434
1272
|
outputPath: z.string()
|
|
1435
1273
|
})).subscription(({ ctx, input }) => {
|
|
1436
1274
|
return createReactiveSubscription(async () => {
|
|
1437
|
-
|
|
1275
|
+
await ctx.kernel.waitForWarmup();
|
|
1276
|
+
await ctx.kernel.ensureGlobArtifactFiles(input.changeId, input.outputPath);
|
|
1277
|
+
return ctx.kernel.getGlobArtifactFiles(input.changeId, input.outputPath);
|
|
1438
1278
|
});
|
|
1439
1279
|
}),
|
|
1440
1280
|
writeArtifactOutput: publicProcedure.input(z.object({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openspecui/server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
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.2.0",
|
|
24
|
+
"@openspecui/search": "1.1.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^22.10.2",
|