openspecui 1.1.1 → 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.
Files changed (31) hide show
  1. package/dist/cli.mjs +2 -2
  2. package/dist/index.mjs +1 -1
  3. package/dist/{src-CzjuiMYe.mjs → src-E2ERj6H4.mjs} +305 -411
  4. package/package.json +3 -3
  5. package/web/assets/{BufferResource-BynRzySn.js → BufferResource-DdnZHNU-.js} +1 -1
  6. package/web/assets/{CanvasRenderer-CbECvW_h.js → CanvasRenderer-W0-8maEY.js} +1 -1
  7. package/web/assets/{Filter-BjiflTCt.js → Filter-BCHzFO9X.js} +1 -1
  8. package/web/assets/{RenderTargetSystem-CD3Xxio1.js → RenderTargetSystem-QYja7U1C.js} +1 -1
  9. package/web/assets/{WebGLRenderer-DsWqcm9A.js → WebGLRenderer-CN6ngwpu.js} +1 -1
  10. package/web/assets/{WebGPURenderer-BnVEe7ZL.js → WebGPURenderer-CSfhxPBR.js} +1 -1
  11. package/web/assets/{browserAll-Cb6nfsf4.js → browserAll-CChvoSPa.js} +1 -1
  12. package/web/assets/{index-DmhYrwH_.js → index-8kjDfgtP.js} +1 -1
  13. package/web/assets/index-BBa-UOW9.css +1 -0
  14. package/web/assets/{index-o68ShgAu.js → index-BPuO-i8p.js} +1 -1
  15. package/web/assets/{index-3oN9R9iN.js → index-BTVg5Nau.js} +1 -1
  16. package/web/assets/{index-CSmGqpdI.js → index-BcA9ozYL.js} +171 -171
  17. package/web/assets/{index-B5u6uSVz.js → index-CWB6CIXv.js} +1 -1
  18. package/web/assets/{index-CsSu022q.js → index-Ca41ecb5.js} +1 -1
  19. package/web/assets/{index-C5CFYfMw.js → index-CoF0ewHZ.js} +1 -1
  20. package/web/assets/{index-BkA1vsv2.js → index-D2pLblyv.js} +1 -1
  21. package/web/assets/{index-F5V_nJpw.js → index-DS0kz2NM.js} +1 -1
  22. package/web/assets/{index-D2zSLUgf.js → index-DSkiV8t7.js} +1 -1
  23. package/web/assets/{index-CVWM2euh.js → index-DWh8uDpX.js} +1 -1
  24. package/web/assets/{index-CbMWJK9x.js → index-DXb6uuwe.js} +1 -1
  25. package/web/assets/{index-BiSFkDHl.js → index-Do3bWt1y.js} +1 -1
  26. package/web/assets/{index-DRNAjv5N.js → index-a4zt_8am.js} +1 -1
  27. package/web/assets/{index-mA1BhKJg.js → index-fWg8Cn9O.js} +1 -1
  28. package/web/assets/{index-DaJuvT8s.js → index-hysFimNk.js} +1 -1
  29. package/web/assets/{webworkerAll-DfP6Gnah.js → webworkerAll-T10QBdIL.js} +1 -1
  30. package/web/index.html +2 -2
  31. package/web/assets/index-BfjQi4qu.css +0 -1
@@ -13657,7 +13657,7 @@ var require_public_api = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnp
13657
13657
  }
13658
13658
  return doc;
13659
13659
  }
