@openspecui/core 2.3.0 → 2.3.4

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.d.mts CHANGED
@@ -306,11 +306,11 @@ declare const DeltaSpecSchema: z.ZodObject<{
306
306
  /** Raw markdown content of the delta spec */
307
307
  content: z.ZodString;
308
308
  }, "strip", z.ZodTypeAny, {
309
- specId: string;
310
309
  content: string;
311
- }, {
312
310
  specId: string;
311
+ }, {
313
312
  content: string;
313
+ specId: string;
314
314
  }>;
315
315
  type DeltaSpec = z.infer<typeof DeltaSpecSchema>;
316
316
  /**
@@ -488,11 +488,11 @@ declare const ChangeSchema: z.ZodObject<{
488
488
  /** Raw markdown content of the delta spec */
489
489
  content: z.ZodString;
490
490
  }, "strip", z.ZodTypeAny, {
491
- specId: string;
492
491
  content: string;
493
- }, {
494
492
  specId: string;
493
+ }, {
495
494
  content: string;
495
+ specId: string;
496
496
  }>, "many">>;
497
497
  /** Optional metadata */
498
498
  metadata: z.ZodOptional<z.ZodObject<{
@@ -549,8 +549,8 @@ declare const ChangeSchema: z.ZodObject<{
549
549
  } | undefined;
550
550
  design?: string | undefined;
551
551
  deltaSpecs?: {
552
- specId: string;
553
552
  content: string;
553
+ specId: string;
554
554
  }[] | undefined;
555
555
  }, {
556
556
  id: string;
@@ -596,8 +596,8 @@ declare const ChangeSchema: z.ZodObject<{
596
596
  } | undefined;
597
597
  design?: string | undefined;
598
598
  deltaSpecs?: {
599
- specId: string;
600
599
  content: string;
600
+ specId: string;
601
601
  }[] | undefined;
602
602
  }>;
603
603
  type Change = z.infer<typeof ChangeSchema>;
@@ -803,8 +803,8 @@ declare class OpenSpecAdapter {
803
803
  } | undefined;
804
804
  design?: string | undefined;
805
805
  deltaSpecs?: {
806
- specId: string;
807
806
  content: string;
807
+ specId: string;
808
808
  }[] | undefined;
809
809
  }[];
810
810
  archivedCount: number;
package/dist/index.mjs CHANGED
@@ -1919,6 +1919,101 @@ function createFileChangeObservable(watcher) {
1919
1919
  } };
1920
1920
  }
1921
1921
 
1922
+ //#endregion
1923
+ //#region src/spawn-safe.ts
1924
+ function getSpawnErrorCode(err) {
1925
+ if (typeof err !== "object" || err === null || !("code" in err)) return;
1926
+ const code = err.code;
1927
+ return typeof code === "string" ? code : void 0;
1928
+ }
1929
+ function formatSpawnError(err) {
1930
+ const message = err instanceof Error ? err.message : String(err);
1931
+ const code = getSpawnErrorCode(err);
1932
+ return {
1933
+ code,
1934
+ message: `${message}${code ? ` (${code})` : ""}`
1935
+ };
1936
+ }
1937
+ function spawnSafe(command, args, options) {
1938
+ try {
1939
+ return {
1940
+ ok: true,
1941
+ child: spawn(command, [...args], options)
1942
+ };
1943
+ } catch (err) {
1944
+ return {
1945
+ ok: false,
1946
+ error: formatSpawnError(err)
1947
+ };
1948
+ }
1949
+ }
1950
+ function killChild(child) {
1951
+ try {
1952
+ child.kill();
1953
+ } catch {}
1954
+ }
1955
+ function runBufferedCommand(options) {
1956
+ return new Promise((resolve$1) => {
1957
+ const started = spawnSafe(options.command, options.args, {
1958
+ cwd: options.cwd,
1959
+ shell: false,
1960
+ env: options.env
1961
+ });
1962
+ if (!started.ok) {
1963
+ resolve$1({
1964
+ stdout: "",
1965
+ stderr: "",
1966
+ exitCode: null,
1967
+ timedOut: false,
1968
+ spawnError: started.error
1969
+ });
1970
+ return;
1971
+ }
1972
+ const { child } = started;
1973
+ let stdout = "";
1974
+ let stderr = "";
1975
+ let timedOut = false;
1976
+ let settled = false;
1977
+ let clearTimer = () => {};
1978
+ if (options.timeoutMs !== void 0) {
1979
+ const timer = setTimeout(() => {
1980
+ timedOut = true;
1981
+ killChild(child);
1982
+ }, options.timeoutMs);
1983
+ clearTimer = () => clearTimeout(timer);
1984
+ }
1985
+ const finish = (result) => {
1986
+ if (settled) return;
1987
+ settled = true;
1988
+ clearTimer();
1989
+ resolve$1(result);
1990
+ };
1991
+ child.stdout?.on("data", (data) => {
1992
+ stdout += data.toString();
1993
+ });
1994
+ child.stderr?.on("data", (data) => {
1995
+ stderr += data.toString();
1996
+ });
1997
+ child.on("error", (err) => {
1998
+ finish({
1999
+ stdout,
2000
+ stderr,
2001
+ exitCode: null,
2002
+ timedOut,
2003
+ spawnError: formatSpawnError(err)
2004
+ });
2005
+ });
2006
+ child.on("close", (exitCode) => {
2007
+ finish({
2008
+ stdout,
2009
+ stderr,
2010
+ exitCode,
2011
+ timedOut
2012
+ });
2013
+ });
2014
+ });
2015
+ }
2016
+
1922
2017
  //#endregion
1923
2018
  //#region src/config.ts
1924
2019
  const execAsync = promisify(exec);
@@ -2172,69 +2267,44 @@ function createCleanCliEnv(baseEnv = process.env) {
2172
2267
  }
2173
2268
  async function probeCliRunner(candidate, cwd, env) {
2174
2269
  const [cmd, ...cmdArgs] = candidate.commandParts;
2175
- return new Promise((resolve$1) => {
2176
- let stdout = "";
2177
- let stderr = "";
2178
- let timedOut = false;
2179
- const timer = setTimeout(() => {
2180
- timedOut = true;
2181
- child.kill();
2182
- }, CLI_PROBE_TIMEOUT_MS);
2183
- const child = spawn(cmd, [...cmdArgs, "--version"], {
2184
- cwd,
2185
- shell: false,
2186
- env
2187
- });
2188
- child.stdout?.on("data", (data) => {
2189
- stdout += data.toString();
2190
- });
2191
- child.stderr?.on("data", (data) => {
2192
- stderr += data.toString();
2193
- });
2194
- child.on("error", (err) => {
2195
- clearTimeout(timer);
2196
- const code = err.code;
2197
- const suffix = code ? ` (${code})` : "";
2198
- resolve$1({
2199
- source: candidate.source,
2200
- command: commandToString(candidate.commandParts),
2201
- success: false,
2202
- error: `${err.message}${suffix}`,
2203
- exitCode: null
2204
- });
2205
- });
2206
- child.on("close", (exitCode) => {
2207
- clearTimeout(timer);
2208
- if (timedOut) {
2209
- resolve$1({
2210
- source: candidate.source,
2211
- command: commandToString(candidate.commandParts),
2212
- success: false,
2213
- error: "CLI probe timed out",
2214
- exitCode
2215
- });
2216
- return;
2217
- }
2218
- if (exitCode === 0) {
2219
- const version = stdout.trim().split("\n")[0] || void 0;
2220
- resolve$1({
2221
- source: candidate.source,
2222
- command: commandToString(candidate.commandParts),
2223
- success: true,
2224
- version,
2225
- exitCode
2226
- });
2227
- return;
2228
- }
2229
- resolve$1({
2230
- source: candidate.source,
2231
- command: commandToString(candidate.commandParts),
2232
- success: false,
2233
- error: stderr.trim() || `Exit code ${exitCode ?? "null"}`,
2234
- exitCode
2235
- });
2236
- });
2270
+ const result = await runBufferedCommand({
2271
+ command: cmd,
2272
+ args: [...cmdArgs, "--version"],
2273
+ cwd,
2274
+ env,
2275
+ timeoutMs: CLI_PROBE_TIMEOUT_MS
2237
2276
  });
2277
+ if (result.timedOut) return {
2278
+ source: candidate.source,
2279
+ command: commandToString(candidate.commandParts),
2280
+ success: false,
2281
+ error: "CLI probe timed out",
2282
+ exitCode: result.exitCode
2283
+ };
2284
+ if (result.spawnError) return {
2285
+ source: candidate.source,
2286
+ command: commandToString(candidate.commandParts),
2287
+ success: false,
2288
+ error: result.spawnError.message,
2289
+ exitCode: null
2290
+ };
2291
+ if (result.exitCode === 0) {
2292
+ const version = result.stdout.trim().split("\n")[0] || void 0;
2293
+ return {
2294
+ source: candidate.source,
2295
+ command: commandToString(candidate.commandParts),
2296
+ success: true,
2297
+ version,
2298
+ exitCode: result.exitCode
2299
+ };
2300
+ }
2301
+ return {
2302
+ source: candidate.source,
2303
+ command: commandToString(candidate.commandParts),
2304
+ success: false,
2305
+ error: result.stderr.trim() || `Exit code ${result.exitCode ?? "null"}`,
2306
+ exitCode: result.exitCode
2307
+ };
2238
2308
  }
2239
2309
  async function resolveCliRunner(candidates, cwd, env) {
2240
2310
  const expandedCandidates = await expandCliRunnerCandidates(candidates, cwd, env);
@@ -2656,42 +2726,27 @@ var CliExecutor = class {
2656
2726
  async buildCommandArray(args) {
2657
2727
  return [...await this.configManager.getCliCommand(), ...args];
2658
2728
  }
2659
- runCommandOnce(fullCommand) {
2729
+ async runCommandOnce(fullCommand) {
2660
2730
  const [cmd, ...cmdArgs] = fullCommand;
2661
- return new Promise((resolve$1) => {
2662
- const child = spawn(cmd, cmdArgs, {
2663
- cwd: this.projectDir,
2664
- shell: false,
2665
- env: createCleanCliEnv()
2666
- });
2667
- let stdout = "";
2668
- let stderr = "";
2669
- child.stdout?.on("data", (data) => {
2670
- stdout += data.toString();
2671
- });
2672
- child.stderr?.on("data", (data) => {
2673
- stderr += data.toString();
2674
- });
2675
- child.on("close", (exitCode) => {
2676
- resolve$1({
2677
- success: exitCode === 0,
2678
- stdout,
2679
- stderr,
2680
- exitCode
2681
- });
2682
- });
2683
- child.on("error", (err) => {
2684
- const errorCode = err.code;
2685
- const errorMessage = err.message + (errorCode ? ` (${errorCode})` : "");
2686
- resolve$1({
2687
- success: false,
2688
- stdout,
2689
- stderr: stderr ? `${stderr}\n${errorMessage}` : errorMessage,
2690
- exitCode: null,
2691
- errorCode
2692
- });
2693
- });
2731
+ const result = await runBufferedCommand({
2732
+ command: cmd,
2733
+ args: cmdArgs,
2734
+ cwd: this.projectDir,
2735
+ env: createCleanCliEnv()
2694
2736
  });
2737
+ if (result.spawnError) return {
2738
+ success: false,
2739
+ stdout: result.stdout,
2740
+ stderr: result.stderr ? `${result.stderr}\n${result.spawnError.message}` : result.spawnError.message,
2741
+ exitCode: null,
2742
+ errorCode: result.spawnError.code
2743
+ };
2744
+ return {
2745
+ success: result.exitCode === 0,
2746
+ stdout: result.stdout,
2747
+ stderr: result.stderr,
2748
+ exitCode: result.exitCode
2749
+ };
2695
2750
  }
2696
2751
  async executeInternal(args, allowRetry) {
2697
2752
  let fullCommand;
@@ -2845,11 +2900,29 @@ var CliExecutor = class {
2845
2900
  data: fullCommand.join(" ")
2846
2901
  });
2847
2902
  const [cmd, ...cmdArgs] = fullCommand;
2848
- const child = spawn(cmd, cmdArgs, {
2903
+ const started = spawnSafe(cmd, cmdArgs, {
2849
2904
  cwd: this.projectDir,
2850
2905
  shell: false,
2851
2906
  env: createCleanCliEnv()
2852
2907
  });
2908
+ if (!started.ok) {
2909
+ const { code, message } = started.error;
2910
+ if (allowRetry && code === "ENOENT" && !cancelled) {
2911
+ this.configManager.invalidateResolvedCliRunner();
2912
+ start(false);
2913
+ return;
2914
+ }
2915
+ onEvent({
2916
+ type: "stderr",
2917
+ data: message
2918
+ });
2919
+ onEvent({
2920
+ type: "exit",
2921
+ exitCode: null
2922
+ });
2923
+ return;
2924
+ }
2925
+ const child = started.child;
2853
2926
  activeChild = child;
2854
2927
  child.stdout?.on("data", (data) => {
2855
2928
  onEvent({
@@ -2874,8 +2947,7 @@ var CliExecutor = class {
2874
2947
  child.on("error", (err) => {
2875
2948
  if (activeChild !== child) return;
2876
2949
  activeChild = null;
2877
- const code = err.code;
2878
- const message = err.message + (code ? ` (${code})` : "");
2950
+ const { code, message } = formatSpawnError(err);
2879
2951
  if (allowRetry && code === "ENOENT" && !cancelled) {
2880
2952
  this.configManager.invalidateResolvedCliRunner();
2881
2953
  start(false);
@@ -2960,11 +3032,23 @@ var CliExecutor = class {
2960
3032
  type: "command",
2961
3033
  data: command.join(" ")
2962
3034
  });
2963
- const child = spawn(cmd, cmdArgs, {
3035
+ const started = spawnSafe(cmd, cmdArgs, {
2964
3036
  cwd: this.projectDir,
2965
3037
  shell: false,
2966
3038
  env: createCleanCliEnv()
2967
3039
  });
3040
+ if (!started.ok) {
3041
+ onEvent({
3042
+ type: "stderr",
3043
+ data: started.error.message
3044
+ });
3045
+ onEvent({
3046
+ type: "exit",
3047
+ exitCode: null
3048
+ });
3049
+ return () => {};
3050
+ }
3051
+ const child = started.child;
2968
3052
  child.stdout?.on("data", (data) => {
2969
3053
  onEvent({
2970
3054
  type: "stdout",
@@ -2984,10 +3068,10 @@ var CliExecutor = class {
2984
3068
  });
2985
3069
  });
2986
3070
  child.on("error", (err) => {
2987
- const code = err.code;
3071
+ const { message } = formatSpawnError(err);
2988
3072
  onEvent({
2989
3073
  type: "stderr",
2990
- data: err.message + (code ? ` (${code})` : "")
3074
+ data: message
2991
3075
  });
2992
3076
  onEvent({
2993
3077
  type: "exit",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openspecui/core",
3
- "version": "2.3.0",
3
+ "version": "2.3.4",
4
4
  "description": "Core OpenSpec adapter and parser",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",