13660
- function parse$4(src, reviver, options) {
13660
+ function parse$3(src, reviver, options) {
13661
13661
  let _reviver = void 0;
13662
13662
  if (typeof reviver === "function") _reviver = reviver;
13663
13663
  else if (options === void 0 && reviver && typeof reviver === "object") options = reviver;
@@ -13684,7 +13684,7 @@ var require_public_api = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnp
13684
13684
  if (identity$2.isDocument(value) && !_replacer) return value.toString(options);
13685
13685
  return new Document$1.Document(value, _replacer, options).toString(options);
13686
13686
  }
13687
- exports.parse = parse$4;
13687
+ exports.parse = parse$3;
13688
13688
  exports.parseAllDocuments = parseAllDocuments;
13689
13689
  exports.parseDocument = parseDocument;
13690
13690
  exports.stringify = stringify;
@@ -13741,8 +13741,8 @@ var require_dist = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnpm/yaml
13741
13741
 
13742
13742
  //#endregion
13743
13743
  //#region ../core/src/opsx-kernel.ts
13744
- var import_dist$1 = require_dist();
13745
- function parseCliJson$1(raw$1, schema$6, label) {
13744
+ var import_dist = require_dist();
13745
+ function parseCliJson(raw$1, schema$6, label) {
13746
13746
  const trimmed = raw$1.trim();
13747
13747
  if (!trimmed) throw new Error(`${label} returned empty output`);
13748
13748
  let parsed;
@@ -13756,10 +13756,10 @@ function parseCliJson$1(raw$1, schema$6, label) {
13756
13756
  if (!result.success) throw new Error(`${label} returned unexpected JSON: ${result.error.message}`);
13757
13757
  return result.data;
13758
13758
  }
13759
- function toRelativePath$1(root, absolutePath) {
13759
+ function toRelativePath(root, absolutePath) {
13760
13760
  return relative$1(root, absolutePath).split(sep).join("/");
13761
13761
  }
13762
- async function readEntriesUnderRoot$1(root) {
13762
+ async function readEntriesUnderRoot(root) {
13763
13763
  if (!(await reactiveStat(root))?.isDirectory) return [];
13764
13764
  const collectEntries = async (dir) => {
13765
13765
  const names = await reactiveReadDir(dir, { includeHidden: false });
@@ -13768,7 +13768,7 @@ async function readEntriesUnderRoot$1(root) {
13768
13768
  const fullPath = join$1(dir, name);
13769
13769
  const statInfo = await reactiveStat(fullPath);
13770
13770
  if (!statInfo) continue;
13771
- const relativePath = toRelativePath$1(root, fullPath);
13771
+ const relativePath = toRelativePath(root, fullPath);
13772
13772
  if (statInfo.isDirectory) {
13773
13773
  entries.push({
13774
13774
  path: relativePath,
@@ -13790,14 +13790,14 @@ async function readEntriesUnderRoot$1(root) {
13790
13790
  };
13791
13791
  return collectEntries(root);
13792
13792
  }
13793
- async function readGlobArtifactFiles$1(projectDir, changeId, outputPath) {
13794
- return (await readEntriesUnderRoot$1(join$1(projectDir, "openspec", "changes", changeId))).filter((entry) => entry.type === "file" && matchesGlob(entry.path, outputPath)).map((entry) => ({
13793
+ async function readGlobArtifactFiles(projectDir, changeId, outputPath) {
13794
+ return (await readEntriesUnderRoot(join$1(projectDir, "openspec", "changes", changeId))).filter((entry) => entry.type === "file" && matchesGlob(entry.path, outputPath)).map((entry) => ({
13795
13795
  path: entry.path,
13796
13796
  type: "file",
13797
13797
  content: entry.content ?? ""
13798
13798
  }));
13799
13799
  }
13800
- async function touchOpsxProjectDeps$1(projectDir) {
13800
+ async function touchOpsxProjectDeps(projectDir) {
13801
13801
  const openspecDir = join$1(projectDir, "openspec");
13802
13802
  await reactiveReadFile(join$1(openspecDir, "config.yaml"));
13803
13803
  const schemaRoot = join$1(openspecDir, "schemas");
@@ -13812,7 +13812,7 @@ async function touchOpsxProjectDeps$1(projectDir) {
13812
13812
  exclude: ["archive"]
13813
13813
  });
13814
13814
  }
13815
- async function touchOpsxChangeDeps$1(projectDir, changeId) {
13815
+ async function touchOpsxChangeDeps(projectDir, changeId) {
13816
13816
  const changeDir = join$1(projectDir, "openspec", "changes", changeId);
13817
13817
  await reactiveReadDir(changeDir, { includeHidden: true });
13818
13818
  await reactiveReadFile(join$1(changeDir, ".openspec.yaml"));
@@ -13821,6 +13821,8 @@ var OpsxKernel = class {
13821
13821
  projectDir;
13822
13822
  cliExecutor;
13823
13823
  controller = new AbortController();
13824
+ warmupPromise = null;
13825
+ _streamReady = /* @__PURE__ */ new Map();
13824
13826
  _statusList = new ReactiveState([]);
13825
13827
  _schemas = new ReactiveState([]);
13826
13828
  _changeIds = new ReactiveState([]);
@@ -13843,17 +13845,28 @@ var OpsxKernel = class {
13843
13845
  this.cliExecutor = cliExecutor;
13844
13846
  }
13845
13847
  async warmup() {
13848
+ if (this.warmupPromise) return this.warmupPromise;
13849
+ this.warmupPromise = this.runWarmup().catch((error) => {
13850
+ this.warmupPromise = null;
13851
+ throw error;
13852
+ });
13853
+ return this.warmupPromise;
13854
+ }
13855
+ async waitForWarmup() {
13856
+ await this.warmup();
13857
+ }
13858
+ async runWarmup() {
13846
13859
  const signal = this.controller.signal;
13847
13860
  await Promise.all([
13848
- this.startStream(this._schemas, () => this.fetchSchemas(), signal),
13849
- this.startStream(this._changeIds, () => this.fetchChangeIds(), signal),
13850
- this.startStream(this._projectConfig, () => this.fetchProjectConfig(), signal)
13861
+ this.startStreamOnce("global:schemas", this._schemas, () => this.fetchSchemas(), signal),
13862
+ this.startStreamOnce("global:change-ids", this._changeIds, () => this.fetchChangeIds(), signal),
13863
+ this.startStreamOnce("global:project-config", this._projectConfig, () => this.fetchProjectConfig(), signal)
13851
13864
  ]);
13852
13865
  const schemas$1 = this._schemas.get();
13853
13866
  await Promise.all(schemas$1.map((s) => this.warmupSchema(s.name, signal)));
13854
13867
  const changeIds = this._changeIds.get();
13855
13868
  await Promise.all(changeIds.map((id) => this.warmupChange(id, signal)));
13856
- await this.startStream(this._statusList, () => this.fetchStatusList(), signal);
13869
+ await this.startStreamOnce("global:status-list", this._statusList, () => this.fetchStatusList(), signal);
13857
13870
  this.watchSchemaChanges(signal);
13858
13871
  this.watchChangeIdChanges(signal);
13859
13872
  }
@@ -13861,6 +13874,8 @@ var OpsxKernel = class {
13861
13874
  this.controller.abort();
13862
13875
  for (const ctrl of this._entityControllers.values()) ctrl.abort();
13863
13876
  this._entityControllers.clear();
13877
+ this._streamReady.clear();
13878
+ this.warmupPromise = null;
13864
13879
  }
13865
13880
  getStatusList() {
13866
13881
  return this._statusList.get();
@@ -13907,11 +13922,21 @@ var OpsxKernel = class {
13907
13922
  if (!state) throw new Error(`Schema resolution not found for "${name}"`);
13908
13923
  return state.get();
13909
13924
  }
13925
+ peekSchemaResolution(name) {
13926
+ const state = this._schemaResolutions.get(name);
13927
+ if (!state) return null;
13928
+ return state.get() ?? null;
13929
+ }
13910
13930
  getSchemaDetail(name) {
13911
13931
  const state = this._schemaDetails.get(name);
13912
13932
  if (!state) throw new Error(`Schema detail not found for "${name}"`);
13913
13933
  return state.get();
13914
13934
  }
13935
+ peekSchemaDetail(name) {
13936
+ const state = this._schemaDetails.get(name);
13937
+ if (!state) return null;
13938
+ return state.get() ?? null;
13939
+ }
13915
13940
  getSchemaFiles(name) {
13916
13941
  const state = this._schemaFiles.get(name);
13917
13942
  if (!state) throw new Error(`Schema files not found for "${name}"`);
@@ -13940,7 +13965,7 @@ var OpsxKernel = class {
13940
13965
  return state.get();
13941
13966
  }
13942
13967
  startStream(state, task, signal) {
13943
- return new Promise((resolve$2) => {
13968
+ return new Promise((resolve$2, reject) => {
13944
13969
  const context = new ReactiveContext();
13945
13970
  let first = true;
13946
13971
  (async () => {
@@ -13952,12 +13977,28 @@ var OpsxKernel = class {
13952
13977
  resolve$2();
13953
13978
  }
13954
13979
  }
13955
- } catch {}
13980
+ } catch (error) {
13981
+ if (first && !signal.aborted) {
13982
+ reject(error);
13983
+ return;
13984
+ }
13985
+ }
13956
13986
  if (first) resolve$2();
13957
13987
  })();
13958
13988
  });
13959
13989
  }
13990
+ startStreamOnce(key, state, task, signal) {
13991
+ const existing = this._streamReady.get(key);
13992
+ if (existing) return existing;
13993
+ const ready = this.startStream(state, task, signal).catch((error) => {
13994
+ this._streamReady.delete(key);
13995
+ throw error;
13996
+ });
13997
+ this._streamReady.set(key, ready);
13998
+ return ready;
13999
+ }
13960
14000
  async warmupSchema(name, parentSignal) {
14001
+ if (this._entityControllers.has(`schema:${name}`)) return;
13961
14002
  const entityCtrl = new AbortController();
13962
14003
  this._entityControllers.set(`schema:${name}`, entityCtrl);
13963
14004
  const signal = this.combineSignals(parentSignal, entityCtrl.signal);
@@ -13970,17 +14011,18 @@ var OpsxKernel = class {
13970
14011
  if (!this._templates.has("")) this._templates.set("", new ReactiveState({}));
13971
14012
  if (!this._templateContents.has("")) this._templateContents.set("", new ReactiveState({}));
13972
14013
  await Promise.all([
13973
- this.startStream(this._schemaResolutions.get(name), () => this.fetchSchemaResolution(name), signal),
13974
- this.startStream(this._schemaDetails.get(name), () => this.fetchSchemaDetail(name), signal),
13975
- this.startStream(this._schemaFiles.get(name), () => this.fetchSchemaFiles(name), signal),
13976
- this.startStream(this._schemaYamls.get(name), () => this.fetchSchemaYaml(name), signal),
13977
- this.startStream(this._templates.get(name), () => this.fetchTemplates(name), signal),
13978
- this.startStream(this._templateContents.get(name), () => this.fetchTemplateContents(name), signal),
13979
- this.startStream(this._templates.get(""), () => this.fetchTemplates(void 0), signal),
13980
- this.startStream(this._templateContents.get(""), () => this.fetchTemplateContents(void 0), signal)
14014
+ this.startStreamOnce(`schema:${name}:resolution`, this._schemaResolutions.get(name), () => this.fetchSchemaResolution(name), signal),
14015
+ this.startStreamOnce(`schema:${name}:detail`, this._schemaDetails.get(name), () => this.fetchSchemaDetail(name), signal),
14016
+ this.startStreamOnce(`schema:${name}:files`, this._schemaFiles.get(name), () => this.fetchSchemaFiles(name), signal),
14017
+ this.startStreamOnce(`schema:${name}:yaml`, this._schemaYamls.get(name), () => this.fetchSchemaYaml(name), signal),
14018
+ this.startStreamOnce(`schema:${name}:templates`, this._templates.get(name), () => this.fetchTemplates(name), signal),
14019
+ this.startStreamOnce(`schema:${name}:template-contents`, this._templateContents.get(name), () => this.fetchTemplateContents(name), signal),
14020
+ this.startStreamOnce("schema::templates", this._templates.get(""), () => this.fetchTemplates(void 0), signal),
14021
+ this.startStreamOnce("schema::template-contents", this._templateContents.get(""), () => this.fetchTemplateContents(void 0), signal)
13981
14022
  ]);
13982
14023
  }
13983
14024
  async warmupChange(changeId, parentSignal) {
14025
+ if (this._entityControllers.has(`change:${changeId}`)) return;
13984
14026
  const entityCtrl = new AbortController();
13985
14027
  this._entityControllers.set(`change:${changeId}`, entityCtrl);
13986
14028
  const signal = this.combineSignals(parentSignal, entityCtrl.signal);
@@ -13990,22 +14032,22 @@ var OpsxKernel = class {
13990
14032
  const applyKey = `${changeId}:`;
13991
14033
  if (!this._applyInstructions.has(applyKey)) this._applyInstructions.set(applyKey, new ReactiveState(null));
13992
14034
  await Promise.all([
13993
- this.startStream(this._statuses.get(statusKey), () => this.fetchStatus(changeId, void 0), signal),
13994
- this.startStream(this._changeMetadata.get(changeId), () => this.fetchChangeMetadata(changeId), signal),
13995
- this.startStream(this._applyInstructions.get(applyKey), () => this.fetchApplyInstructions(changeId, void 0), signal)
14035
+ this.startStreamOnce(`change:${changeId}:status:`, this._statuses.get(statusKey), () => this.fetchStatus(changeId, void 0), signal),
14036
+ this.startStreamOnce(`change:${changeId}:metadata`, this._changeMetadata.get(changeId), () => this.fetchChangeMetadata(changeId), signal),
14037
+ this.startStreamOnce(`change:${changeId}:apply:`, this._applyInstructions.get(applyKey), () => this.fetchApplyInstructions(changeId, void 0), signal)
13996
14038
  ]);
13997
14039
  const status = this._statuses.get(statusKey)?.get();
13998
14040
  if (status?.artifacts) await Promise.all(status.artifacts.map(async (artifact) => {
13999
14041
  const instrKey = `${changeId}:${artifact.id}:`;
14000
14042
  if (!this._instructions.has(instrKey)) this._instructions.set(instrKey, new ReactiveState(null));
14001
- await this.startStream(this._instructions.get(instrKey), () => this.fetchInstructions(changeId, artifact.id, void 0), signal);
14043
+ await this.startStreamOnce(`change:${changeId}:instructions:${artifact.id}:`, this._instructions.get(instrKey), () => this.fetchInstructions(changeId, artifact.id, void 0), signal);
14002
14044
  const outputKey = `${changeId}:${artifact.outputPath}`;
14003
14045
  if (!this._artifactOutputs.has(outputKey)) this._artifactOutputs.set(outputKey, new ReactiveState(null));
14004
- await this.startStream(this._artifactOutputs.get(outputKey), () => this.fetchArtifactOutput(changeId, artifact.outputPath), signal);
14046
+ await this.startStreamOnce(`change:${changeId}:output:${artifact.outputPath}`, this._artifactOutputs.get(outputKey), () => this.fetchArtifactOutput(changeId, artifact.outputPath), signal);
14005
14047
  if (artifact.outputPath.includes("*") || artifact.outputPath.includes("?") || artifact.outputPath.includes("[")) {
14006
14048
  const globKey = `${changeId}:${artifact.outputPath}`;
14007
14049
  if (!this._globArtifactFiles.has(globKey)) this._globArtifactFiles.set(globKey, new ReactiveState([]));
14008
- await this.startStream(this._globArtifactFiles.get(globKey), () => readGlobArtifactFiles$1(this.projectDir, changeId, artifact.outputPath), signal);
14050
+ await this.startStreamOnce(`change:${changeId}:glob:${artifact.outputPath}`, this._globArtifactFiles.get(globKey), () => readGlobArtifactFiles(this.projectDir, changeId, artifact.outputPath), signal);
14009
14051
  }
14010
14052
  }));
14011
14053
  }
@@ -14016,7 +14058,7 @@ var OpsxKernel = class {
14016
14058
  try {
14017
14059
  for await (const schemas$1 of context.stream(() => Promise.resolve(this._schemas.get()), signal)) {
14018
14060
  const newNames = new Set(schemas$1.map((s) => s.name));
14019
- for (const name of newNames) if (!prevNames.has(name)) this.warmupSchema(name, signal);
14061
+ for (const name of newNames) if (!prevNames.has(name)) this.warmupSchema(name, signal).catch(() => {});
14020
14062
  for (const name of prevNames) if (!newNames.has(name)) {
14021
14063
  this.teardownEntity(`schema:${name}`);
14022
14064
  this._schemaResolutions.delete(name);
@@ -14025,6 +14067,7 @@ var OpsxKernel = class {
14025
14067
  this._schemaYamls.delete(name);
14026
14068
  this._templates.delete(name);
14027
14069
  this._templateContents.delete(name);
14070
+ this.clearStreamReadyByPrefix(`schema:${name}:`);
14028
14071
  }
14029
14072
  prevNames = newNames;
14030
14073
  }
@@ -14038,15 +14081,33 @@ var OpsxKernel = class {
14038
14081
  try {
14039
14082
  for await (const ids of context.stream(() => Promise.resolve(this._changeIds.get()), signal)) {
14040
14083
  const newIds = new Set(ids);
14041
- for (const id of newIds) if (!prevIds.has(id)) this.warmupChange(id, signal);
14084
+ for (const id of newIds) if (!prevIds.has(id)) this.warmupChange(id, signal).catch(() => {});
14042
14085
  for (const id of prevIds) if (!newIds.has(id)) {
14043
14086
  this.teardownEntity(`change:${id}`);
14044
- for (const key of this._statuses.keys()) if (key.startsWith(`${id}:`)) this._statuses.delete(key);
14045
- for (const key of this._instructions.keys()) if (key.startsWith(`${id}:`)) this._instructions.delete(key);
14046
- for (const key of this._applyInstructions.keys()) if (key.startsWith(`${id}:`)) this._applyInstructions.delete(key);
14087
+ for (const key of this._statuses.keys()) if (key.startsWith(`${id}:`)) {
14088
+ this._statuses.delete(key);
14089
+ this._streamReady.delete(`change:${id}:status:${key.slice(id.length + 1)}`);
14090
+ }
14091
+ for (const key of this._instructions.keys()) if (key.startsWith(`${id}:`)) {
14092
+ this._instructions.delete(key);
14093
+ const suffix = key.slice(id.length + 1);
14094
+ this._streamReady.delete(`change:${id}:instructions:${suffix}`);
14095
+ }
14096
+ for (const key of this._applyInstructions.keys()) if (key.startsWith(`${id}:`)) {
14097
+ this._applyInstructions.delete(key);
14098
+ this._streamReady.delete(`change:${id}:apply:${key.slice(id.length + 1)}`);
14099
+ }
14047
14100
  this._changeMetadata.delete(id);
14048
- for (const key of this._artifactOutputs.keys()) if (key.startsWith(`${id}:`)) this._artifactOutputs.delete(key);
14049
- for (const key of this._globArtifactFiles.keys()) if (key.startsWith(`${id}:`)) this._globArtifactFiles.delete(key);
14101
+ this._streamReady.delete(`change:${id}:metadata`);
14102
+ for (const key of this._artifactOutputs.keys()) if (key.startsWith(`${id}:`)) {
14103
+ this._artifactOutputs.delete(key);
14104
+ this._streamReady.delete(`change:${id}:output:${key.slice(id.length + 1)}`);
14105
+ }
14106
+ for (const key of this._globArtifactFiles.keys()) if (key.startsWith(`${id}:`)) {
14107
+ this._globArtifactFiles.delete(key);
14108
+ this._streamReady.delete(`change:${id}:glob:${key.slice(id.length + 1)}`);
14109
+ }
14110
+ this.clearStreamReadyByPrefix(`change:${id}:`);
14050
14111
  }
14051
14112
  prevIds = newIds;
14052
14113
  }
@@ -14060,11 +14121,14 @@ var OpsxKernel = class {
14060
14121
  this._entityControllers.delete(key);
14061
14122
  }
14062
14123
  }
14124
+ clearStreamReadyByPrefix(prefix) {
14125
+ for (const key of this._streamReady.keys()) if (key.startsWith(prefix)) this._streamReady.delete(key);
14126
+ }
14063
14127
  async fetchSchemas() {
14064
- await touchOpsxProjectDeps$1(this.projectDir);
14128
+ await touchOpsxProjectDeps(this.projectDir);
14065
14129
  const result = await this.cliExecutor.schemas();
14066
14130
  if (!result.success) throw new Error(result.stderr || `openspec schemas failed (exit ${result.exitCode ?? "null"})`);
14067
- return parseCliJson$1(result.stdout, arrayType(SchemaInfoSchema), "openspec schemas");
14131
+ return parseCliJson(result.stdout, arrayType(SchemaInfoSchema), "openspec schemas");
14068
14132
  }
14069
14133
  async fetchChangeIds() {
14070
14134
  return reactiveReadDir(join$1(this.projectDir, "openspec", "changes"), {
@@ -14077,8 +14141,8 @@ var OpsxKernel = class {
14077
14141
  return reactiveReadFile(join$1(this.projectDir, "openspec", "config.yaml"));
14078
14142
  }
14079
14143
  async fetchStatus(changeId, schema$6) {
14080
- await touchOpsxProjectDeps$1(this.projectDir);
14081
- await touchOpsxChangeDeps$1(this.projectDir, changeId);
14144
+ await touchOpsxProjectDeps(this.projectDir);
14145
+ await touchOpsxChangeDeps(this.projectDir, changeId);
14082
14146
  const args = [
14083
14147
  "status",
14084
14148
  "--json",
@@ -14088,23 +14152,20 @@ var OpsxKernel = class {
14088
14152
  if (schema$6) args.push("--schema", schema$6);
14089
14153
  const result = await this.cliExecutor.execute(args);
14090
14154
  if (!result.success) throw new Error(result.stderr || `openspec status failed (exit ${result.exitCode ?? "null"})`);
14091
- const status = parseCliJson$1(result.stdout, ChangeStatusSchema, "openspec status");
14155
+ const status = parseCliJson(result.stdout, ChangeStatusSchema, "openspec status");
14092
14156
  const changeRelDir = `openspec/changes/${changeId}`;
14093
14157
  for (const artifact of status.artifacts) artifact.relativePath = `${changeRelDir}/${artifact.outputPath}`;
14094
14158
  return status;
14095
14159
  }
14096
14160
  async fetchStatusList() {
14161
+ await this.ensureChangeIds();
14097
14162
  const changeIds = this._changeIds.get();
14098
- return Promise.all(changeIds.map((id) => {
14099
- const key = `${id}:`;
14100
- const state = this._statuses.get(key);
14101
- if (state) return Promise.resolve(state.get());
14102
- return this.fetchStatus(id);
14103
- }));
14163
+ await Promise.all(changeIds.map((id) => this.ensureStatus(id)));
14164
+ return changeIds.map((id) => this.getStatus(id));
14104
14165
  }
14105
14166
  async fetchInstructions(changeId, artifact, schema$6) {
14106
- await touchOpsxProjectDeps$1(this.projectDir);
14107
- await touchOpsxChangeDeps$1(this.projectDir, changeId);
14167
+ await touchOpsxProjectDeps(this.projectDir);
14168
+ await touchOpsxChangeDeps(this.projectDir, changeId);
14108
14169
  const args = [
14109
14170
  "instructions",
14110
14171
  artifact,
@@ -14115,11 +14176,11 @@ var OpsxKernel = class {
14115
14176
  if (schema$6) args.push("--schema", schema$6);
14116
14177
  const result = await this.cliExecutor.execute(args);
14117
14178
  if (!result.success) throw new Error(result.stderr || `openspec instructions failed (exit ${result.exitCode ?? "null"})`);
14118
- return parseCliJson$1(result.stdout, ArtifactInstructionsSchema, "openspec instructions");
14179
+ return parseCliJson(result.stdout, ArtifactInstructionsSchema, "openspec instructions");
14119
14180
  }
14120
14181
  async fetchApplyInstructions(changeId, schema$6) {
14121
- await touchOpsxProjectDeps$1(this.projectDir);
14122
- await touchOpsxChangeDeps$1(this.projectDir, changeId);
14182
+ await touchOpsxProjectDeps(this.projectDir);
14183
+ await touchOpsxChangeDeps(this.projectDir, changeId);
14123
14184
  const args = [
14124
14185
  "instructions",
14125
14186
  "apply",
@@ -14130,37 +14191,41 @@ var OpsxKernel = class {
14130
14191
  if (schema$6) args.push("--schema", schema$6);
14131
14192
  const result = await this.cliExecutor.execute(args);
14132
14193
  if (!result.success) throw new Error(result.stderr || `openspec instructions apply failed (exit ${result.exitCode ?? "null"})`);
14133
- return parseCliJson$1(result.stdout, ApplyInstructionsSchema, "openspec instructions apply");
14194
+ return parseCliJson(result.stdout, ApplyInstructionsSchema, "openspec instructions apply");
14134
14195
  }
14135
14196
  async fetchSchemaResolution(name) {
14136
- await touchOpsxProjectDeps$1(this.projectDir);
14197
+ await touchOpsxProjectDeps(this.projectDir);
14137
14198
  const result = await this.cliExecutor.schemaWhich(name);
14138
14199
  if (!result.success) throw new Error(result.stderr || `openspec schema which failed (exit ${result.exitCode ?? "null"})`);
14139
- return parseCliJson$1(result.stdout, SchemaResolutionSchema, "openspec schema which");
14200
+ return parseCliJson(result.stdout, SchemaResolutionSchema, "openspec schema which");
14140
14201
  }
14141
14202
  async fetchSchemaDetail(name) {
14142
- await touchOpsxProjectDeps$1(this.projectDir);
14143
- const schemaPath = join$1((await this.fetchSchemaResolution(name)).path, "schema.yaml");
14203
+ await touchOpsxProjectDeps(this.projectDir);
14204
+ await this.ensureSchemaResolution(name);
14205
+ const schemaPath = join$1(this.getSchemaResolution(name).path, "schema.yaml");
14144
14206
  const content = await reactiveReadFile(schemaPath);
14145
14207
  if (!content) throw new Error(`schema.yaml not found at ${schemaPath}`);
14146
14208
  return parseSchemaYamlInline(content);
14147
14209
  }
14148
14210
  async fetchSchemaFiles(name) {
14149
- await touchOpsxProjectDeps$1(this.projectDir);
14150
- return readEntriesUnderRoot$1((await this.fetchSchemaResolution(name)).path);
14211
+ await touchOpsxProjectDeps(this.projectDir);
14212
+ await this.ensureSchemaResolution(name);
14213
+ return readEntriesUnderRoot(this.getSchemaResolution(name).path);
14151
14214
  }
14152
14215
  async fetchSchemaYaml(name) {
14153
- await touchOpsxProjectDeps$1(this.projectDir);
14154
- return reactiveReadFile(join$1((await this.fetchSchemaResolution(name)).path, "schema.yaml"));
14216
+ await touchOpsxProjectDeps(this.projectDir);
14217
+ await this.ensureSchemaResolution(name);
14218
+ return reactiveReadFile(join$1(this.getSchemaResolution(name).path, "schema.yaml"));
14155
14219
  }
14156
14220
  async fetchTemplates(schema$6) {
14157
- await touchOpsxProjectDeps$1(this.projectDir);
14221
+ await touchOpsxProjectDeps(this.projectDir);
14158
14222
  const result = await this.cliExecutor.templates(schema$6);
14159
14223
  if (!result.success) throw new Error(result.stderr || `openspec templates failed (exit ${result.exitCode ?? "null"})`);
14160
- return parseCliJson$1(result.stdout, TemplatesSchema, "openspec templates");
14224
+ return parseCliJson(result.stdout, TemplatesSchema, "openspec templates");
14161
14225
  }
14162
14226
  async fetchTemplateContents(schema$6) {
14163
- const templates = await this.fetchTemplates(schema$6);
14227
+ await this.ensureTemplates(schema$6);
14228
+ const templates = this.getTemplates(schema$6);
14164
14229
  const entries = await Promise.all(Object.entries(templates).map(async ([artifactId, info]) => {
14165
14230
  return [artifactId, {
14166
14231
  content: await reactiveReadFile(info.path),
@@ -14176,88 +14241,72 @@ var OpsxKernel = class {
14176
14241
  async fetchArtifactOutput(changeId, outputPath) {
14177
14242
  return reactiveReadFile(join$1(this.projectDir, "openspec", "changes", changeId, outputPath));
14178
14243
  }
14179
- /**
14180
- * Ensure a per-change status stream exists. If not yet warmed up,
14181
- * creates the state and starts a stream lazily.
14182
- */
14183
- ensureStatus(changeId, schema$6) {
14244
+ async ensureSchemas() {
14245
+ await this.startStreamOnce("global:schemas", this._schemas, () => this.fetchSchemas(), this.controller.signal);
14246
+ }
14247
+ async ensureChangeIds() {
14248
+ await this.startStreamOnce("global:change-ids", this._changeIds, () => this.fetchChangeIds(), this.controller.signal);
14249
+ }
14250
+ async ensureProjectConfig() {
14251
+ await this.startStreamOnce("global:project-config", this._projectConfig, () => this.fetchProjectConfig(), this.controller.signal);
14252
+ }
14253
+ async ensureStatusList() {
14254
+ await this.startStreamOnce("global:status-list", this._statusList, () => this.fetchStatusList(), this.controller.signal);
14255
+ }
14256
+ async ensureStatus(changeId, schema$6) {
14184
14257
  const key = `${changeId}:${schema$6 ?? ""}`;
14185
- if (!this._statuses.has(key)) {
14186
- this._statuses.set(key, new ReactiveState(null));
14187
- this.startStream(this._statuses.get(key), () => this.fetchStatus(changeId, schema$6), this.controller.signal);
14188
- }
14258
+ if (!this._statuses.has(key)) this._statuses.set(key, new ReactiveState(null));
14259
+ await this.startStreamOnce(`change:${changeId}:status:${schema$6 ?? ""}`, this._statuses.get(key), () => this.fetchStatus(changeId, schema$6), this.controller.signal);
14189
14260
  }
14190
- ensureInstructions(changeId, artifact, schema$6) {
14261
+ async ensureInstructions(changeId, artifact, schema$6) {
14191
14262
  const key = `${changeId}:${artifact}:${schema$6 ?? ""}`;
14192
- if (!this._instructions.has(key)) {
14193
- this._instructions.set(key, new ReactiveState(null));
14194
- this.startStream(this._instructions.get(key), () => this.fetchInstructions(changeId, artifact, schema$6), this.controller.signal);
14195
- }
14263
+ if (!this._instructions.has(key)) this._instructions.set(key, new ReactiveState(null));
14264
+ await this.startStreamOnce(`change:${changeId}:instructions:${artifact}:${schema$6 ?? ""}`, this._instructions.get(key), () => this.fetchInstructions(changeId, artifact, schema$6), this.controller.signal);
14196
14265
  }
14197
- ensureApplyInstructions(changeId, schema$6) {
14266
+ async ensureApplyInstructions(changeId, schema$6) {
14198
14267
  const key = `${changeId}:${schema$6 ?? ""}`;
14199
- if (!this._applyInstructions.has(key)) {
14200
- this._applyInstructions.set(key, new ReactiveState(null));
14201
- this.startStream(this._applyInstructions.get(key), () => this.fetchApplyInstructions(changeId, schema$6), this.controller.signal);
14202
- }
14268
+ if (!this._applyInstructions.has(key)) this._applyInstructions.set(key, new ReactiveState(null));
14269
+ await this.startStreamOnce(`change:${changeId}:apply:${schema$6 ?? ""}`, this._applyInstructions.get(key), () => this.fetchApplyInstructions(changeId, schema$6), this.controller.signal);
14203
14270
  }
14204
- ensureArtifactOutput(changeId, outputPath) {
14271
+ async ensureArtifactOutput(changeId, outputPath) {
14205
14272
  const key = `${changeId}:${outputPath}`;
14206
- if (!this._artifactOutputs.has(key)) {
14207
- this._artifactOutputs.set(key, new ReactiveState(null));
14208
- this.startStream(this._artifactOutputs.get(key), () => this.fetchArtifactOutput(changeId, outputPath), this.controller.signal);
14209
- }
14273
+ if (!this._artifactOutputs.has(key)) this._artifactOutputs.set(key, new ReactiveState(null));
14274
+ await this.startStreamOnce(`change:${changeId}:output:${outputPath}`, this._artifactOutputs.get(key), () => this.fetchArtifactOutput(changeId, outputPath), this.controller.signal);
14210
14275
  }
14211
- ensureGlobArtifactFiles(changeId, outputPath) {
14276
+ async ensureGlobArtifactFiles(changeId, outputPath) {
14212
14277
  const key = `${changeId}:${outputPath}`;
14213
- if (!this._globArtifactFiles.has(key)) {
14214
- this._globArtifactFiles.set(key, new ReactiveState([]));
14215
- this.startStream(this._globArtifactFiles.get(key), () => readGlobArtifactFiles$1(this.projectDir, changeId, outputPath), this.controller.signal);
14216
- }
14278
+ if (!this._globArtifactFiles.has(key)) this._globArtifactFiles.set(key, new ReactiveState([]));
14279
+ await this.startStreamOnce(`change:${changeId}:glob:${outputPath}`, this._globArtifactFiles.get(key), () => readGlobArtifactFiles(this.projectDir, changeId, outputPath), this.controller.signal);
14217
14280
  }
14218
- ensureSchemaResolution(name) {
14219
- if (!this._schemaResolutions.has(name)) {
14220
- this._schemaResolutions.set(name, new ReactiveState(null));
14221
- this.startStream(this._schemaResolutions.get(name), () => this.fetchSchemaResolution(name), this.controller.signal);
14222
- }
14281
+ async ensureSchemaResolution(name) {
14282
+ if (!this._schemaResolutions.has(name)) this._schemaResolutions.set(name, new ReactiveState(null));
14283
+ await this.startStreamOnce(`schema:${name}:resolution`, this._schemaResolutions.get(name), () => this.fetchSchemaResolution(name), this.controller.signal);
14223
14284
  }
14224
- ensureSchemaDetail(name) {
14225
- if (!this._schemaDetails.has(name)) {
14226
- this._schemaDetails.set(name, new ReactiveState(null));
14227
- this.startStream(this._schemaDetails.get(name), () => this.fetchSchemaDetail(name), this.controller.signal);
14228
- }
14285
+ async ensureSchemaDetail(name) {
14286
+ if (!this._schemaDetails.has(name)) this._schemaDetails.set(name, new ReactiveState(null));
14287
+ await this.startStreamOnce(`schema:${name}:detail`, this._schemaDetails.get(name), () => this.fetchSchemaDetail(name), this.controller.signal);
14229
14288
  }
14230
- ensureSchemaFiles(name) {
14231
- if (!this._schemaFiles.has(name)) {
14232
- this._schemaFiles.set(name, new ReactiveState([]));
14233
- this.startStream(this._schemaFiles.get(name), () => this.fetchSchemaFiles(name), this.controller.signal);
14234
- }
14289
+ async ensureSchemaFiles(name) {
14290
+ if (!this._schemaFiles.has(name)) this._schemaFiles.set(name, new ReactiveState([]));
14291
+ await this.startStreamOnce(`schema:${name}:files`, this._schemaFiles.get(name), () => this.fetchSchemaFiles(name), this.controller.signal);
14235
14292
  }
14236
- ensureSchemaYaml(name) {
14237
- if (!this._schemaYamls.has(name)) {
14238
- this._schemaYamls.set(name, new ReactiveState(null));
14239
- this.startStream(this._schemaYamls.get(name), () => this.fetchSchemaYaml(name), this.controller.signal);
14240
- }
14293
+ async ensureSchemaYaml(name) {
14294
+ if (!this._schemaYamls.has(name)) this._schemaYamls.set(name, new ReactiveState(null));
14295
+ await this.startStreamOnce(`schema:${name}:yaml`, this._schemaYamls.get(name), () => this.fetchSchemaYaml(name), this.controller.signal);
14241
14296
  }
14242
- ensureTemplates(schema$6) {
14297
+ async ensureTemplates(schema$6) {
14243
14298
  const key = schema$6 ?? "";
14244
- if (!this._templates.has(key)) {
14245
- this._templates.set(key, new ReactiveState({}));
14246
- this.startStream(this._templates.get(key), () => this.fetchTemplates(schema$6), this.controller.signal);
14247
- }
14299
+ if (!this._templates.has(key)) this._templates.set(key, new ReactiveState({}));
14300
+ await this.startStreamOnce(`schema:${key}:templates`, this._templates.get(key), () => this.fetchTemplates(schema$6), this.controller.signal);
14248
14301
  }
14249
- ensureTemplateContents(schema$6) {
14302
+ async ensureTemplateContents(schema$6) {
14250
14303
  const key = schema$6 ?? "";
14251
- if (!this._templateContents.has(key)) {
14252
- this._templateContents.set(key, new ReactiveState({}));
14253
- this.startStream(this._templateContents.get(key), () => this.fetchTemplateContents(schema$6), this.controller.signal);
14254
- }
14304
+ if (!this._templateContents.has(key)) this._templateContents.set(key, new ReactiveState({}));
14305
+ await this.startStreamOnce(`schema:${key}:template-contents`, this._templateContents.get(key), () => this.fetchTemplateContents(schema$6), this.controller.signal);
14255
14306
  }
14256
- ensureChangeMetadata(changeId) {
14257
- if (!this._changeMetadata.has(changeId)) {
14258
- this._changeMetadata.set(changeId, new ReactiveState(null));
14259
- this.startStream(this._changeMetadata.get(changeId), () => this.fetchChangeMetadata(changeId), this.controller.signal);
14260
- }
14307
+ async ensureChangeMetadata(changeId) {
14308
+ if (!this._changeMetadata.has(changeId)) this._changeMetadata.set(changeId, new ReactiveState(null));
14309
+ await this.startStreamOnce(`change:${changeId}:metadata`, this._changeMetadata.get(changeId), () => this.fetchChangeMetadata(changeId), this.controller.signal);
14261
14310
  }
14262
14311
  combineSignals(a, b) {
14263
14312
  const ctrl = new AbortController();
@@ -14271,7 +14320,7 @@ var OpsxKernel = class {
14271
14320
  return ctrl.signal;
14272
14321
  }
14273
14322
  };
14274
- const SchemaYamlArtifactSchema$1 = objectType({
14323
+ const SchemaYamlArtifactSchema = objectType({
14275
14324
  id: stringType(),
14276
14325
  generates: stringType(),
14277
14326
  description: stringType().optional(),
@@ -14279,11 +14328,11 @@ const SchemaYamlArtifactSchema$1 = objectType({
14279
14328
  instruction: stringType().optional(),
14280
14329
  requires: arrayType(stringType()).optional()
14281
14330
  });
14282
- const SchemaYamlSchema$1 = objectType({
14331
+ const SchemaYamlSchema = objectType({
14283
14332
  name: stringType(),
14284
14333
  version: unionType([stringType(), numberType()]).optional(),
14285
14334
  description: stringType().optional(),
14286
- artifacts: arrayType(SchemaYamlArtifactSchema$1),
14335
+ artifacts: arrayType(SchemaYamlArtifactSchema),
14287
14336
  apply: objectType({
14288
14337
  requires: arrayType(stringType()).optional(),
14289
14338
  tracks: stringType().optional(),
@@ -14291,8 +14340,8 @@ const SchemaYamlSchema$1 = objectType({
14291
14340
  }).optional()
14292
14341
  });
14293
14342
  function parseSchemaYamlInline(content) {
14294
- const raw$1 = (0, import_dist$1.parse)(content);
14295
- const parsed = SchemaYamlSchema$1.safeParse(raw$1);
14343
+ const raw$1 = (0, import_dist.parse)(content);
14344
+ const parsed = SchemaYamlSchema.safeParse(raw$1);
14296
14345
  if (!parsed.success) throw new Error(`Invalid schema.yaml: ${parsed.error.message}`);
14297
14346
  const { artifacts, apply, name, description, version } = parsed.data;
14298
14347
  const detail = {
@@ -14324,6 +14373,7 @@ const PtyPlatformSchema = enumType([
14324
14373
  "macos",
14325
14374
  "common"
14326
14375
  ]);
14376
+ const CloseCallbackUrlSchema = unionType([stringType(), recordType(stringType())]);
14327
14377
  const PtySessionInfoSchema = objectType({
14328
14378
  id: stringType().min(1),
14329
14379
  title: stringType(),
@@ -14331,7 +14381,9 @@ const PtySessionInfoSchema = objectType({
14331
14381
  args: arrayType(stringType()),
14332
14382
  platform: PtyPlatformSchema,
14333
14383
  isExited: booleanType(),
14334
- exitCode: numberType().int().nullable()
14384
+ exitCode: numberType().int().nullable(),
14385
+ closeTip: stringType().optional(),
14386
+ closeCallbackUrl: CloseCallbackUrlSchema.optional()
14335
14387
  });
14336
14388
  const PtyCreateMessageSchema = objectType({
14337
14389
  type: literalType("create"),
@@ -14339,7 +14391,9 @@ const PtyCreateMessageSchema = objectType({
14339
14391
  cols: PositiveInt.optional(),
14340
14392
  rows: PositiveInt.optional(),
14341
14393
  command: stringType().min(1).optional(),
14342
- args: arrayType(stringType()).optional()
14394
+ args: arrayType(stringType()).optional(),
14395
+ closeTip: stringType().optional(),
14396
+ closeCallbackUrl: CloseCallbackUrlSchema.optional()
14343
14397
  });
14344
14398
  const PtyInputMessageSchema = objectType({
14345
14399
  type: literalType("input"),
@@ -16999,12 +17053,12 @@ function createMiddlewareFactory() {
16999
17053
  * @internal
17000
17054
  * Please note, `trpc-openapi` uses this function.
17001
17055
  */
17002
- function createInputMiddleware(parse$5) {
17056
+ function createInputMiddleware(parse$4) {
17003
17057
  const inputMiddleware = async function inputValidatorMiddleware(opts) {
17004
17058
  let parsedInput;
17005
17059
  const rawInput = await opts.getRawInput();
17006
17060
  try {
17007
- parsedInput = await parse$5(rawInput);
17061
+ parsedInput = await parse$4(rawInput);
17008
17062
  } catch (cause) {
17009
17063
  throw new TRPCError({
17010
17064
  code: "BAD_REQUEST",
@@ -17020,12 +17074,12 @@ function createInputMiddleware(parse$5) {
17020
17074
  /**
17021
17075
  * @internal
17022
17076
  */
17023
- function createOutputMiddleware(parse$5) {
17077
+ function createOutputMiddleware(parse$4) {
17024
17078
  const outputMiddleware = async function outputValidatorMiddleware({ next }) {
17025
17079
  const result = await next();
17026
17080
  if (!result.ok) return result;
17027
17081
  try {
17028
- const data = await parse$5(result.data);
17082
+ const data = await parse$4(result.data);
17029
17083
  return (0, import_objectSpread2$2.default)((0, import_objectSpread2$2.default)({}, result), {}, { data });
17030
17084
  } catch (cause) {
17031
17085
  throw new TRPCError({
@@ -20914,7 +20968,7 @@ var require_extension = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnpm
20914
20968
  * @return {Object} The parsed object
20915
20969
  * @public
20916
20970
  */
20917
- function parse$3(header) {
20971
+ function parse$2(header) {
20918
20972
  const offers = Object.create(null);
20919
20973
  let params = Object.create(null);
20920
20974
  let mustUnescape = false;
@@ -21029,7 +21083,7 @@ var require_extension = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnpm
21029
21083
  }
21030
21084
  module.exports = {
21031
21085
  format: format$2,
21032
- parse: parse$3
21086
+ parse: parse$2
21033
21087
  };
21034
21088
  }) });
21035
21089
 
@@ -21050,7 +21104,7 @@ var require_websocket = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnpm
21050
21104
  const { isBlob } = require_validation();
21051
21105
  const { BINARY_TYPES, EMPTY_BUFFER, GUID: GUID$1, kForOnEventAttribute, kListener, kStatusCode, kWebSocket: kWebSocket$1, NOOP } = require_constants();
21052
21106
  const { EventTarget: { addEventListener: addEventListener$1, removeEventListener } } = require_event_target();
21053
- const { format: format$1, parse: parse$2 } = require_extension();
21107
+ const { format: format$1, parse: parse$1 } = require_extension();
21054
21108
  const { toBuffer } = require_buffer_util();
21055
21109
  const closeTimeout = 30 * 1e3;
21056
21110
  const kAborted = Symbol("kAborted");
@@ -21713,7 +21767,7 @@ var require_websocket = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnpm
21713
21767
  }
21714
21768
  let extensions;
21715
21769
  try {
21716
- extensions = parse$2(secWebSocketExtensions);
21770
+ extensions = parse$1(secWebSocketExtensions);
21717
21771
  } catch (err) {
21718
21772
  abortHandshake$1(websocket, socket, "Invalid Sec-WebSocket-Extensions header");
21719
21773
  return;
@@ -22127,7 +22181,7 @@ var require_subprotocol = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pn
22127
22181
  * @return {Set} The subprotocol names
22128
22182
  * @public
22129
22183
  */
22130
- function parse$1(header) {
22184
+ function parse(header) {
22131
22185
  const protocols = /* @__PURE__ */ new Set();
22132
22186
  let start = -1;
22133
22187
  let end = -1;
@@ -22153,7 +22207,7 @@ var require_subprotocol = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pn
22153
22207
  protocols.add(protocol);
22154
22208
  return protocols;
22155
22209
  }
22156
- module.exports = { parse: parse$1 };
22210
+ module.exports = { parse };
22157
22211
  }) });
22158
22212
 
22159
22213
  //#endregion
@@ -22599,6 +22653,8 @@ var PtySession = class extends EventEmitter {
22599
22653
  command;
22600
22654
  args;
22601
22655
  platform;
22656
+ closeTip;
22657
+ closeCallbackUrl;
22602
22658
  createdAt;
22603
22659
  process;
22604
22660
  titleInterval = null;
@@ -22622,6 +22678,8 @@ var PtySession = class extends EventEmitter {
22622
22678
  this.command = resolvedCommand.command;
22623
22679
  this.args = resolvedCommand.args;
22624
22680
  this.platform = opts.platform;
22681
+ this.closeTip = opts.closeTip;
22682
+ this.closeCallbackUrl = opts.closeCallbackUrl;
22625
22683
  this.maxBufferLines = opts.scrollback ?? DEFAULT_SCROLLBACK;
22626
22684
  this.maxBufferBytes = opts.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES;
22627
22685
  this.process = pty.spawn(this.command, this.args, {
@@ -22702,6 +22760,8 @@ var PtySession = class extends EventEmitter {
22702
22760
  platform: this.platform,
22703
22761
  isExited: this.isExited,
22704
22762
  exitCode: this.exitCode,
22763
+ closeTip: this.closeTip,
22764
+ closeCallbackUrl: this.closeCallbackUrl,
22705
22765
  createdAt: this.createdAt
22706
22766
  };
22707
22767
  }
@@ -22721,6 +22781,8 @@ var PtyManager = class {
22721
22781
  rows: opts.rows,
22722
22782
  command: opts.command,
22723
22783
  args: opts.args,
22784
+ closeTip: opts.closeTip,
22785
+ closeCallbackUrl: opts.closeCallbackUrl,
22724
22786
  cwd: this.defaultCwd,
22725
22787
  scrollback: opts.scrollback,
22726
22788
  maxBufferBytes: opts.maxBufferBytes,
@@ -22825,11 +22887,14 @@ function createPtyWebSocketHandler(ptyManager) {
22825
22887
  switch (msg.type) {
22826
22888
  case "create":
22827
22889
  try {
22890
+ const createMessage = msg;
22828
22891
  const session = ptyManager.create({
22829
22892
  cols: msg.cols,
22830
22893
  rows: msg.rows,
22831
22894
  command: msg.command,
22832
- args: msg.args
22895
+ args: msg.args,
22896
+ closeTip: createMessage.closeTip,
22897
+ closeCallbackUrl: createMessage.closeCallbackUrl
22833
22898
  });
22834
22899
  send({
22835
22900
  type: "created",
@@ -22885,7 +22950,9 @@ function createPtyWebSocketHandler(ptyManager) {
22885
22950
  args: s.args,
22886
22951
  platform: s.platform,
22887
22952
  isExited: s.isExited,
22888
- exitCode: s.exitCode
22953
+ exitCode: s.exitCode,
22954
+ closeTip: s.closeTip,
22955
+ closeCallbackUrl: s.closeCallbackUrl
22889
22956
  }))
22890
22957
  });
22891
22958
  break;
@@ -23210,54 +23277,6 @@ function createCliStreamObservable(startStream) {
23210
23277
  });
23211
23278
  }
23212
23279
 
23213
- //#endregion
23214
- //#region ../server/src/opsx-schema.ts
23215
- var import_dist = require_dist();
23216
- const SchemaYamlArtifactSchema = objectType({
23217
- id: stringType(),
23218
- generates: stringType(),
23219
- description: stringType().optional(),
23220
- template: stringType().optional(),
23221
- instruction: stringType().optional(),
23222
- requires: arrayType(stringType()).optional()
23223
- });
23224
- const SchemaYamlSchema = objectType({
23225
- name: stringType(),
23226
- version: unionType([stringType(), numberType()]).optional(),
23227
- description: stringType().optional(),
23228
- artifacts: arrayType(SchemaYamlArtifactSchema),
23229
- apply: objectType({
23230
- requires: arrayType(stringType()).optional(),
23231
- tracks: stringType().optional(),
23232
- instruction: stringType().optional()
23233
- }).optional()
23234
- });
23235
- function parseSchemaYaml(content) {
23236
- const raw$1 = (0, import_dist.parse)(content);
23237
- const parsed = SchemaYamlSchema.safeParse(raw$1);
23238
- if (!parsed.success) throw new Error(`Invalid schema.yaml: ${parsed.error.message}`);
23239
- const { artifacts, apply, name, description, version } = parsed.data;
23240
- const detail = {
23241
- name,
23242
- description,
23243
- version,
23244
- artifacts: artifacts.map((artifact) => ({
23245
- id: artifact.id,
23246
- outputPath: artifact.generates,
23247
- description: artifact.description,
23248
- template: artifact.template,
23249
- instruction: artifact.instruction,
23250
- requires: artifact.requires ?? []
23251
- })),
23252
- applyRequires: apply?.requires ?? [],
23253
- applyTracks: apply?.tracks,
23254
- applyInstruction: apply?.instruction
23255
- };
23256
- const validated = SchemaDetailSchema.safeParse(detail);
23257
- if (!validated.success) throw new Error(`Invalid schema detail: ${validated.error.message}`);
23258
- return validated.data;
23259
- }
23260
-
23261
23280
  //#endregion
23262
23281
  //#region ../server/src/reactive-kv.ts
23263
23282
  /**
@@ -23385,20 +23404,6 @@ function requireChangeId(changeId) {
23385
23404
  function ensureEditableSource(source, label) {
23386
23405
  if (source === "package") throw new Error(`${label} is read-only (package source)`);
23387
23406
  }
23388
- function parseCliJson(raw$1, schema$6, label) {
23389
- const trimmed = raw$1.trim();
23390
- if (!trimmed) throw new Error(`${label} returned empty output`);
23391
- let parsed;
23392
- try {
23393
- parsed = JSON.parse(trimmed);
23394
- } catch (err) {
23395
- const message = err instanceof Error ? err.message : String(err);
23396
- throw new Error(`${label} returned invalid JSON: ${message}`);
23397
- }
23398
- const result = schema$6.safeParse(parsed);
23399
- if (!result.success) throw new Error(`${label} returned unexpected JSON: ${result.error.message}`);
23400
- return result.data;
23401
- }
23402
23407
  function resolveEntryPath(root, entryPath) {
23403
23408
  const normalizedRoot = resolve$1(root);
23404
23409
  const resolvedPath = resolve$1(normalizedRoot, entryPath);
@@ -23406,153 +23411,62 @@ function resolveEntryPath(root, entryPath) {
23406
23411
  if (resolvedPath !== normalizedRoot && !resolvedPath.startsWith(rootPrefix)) throw new Error("Invalid path: outside schema root");
23407
23412
  return resolvedPath;
23408
23413
  }
23409
- function toRelativePath(root, absolutePath) {
23410
- return relative$1(root, absolutePath).split(sep).join("/");
23411
- }
23412
- async function readEntriesUnderRoot(root) {
23413
- if (!(await reactiveStat(root))?.isDirectory) return [];
23414
- const collectEntries = async (dir) => {
23415
- const names = await reactiveReadDir(dir, { includeHidden: false });
23416
- const entries = [];
23417
- for (const name of names) {
23418
- const fullPath = join$1(dir, name);
23419
- const statInfo = await reactiveStat(fullPath);
23420
- if (!statInfo) continue;
23421
- const relativePath = toRelativePath(root, fullPath);
23422
- if (statInfo.isDirectory) {
23423
- entries.push({
23424
- path: relativePath,
23425
- type: "directory"
23426
- });
23427
- entries.push(...await collectEntries(fullPath));
23428
- } else {
23429
- const content = await reactiveReadFile(fullPath);
23430
- const size = content ? Buffer.byteLength(content, "utf-8") : void 0;
23431
- entries.push({
23432
- path: relativePath,
23433
- type: "file",
23434
- content: content ?? void 0,
23435
- size
23436
- });
23437
- }
23438
- }
23439
- return entries;
23440
- };
23441
- return collectEntries(root);
23442
- }
23443
- async function touchOpsxProjectDeps(projectDir) {
23444
- const openspecDir = join$1(projectDir, "openspec");
23445
- await reactiveReadFile(join$1(openspecDir, "config.yaml"));
23446
- const schemaRoot = join$1(openspecDir, "schemas");
23447
- const schemaDirs = await reactiveReadDir(schemaRoot, {
23448
- directoriesOnly: true,
23449
- includeHidden: true
23450
- });
23451
- await Promise.all(schemaDirs.map((name) => reactiveReadFile(join$1(schemaRoot, name, "schema.yaml"))));
23452
- await reactiveReadDir(join$1(openspecDir, "changes"), {
23453
- directoriesOnly: true,
23454
- includeHidden: true,
23455
- exclude: ["archive"]
23456
- });
23457
- }
23458
- async function touchOpsxChangeDeps(projectDir, changeId) {
23459
- const changeDir = join$1(projectDir, "openspec", "changes", changeId);
23460
- await reactiveReadDir(changeDir, { includeHidden: true });
23461
- await reactiveReadFile(join$1(changeDir, ".openspec.yaml"));
23462
- }
23463
- async function readGlobArtifactFiles(projectDir, changeId, outputPath) {
23464
- return (await readEntriesUnderRoot(join$1(projectDir, "openspec", "changes", changeId))).filter((entry) => entry.type === "file" && matchesGlob(entry.path, outputPath)).map((entry) => ({
23465
- path: entry.path,
23466
- type: "file",
23467
- content: entry.content ?? ""
23468
- }));
23469
- }
23470
23414
  async function fetchOpsxStatus(ctx, input) {
23471
23415
  const changeId = requireChangeId(input.change);
23472
- await touchOpsxProjectDeps(ctx.projectDir);
23473
- await touchOpsxChangeDeps(ctx.projectDir, changeId);
23474
- const args = [
23475
- "status",
23476
- "--json",
23477
- "--change",
23478
- changeId
23479
- ];
23480
- if (input.schema) args.push("--schema", input.schema);
23481
- const result = await ctx.cliExecutor.execute(args);
23482
- if (!result.success) throw new Error(result.stderr || `openspec status failed (exit ${result.exitCode ?? "null"})`);
23483
- const status = parseCliJson(result.stdout, ChangeStatusSchema, "openspec status");
23484
- const changeRelDir = `openspec/changes/${changeId}`;
23485
- for (const artifact of status.artifacts) artifact.relativePath = `${changeRelDir}/${artifact.outputPath}`;
23486
- return status;
23416
+ await ctx.kernel.waitForWarmup();
23417
+ await ctx.kernel.ensureStatus(changeId, input.schema);
23418
+ return ctx.kernel.getStatus(changeId, input.schema);
23487
23419
  }
23488
23420
  async function fetchOpsxStatusList(ctx) {
23489
- const changeIds = await reactiveReadDir(join$1(ctx.projectDir, "openspec", "changes"), {
23490
- directoriesOnly: true,
23491
- includeHidden: false,
23492
- exclude: ["archive"]
23493
- });
23494
- return await Promise.all(changeIds.map((changeId) => fetchOpsxStatus(ctx, { change: changeId })));
23421
+ await ctx.kernel.waitForWarmup();
23422
+ await ctx.kernel.ensureStatusList();
23423
+ return ctx.kernel.getStatusList();
23495
23424
  }
23496
23425
  async function fetchOpsxInstructions(ctx, input) {
23497
23426
  const changeId = requireChangeId(input.change);
23498
- await touchOpsxProjectDeps(ctx.projectDir);
23499
- await touchOpsxChangeDeps(ctx.projectDir, changeId);
23500
- const args = [
23501
- "instructions",
23502
- input.artifact,
23503
- "--json",
23504
- "--change",
23505
- changeId
23506
- ];
23507
- if (input.schema) args.push("--schema", input.schema);
23508
- const result = await ctx.cliExecutor.execute(args);
23509
- if (!result.success) throw new Error(result.stderr || `openspec instructions failed (exit ${result.exitCode ?? "null"})`);
23510
- return parseCliJson(result.stdout, ArtifactInstructionsSchema, "openspec instructions");
23427
+ await ctx.kernel.waitForWarmup();
23428
+ await ctx.kernel.ensureInstructions(changeId, input.artifact, input.schema);
23429
+ return ctx.kernel.getInstructions(changeId, input.artifact, input.schema);
23511
23430
  }
23512
23431
  async function fetchOpsxApplyInstructions(ctx, input) {
23513
23432
  const changeId = requireChangeId(input.change);
23514
- await touchOpsxProjectDeps(ctx.projectDir);
23515
- await touchOpsxChangeDeps(ctx.projectDir, changeId);
23516
- const args = [
23517
- "instructions",
23518
- "apply",
23519
- "--json",
23520
- "--change",
23521
- changeId
23522
- ];
23523
- if (input.schema) args.push("--schema", input.schema);
23524
- const result = await ctx.cliExecutor.execute(args);
23525
- if (!result.success) throw new Error(result.stderr || `openspec instructions apply failed (exit ${result.exitCode ?? "null"})`);
23526
- return parseCliJson(result.stdout, ApplyInstructionsSchema, "openspec instructions apply");
23433
+ await ctx.kernel.waitForWarmup();
23434
+ await ctx.kernel.ensureApplyInstructions(changeId, input.schema);
23435
+ return ctx.kernel.getApplyInstructions(changeId, input.schema);
23527
23436
  }
23528
- async function fetchOpsxSchemas(ctx) {
23529
- await touchOpsxProjectDeps(ctx.projectDir);
23530
- const result = await ctx.cliExecutor.schemas();
23531
- if (!result.success) throw new Error(result.stderr || `openspec schemas failed (exit ${result.exitCode ?? "null"})`);
23532
- return parseCliJson(result.stdout, arrayType(SchemaInfoSchema), "openspec schemas");
23437
+ async function fetchOpsxConfigBundle(ctx) {
23438
+ await ctx.kernel.ensureSchemas();
23439
+ const schemas$1 = ctx.kernel.getSchemas();
23440
+ for (const schema$6 of schemas$1) {
23441
+ ctx.kernel.ensureSchemaDetail(schema$6.name).catch(() => {});
23442
+ ctx.kernel.ensureSchemaResolution(schema$6.name).catch(() => {});
23443
+ }
23444
+ const schemaDetails = {};
23445
+ const schemaResolutions = {};
23446
+ for (const schema$6 of schemas$1) {
23447
+ schemaDetails[schema$6.name] = ctx.kernel.peekSchemaDetail(schema$6.name);
23448
+ schemaResolutions[schema$6.name] = ctx.kernel.peekSchemaResolution(schema$6.name);
23449
+ }
23450
+ return {
23451
+ schemas: schemas$1,
23452
+ schemaDetails,
23453
+ schemaResolutions
23454
+ };
23533
23455
  }
23534
23456
  async function fetchOpsxSchemaResolution(ctx, name) {
23535
- await touchOpsxProjectDeps(ctx.projectDir);
23536
- const result = await ctx.cliExecutor.schemaWhich(name);
23537
- if (!result.success) throw new Error(result.stderr || `openspec schema which failed (exit ${result.exitCode ?? "null"})`);
23538
- return parseCliJson(result.stdout, SchemaResolutionSchema, "openspec schema which");
23457
+ await ctx.kernel.waitForWarmup();
23458
+ await ctx.kernel.ensureSchemaResolution(name);
23459
+ return ctx.kernel.getSchemaResolution(name);
23539
23460
  }
23540
23461
  async function fetchOpsxTemplates(ctx, schema$6) {
23541
- await touchOpsxProjectDeps(ctx.projectDir);
23542
- const result = await ctx.cliExecutor.templates(schema$6);
23543
- if (!result.success) throw new Error(result.stderr || `openspec templates failed (exit ${result.exitCode ?? "null"})`);
23544
- return parseCliJson(result.stdout, TemplatesSchema, "openspec templates");
23462
+ await ctx.kernel.waitForWarmup();
23463
+ await ctx.kernel.ensureTemplates(schema$6);
23464
+ return ctx.kernel.getTemplates(schema$6);
23545
23465
  }
23546
23466
  async function fetchOpsxTemplateContents(ctx, schema$6) {
23547
- const templates = await fetchOpsxTemplates(ctx, schema$6);
23548
- const entries = await Promise.all(Object.entries(templates).map(async ([artifactId, info]) => {
23549
- return [artifactId, {
23550
- content: await reactiveReadFile(info.path),
23551
- path: info.path,
23552
- source: info.source
23553
- }];
23554
- }));
23555
- return Object.fromEntries(entries);
23467
+ await ctx.kernel.waitForWarmup();
23468
+ await ctx.kernel.ensureTemplateContents(schema$6);
23469
+ return ctx.kernel.getTemplateContents(schema$6);
23556
23470
  }
23557
23471
  /**
23558
23472
  * Spec router - spec CRUD operations
@@ -23942,11 +23856,11 @@ const opsxRouter = router({
23942
23856
  })).subscription(({ ctx, input }) => {
23943
23857
  return createReactiveSubscription(() => fetchOpsxApplyInstructions(ctx, input));
23944
23858
  }),
23945
- schemas: publicProcedure.query(async ({ ctx }) => {
23946
- return fetchOpsxSchemas(ctx);
23859
+ configBundle: publicProcedure.query(async ({ ctx }) => {
23860
+ return fetchOpsxConfigBundle(ctx);
23947
23861
  }),
23948
- subscribeSchemas: publicProcedure.subscription(({ ctx }) => {
23949
- return createReactiveSubscription(() => fetchOpsxSchemas(ctx));
23862
+ subscribeConfigBundle: publicProcedure.subscription(({ ctx }) => {
23863
+ return createReactiveSubscription(() => fetchOpsxConfigBundle(ctx));
23950
23864
  }),
23951
23865
  templates: publicProcedure.input(objectType({ schema: stringType().optional() }).optional()).query(async ({ ctx, input }) => {
23952
23866
  return fetchOpsxTemplates(ctx, input?.schema);
@@ -23960,53 +23874,34 @@ const opsxRouter = router({
23960
23874
  subscribeTemplateContents: publicProcedure.input(objectType({ schema: stringType().optional() }).optional()).subscription(({ ctx, input }) => {
23961
23875
  return createReactiveSubscription(() => fetchOpsxTemplateContents(ctx, input?.schema));
23962
23876
  }),
23963
- schemaResolution: publicProcedure.input(objectType({ name: stringType() })).query(async ({ ctx, input }) => {
23964
- return fetchOpsxSchemaResolution(ctx, input.name);
23965
- }),
23966
- subscribeSchemaResolution: publicProcedure.input(objectType({ name: stringType() })).subscription(({ ctx, input }) => {
23967
- return createReactiveSubscription(() => fetchOpsxSchemaResolution(ctx, input.name));
23968
- }),
23969
- schemaDetail: publicProcedure.input(objectType({ name: stringType() })).query(async ({ ctx, input }) => {
23970
- await touchOpsxProjectDeps(ctx.projectDir);
23971
- const schemaPath = join$1((await fetchOpsxSchemaResolution(ctx, input.name)).path, "schema.yaml");
23972
- const content = await reactiveReadFile(schemaPath);
23973
- if (!content) throw new Error(`schema.yaml not found at ${schemaPath}`);
23974
- return parseSchemaYaml(content);
23975
- }),
23976
- subscribeSchemaDetail: publicProcedure.input(objectType({ name: stringType() })).subscription(({ ctx, input }) => {
23977
- return createReactiveSubscription(async () => {
23978
- await touchOpsxProjectDeps(ctx.projectDir);
23979
- const schemaPath = join$1((await fetchOpsxSchemaResolution(ctx, input.name)).path, "schema.yaml");
23980
- const content = await reactiveReadFile(schemaPath);
23981
- if (!content) throw new Error(`schema.yaml not found at ${schemaPath}`);
23982
- return parseSchemaYaml(content);
23983
- });
23984
- }),
23985
23877
  schemaFiles: publicProcedure.input(objectType({ name: stringType() })).query(async ({ ctx, input }) => {
23986
- await touchOpsxProjectDeps(ctx.projectDir);
23987
- return readEntriesUnderRoot((await fetchOpsxSchemaResolution(ctx, input.name)).path);
23878
+ await ctx.kernel.waitForWarmup();
23879
+ await ctx.kernel.ensureSchemaFiles(input.name);
23880
+ return ctx.kernel.getSchemaFiles(input.name);
23988
23881
  }),
23989
23882
  subscribeSchemaFiles: publicProcedure.input(objectType({ name: stringType() })).subscription(({ ctx, input }) => {
23990
23883
  return createReactiveSubscription(async () => {
23991
- await touchOpsxProjectDeps(ctx.projectDir);
23992
- return readEntriesUnderRoot((await fetchOpsxSchemaResolution(ctx, input.name)).path);
23884
+ await ctx.kernel.waitForWarmup();
23885
+ await ctx.kernel.ensureSchemaFiles(input.name);
23886
+ return ctx.kernel.getSchemaFiles(input.name);
23993
23887
  });
23994
23888
  }),
23995
23889
  schemaYaml: publicProcedure.input(objectType({ name: stringType() })).query(async ({ ctx, input }) => {
23996
- await touchOpsxProjectDeps(ctx.projectDir);
23997
- return reactiveReadFile(join$1((await fetchOpsxSchemaResolution(ctx, input.name)).path, "schema.yaml"));
23890
+ await ctx.kernel.waitForWarmup();
23891
+ await ctx.kernel.ensureSchemaYaml(input.name);
23892
+ return ctx.kernel.getSchemaYaml(input.name);
23998
23893
  }),
23999
23894
  subscribeSchemaYaml: publicProcedure.input(objectType({ name: stringType() })).subscription(({ ctx, input }) => {
24000
23895
  return createReactiveSubscription(async () => {
24001
- await touchOpsxProjectDeps(ctx.projectDir);
24002
- return reactiveReadFile(join$1((await fetchOpsxSchemaResolution(ctx, input.name)).path, "schema.yaml"));
23896
+ await ctx.kernel.waitForWarmup();
23897
+ await ctx.kernel.ensureSchemaYaml(input.name);
23898
+ return ctx.kernel.getSchemaYaml(input.name);
24003
23899
  });
24004
23900
  }),
24005
23901
  writeSchemaYaml: publicProcedure.input(objectType({
24006
23902
  name: stringType(),
24007
23903
  content: stringType()
24008
23904
  })).mutation(async ({ ctx, input }) => {
24009
- await touchOpsxProjectDeps(ctx.projectDir);
24010
23905
  const resolution = await fetchOpsxSchemaResolution(ctx, input.name);
24011
23906
  ensureEditableSource(resolution.source, "schema.yaml");
24012
23907
  const schemaPath = join$1(resolution.path, "schema.yaml");
@@ -24019,7 +23914,6 @@ const opsxRouter = router({
24019
23914
  path: stringType(),
24020
23915
  content: stringType()
24021
23916
  })).mutation(async ({ ctx, input }) => {
24022
- await touchOpsxProjectDeps(ctx.projectDir);
24023
23917
  const resolution = await fetchOpsxSchemaResolution(ctx, input.schema);
24024
23918
  ensureEditableSource(resolution.source, "schema file");
24025
23919
  if (!input.path.trim()) throw new Error("path is required");
@@ -24033,7 +23927,6 @@ const opsxRouter = router({
24033
23927
  path: stringType(),
24034
23928
  content: stringType().optional()
24035
23929
  })).mutation(async ({ ctx, input }) => {
24036
- await touchOpsxProjectDeps(ctx.projectDir);
24037
23930
  const resolution = await fetchOpsxSchemaResolution(ctx, input.schema);
24038
23931
  ensureEditableSource(resolution.source, "schema file");
24039
23932
  if (!input.path.trim()) throw new Error("path is required");
@@ -24046,7 +23939,6 @@ const opsxRouter = router({
24046
23939
  schema: stringType(),
24047
23940
  path: stringType()
24048
23941
  })).mutation(async ({ ctx, input }) => {
24049
- await touchOpsxProjectDeps(ctx.projectDir);
24050
23942
  const resolution = await fetchOpsxSchemaResolution(ctx, input.schema);
24051
23943
  ensureEditableSource(resolution.source, "schema directory");
24052
23944
  if (!input.path.trim()) throw new Error("path is required");
@@ -24057,7 +23949,6 @@ const opsxRouter = router({
24057
23949
  schema: stringType(),
24058
23950
  path: stringType()
24059
23951
  })).mutation(async ({ ctx, input }) => {
24060
- await touchOpsxProjectDeps(ctx.projectDir);
24061
23952
  const resolution = await fetchOpsxSchemaResolution(ctx, input.schema);
24062
23953
  ensureEditableSource(resolution.source, "schema entry");
24063
23954
  if (!input.path.trim()) throw new Error("path is required");
@@ -24073,26 +23964,18 @@ const opsxRouter = router({
24073
23964
  schema: stringType(),
24074
23965
  artifactId: stringType()
24075
23966
  })).query(async ({ ctx, input }) => {
24076
- const info = (await fetchOpsxTemplates(ctx, input.schema))[input.artifactId];
23967
+ const info = (await fetchOpsxTemplateContents(ctx, input.schema))[input.artifactId];
24077
23968
  if (!info) throw new Error(`Template not found for ${input.schema}:${input.artifactId}`);
24078
- return {
24079
- content: await reactiveReadFile(info.path),
24080
- path: info.path,
24081
- source: info.source
24082
- };
23969
+ return info;
24083
23970
  }),
24084
23971
  subscribeTemplateContent: publicProcedure.input(objectType({
24085
23972
  schema: stringType(),
24086
23973
  artifactId: stringType()
24087
23974
  })).subscription(({ ctx, input }) => {
24088
23975
  return createReactiveSubscription(async () => {
24089
- const info = (await fetchOpsxTemplates(ctx, input.schema))[input.artifactId];
23976
+ const info = (await fetchOpsxTemplateContents(ctx, input.schema))[input.artifactId];
24090
23977
  if (!info) throw new Error(`Template not found for ${input.schema}:${input.artifactId}`);
24091
- return {
24092
- content: await reactiveReadFile(info.path),
24093
- path: info.path,
24094
- source: info.source
24095
- };
23978
+ return info;
24096
23979
  });
24097
23980
  }),
24098
23981
  writeTemplateContent: publicProcedure.input(objectType({
@@ -24108,7 +23991,6 @@ const opsxRouter = router({
24108
23991
  return { success: true };
24109
23992
  }),
24110
23993
  deleteSchema: publicProcedure.input(objectType({ name: stringType() })).mutation(async ({ ctx, input }) => {
24111
- await touchOpsxProjectDeps(ctx.projectDir);
24112
23994
  const resolution = await fetchOpsxSchemaResolution(ctx, input.name);
24113
23995
  ensureEditableSource(resolution.source, "schema");
24114
23996
  await rm(resolution.path, {
@@ -24118,11 +24000,15 @@ const opsxRouter = router({
24118
24000
  return { success: true };
24119
24001
  }),
24120
24002
  projectConfig: publicProcedure.query(async ({ ctx }) => {
24121
- return reactiveReadFile(join$1(ctx.projectDir, "openspec", "config.yaml"));
24003
+ await ctx.kernel.waitForWarmup();
24004
+ await ctx.kernel.ensureProjectConfig();
24005
+ return ctx.kernel.getProjectConfig();
24122
24006
  }),
24123
24007
  subscribeProjectConfig: publicProcedure.subscription(({ ctx }) => {
24124
24008
  return createReactiveSubscription(async () => {
24125
- return reactiveReadFile(join$1(ctx.projectDir, "openspec", "config.yaml"));
24009
+ await ctx.kernel.waitForWarmup();
24010
+ await ctx.kernel.ensureProjectConfig();
24011
+ return ctx.kernel.getProjectConfig();
24126
24012
  });
24127
24013
  }),
24128
24014
  writeProjectConfig: publicProcedure.input(objectType({ content: stringType() })).mutation(async ({ ctx, input }) => {
@@ -24132,55 +24018,63 @@ const opsxRouter = router({
24132
24018
  return { success: true };
24133
24019
  }),
24134
24020
  listChanges: publicProcedure.query(async ({ ctx }) => {
24135
- return reactiveReadDir(join$1(ctx.projectDir, "openspec", "changes"), {
24136
- directoriesOnly: true,
24137
- exclude: ["archive"],
24138
- includeHidden: false
24139
- });
24021
+ await ctx.kernel.waitForWarmup();
24022
+ await ctx.kernel.ensureChangeIds();
24023
+ return ctx.kernel.getChangeIds();
24140
24024
  }),
24141
24025
  subscribeChanges: publicProcedure.subscription(({ ctx }) => {
24142
24026
  return createReactiveSubscription(async () => {
24143
- return reactiveReadDir(join$1(ctx.projectDir, "openspec", "changes"), {
24144
- directoriesOnly: true,
24145
- exclude: ["archive"],
24146
- includeHidden: false
24147
- });
24027
+ await ctx.kernel.waitForWarmup();
24028
+ await ctx.kernel.ensureChangeIds();
24029
+ return ctx.kernel.getChangeIds();
24148
24030
  });
24149
24031
  }),
24150
24032
  changeMetadata: publicProcedure.input(objectType({ changeId: stringType() })).query(async ({ ctx, input }) => {
24151
- return reactiveReadFile(join$1(ctx.projectDir, "openspec", "changes", input.changeId, ".openspec.yaml"));
24033
+ await ctx.kernel.waitForWarmup();
24034
+ await ctx.kernel.ensureChangeMetadata(input.changeId);
24035
+ return ctx.kernel.getChangeMetadata(input.changeId);
24152
24036
  }),
24153
24037
  subscribeChangeMetadata: publicProcedure.input(objectType({ changeId: stringType() })).subscription(({ ctx, input }) => {
24154
24038
  return createReactiveSubscription(async () => {
24155
- return reactiveReadFile(join$1(ctx.projectDir, "openspec", "changes", input.changeId, ".openspec.yaml"));
24039
+ await ctx.kernel.waitForWarmup();
24040
+ await ctx.kernel.ensureChangeMetadata(input.changeId);
24041
+ return ctx.kernel.getChangeMetadata(input.changeId);
24156
24042
  });
24157
24043
  }),
24158
24044
  readArtifactOutput: publicProcedure.input(objectType({
24159
24045
  changeId: stringType(),
24160
24046
  outputPath: stringType()
24161
24047
  })).query(async ({ ctx, input }) => {
24162
- return reactiveReadFile(join$1(ctx.projectDir, "openspec", "changes", input.changeId, input.outputPath));
24048
+ await ctx.kernel.waitForWarmup();
24049
+ await ctx.kernel.ensureArtifactOutput(input.changeId, input.outputPath);
24050
+ return ctx.kernel.getArtifactOutput(input.changeId, input.outputPath);
24163
24051
  }),
24164
24052
  subscribeArtifactOutput: publicProcedure.input(objectType({
24165
24053
  changeId: stringType(),
24166
24054
  outputPath: stringType()
24167
24055
  })).subscription(({ ctx, input }) => {
24168
24056
  return createReactiveSubscription(async () => {
24169
- return reactiveReadFile(join$1(ctx.projectDir, "openspec", "changes", input.changeId, input.outputPath));
24057
+ await ctx.kernel.waitForWarmup();
24058
+ await ctx.kernel.ensureArtifactOutput(input.changeId, input.outputPath);
24059
+ return ctx.kernel.getArtifactOutput(input.changeId, input.outputPath);
24170
24060
  });
24171
24061
  }),
24172
24062
  readGlobArtifactFiles: publicProcedure.input(objectType({
24173
24063
  changeId: stringType(),
24174
24064
  outputPath: stringType()
24175
24065
  })).query(async ({ ctx, input }) => {
24176
- return readGlobArtifactFiles(ctx.projectDir, input.changeId, input.outputPath);
24066
+ await ctx.kernel.waitForWarmup();
24067
+ await ctx.kernel.ensureGlobArtifactFiles(input.changeId, input.outputPath);
24068
+ return ctx.kernel.getGlobArtifactFiles(input.changeId, input.outputPath);
24177
24069
  }),
24178
24070
  subscribeGlobArtifactFiles: publicProcedure.input(objectType({
24179
24071
  changeId: stringType(),
24180
24072
  outputPath: stringType()
24181
24073
  })).subscription(({ ctx, input }) => {
24182
24074
  return createReactiveSubscription(async () => {
24183
- return readGlobArtifactFiles(ctx.projectDir, input.changeId, input.outputPath);
24075
+ await ctx.kernel.waitForWarmup();
24076
+ await ctx.kernel.ensureGlobArtifactFiles(input.changeId, input.outputPath);
24077
+ return ctx.kernel.getGlobArtifactFiles(input.changeId, input.outputPath);
24184
24078
  });
24185
24079
  }),
24186
24080
  writeArtifactOutput: publicProcedure.input(objectType({