@openspecui/core 9.0.1 → 9.0.3

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 (54) hide show
  1. package/dist/{active-root-config-7fBdHM6Y.d.mts → active-root-config-CDH9K5lV.d.mts} +15 -15
  2. package/dist/active-root-config.d.mts +4 -4
  3. package/dist/app-daemon-control.d.mts +51 -51
  4. package/dist/{cli-projection-BaiM5tvA.d.mts → cli-projection-C1ZYzYMm.d.mts} +3 -3
  5. package/dist/cli-projection.d.mts +4 -4
  6. package/dist/{dashboard-summary-transport-CuNVcC0j.d.mts → dashboard-summary-transport-Bys0g-UT.d.mts} +4343 -4343
  7. package/dist/dashboard-summary-transport.d.mts +17 -17
  8. package/dist/hosted-app.d.mts +17 -17
  9. package/dist/hosted-contract.d.mts +17 -17
  10. package/dist/{index-BZWtHuI2.d.mts → index-C7jJcSdH.d.mts} +7 -7
  11. package/dist/index.d.mts +17 -17
  12. package/dist/index.mjs +130 -48
  13. package/dist/{local-download-profiles-BcWLAxXm.d.mts → local-download-profiles-CyAhZwxA.d.mts} +1 -1
  14. package/dist/local-download-profiles.d.mts +2 -2
  15. package/dist/local-download-profiles.mjs +1 -1
  16. package/dist/{notifications-BytLKOTa.d.mts → notifications-Be5ltQeN.d.mts} +3 -3
  17. package/dist/notifications.d.mts +2 -2
  18. package/dist/openspec-compat.d.mts +3 -3
  19. package/dist/openspec-compat.mjs +1 -1
  20. package/dist/{openspec-projection-D2l0gt1a.d.mts → openspec-projection-Bymnjuf9.d.mts} +1 -1
  21. package/dist/openspec-projection.d.mts +2 -2
  22. package/dist/{opsx-entity-DPNoe1RP.d.mts → opsx-entity-NFWGsreJ.d.mts} +2 -2
  23. package/dist/opsx-entity.d.mts +6 -6
  24. package/dist/{opsx-schema-detail-Cd5Av3ge.d.mts → opsx-schema-detail-ChaSoC8S.d.mts} +2 -2
  25. package/dist/opsx-schema-detail.d.mts +7 -7
  26. package/dist/{opsx-types-CwR1AXgQ.d.mts → opsx-types-C2lUEACZ.d.mts} +227 -227
  27. package/dist/planning-cli-projection.d.mts +17 -17
  28. package/dist/planning-cli-projection.mjs +1 -1
  29. package/dist/{schemas-_BT364v-.d.mts → schemas-BG7Tcs8J.d.mts} +132 -132
  30. package/dist/{sounds-CoSDUNQn.d.mts → sounds-DdPTMYMa.d.mts} +8 -8
  31. package/dist/sounds.d.mts +1 -1
  32. package/dist/spec-catalog.d.mts +17 -17
  33. package/dist/{store-mutation-protocol-C9xgZkNh.d.mts → store-mutation-protocol-DXeWtAvN.d.mts} +24 -24
  34. package/dist/store-mutation-protocol.d.mts +1 -1
  35. package/dist/{store-types-og5YxoDu.d.mts → store-types-X35XKl10.d.mts} +1 -1
  36. package/dist/store-types.d.mts +4 -4
  37. package/dist/task-progress.d.mts +5 -5
  38. package/dist/{terminal-audio-DLgCr6Km.d.mts → terminal-audio-Csuw114f.d.mts} +1 -1
  39. package/dist/terminal-audio.d.mts +2 -2
  40. package/dist/terminal-audio.mjs +1 -1
  41. package/dist/terminal-control.d.mts +2 -2
  42. package/dist/{terminal-invocation-OqCEd2gX.d.mts → terminal-invocation-C5AN93a9.d.mts} +82 -82
  43. package/dist/terminal-invocation.d.mts +1 -1
  44. package/dist/terminal-theme.mjs +1 -1
  45. package/dist/translation-language-pair.mjs +1 -1
  46. package/dist/{translator-CIptPzqy.d.mts → translator-4wvacuAX.d.mts} +77 -77
  47. package/dist/translator.d.mts +1 -1
  48. package/package.json +1 -1
  49. /package/dist/{local-download-profiles-BRsR1-kK.mjs → local-download-profiles-3I8AOUJj.mjs} +0 -0
  50. /package/dist/{openspec-compat-B246EQNW.mjs → openspec-compat-DidEO359.mjs} +0 -0
  51. /package/dist/{planning-cli-projection-DV22v3Xl.mjs → planning-cli-projection-BTkiQ7PG.mjs} +0 -0
  52. /package/dist/{terminal-audio-ELHVH24M.mjs → terminal-audio-CLEDFFpW.mjs} +0 -0
  53. /package/dist/{terminal-theme-C6BPfQ2G.mjs → terminal-theme-Bse1UdaX.mjs} +0 -0
  54. /package/dist/{translation-language-pair-CWLlH7Ab.mjs → translation-language-pair-BTfLQehX.mjs} +0 -0
package/dist/index.mjs CHANGED
@@ -16,12 +16,12 @@ import { a as DocumentTranslationDisplayModeSchema, c as TRANSLATION_CACHE_POLIC
16
16
  import { _ as customHashFromSoundId, a as CustomSoundHashSchema, b as soundIdFromCustomHash, c as CustomSoundMetadataSchema, f as LEGACY_SOUND_ID_MAP, g as SoundVolumeSchema, h as SoundIdSchema, i as CUSTOM_SOUND_ADD_VALUE, l as DEFAULT_BELL_SOUND_ID, m as SoundConfigIdSchema, n as BUILTIN_SOUND_OPTIONS, o as CustomSoundIdSchema, p as SILENT_SOUND_ID, r as BuiltinSoundIdSchema, s as CustomSoundMetadataFileSchema, t as BUILTIN_SOUND_IDS, u as DEFAULT_NOTIFICATION_SOUND_ID, v as getBuiltinSoundUrl, y as normalizeLegacySoundId } from "./sounds-cd9lIDxN.mjs";
17
17
  import { n as terminalNotificationEventToPublishInput, t as TerminalControlParser } from "./terminal-control-D893EEN_.mjs";
18
18
  import { a as NotificationPublishInputSchema, c as NotificationSoundSchema, h as groupNotifications, i as NotificationGroupKeySchema, l as NotificationSourceSchema, m as getNotificationGroupLabel, n as NOTIFICATION_SOUND_VALUES, o as NotificationRecordSchema, p as getNotificationGroupKey, r as NotificationActionSchema, s as NotificationSettingsSchema, t as NOTIFICATION_SOUND_OPTIONS, u as TerminalNotificationParser } from "./notifications-D6XlgL9b.mjs";
19
- import { n as TERMINAL_BELL_SOUND_VALUES, r as TerminalBellSoundSchema, t as TERMINAL_BELL_SOUND_OPTIONS } from "./terminal-audio-ELHVH24M.mjs";
20
- import { a as TERMINAL_THEME_VALUES, i as TERMINAL_THEME_MODE_VALUES, n as DEFAULT_TERMINAL_LIGHT_THEME, r as DEFAULT_TERMINAL_THEME_MODE, t as DEFAULT_TERMINAL_DARK_THEME } from "./terminal-theme-C6BPfQ2G.mjs";
21
- import { i as selectLocalDownloadGroup, n as buildLocalDownloadPlanFromRepositoryFiles, r as buildLocalDownloadPlanFromRuntimeProfileFiles, t as LOCAL_MODEL_PROFILE_DEFINITIONS } from "./local-download-profiles-BRsR1-kK.mjs";
22
- import { n as inferLocalDirectionalModelLanguagePair, t as checkLocalDirectionalModelLanguagePair } from "./translation-language-pair-CWLlH7Ab.mjs";
23
- import { C as SchemaResolutionSchema, D as isGlobPattern, E as TemplatesSchema, S as SchemaInfoSchema, T as TemplateContentSchema, _ as OpsxCliEvidenceSchema, a as PlanningCliProjectionDataSchema, b as SchemaArtifactSchema, c as ApplyInstructionsContextFilesSchema, d as ApplyTaskSchema, f as ArchiveInstructionsSchema, g as DependencyInfoSchema, h as ChangeStatusSchema, i as EnvironmentGlobalProjectionStateSchema, l as ApplyInstructionsProjectionSchema, m as ArtifactStatusSchema, n as EnvironmentGlobalFileProjectionStateSchema, o as PlanningCliProjectionSelectorSchema, p as ArtifactInstructionsSchema, r as EnvironmentGlobalProjectionDataSchema, s as PlanningCliProjectionStateSchema, t as EnvironmentGlobalFileProjectionDataSchema, u as ApplyInstructionsSchema, v as OpsxConfigBundleSchema, w as TemplateContentMapSchema, x as SchemaDetailSchema, y as OpsxStatusEvidenceSchema } from "./planning-cli-projection-DV22v3Xl.mjs";
24
- import { h as parseOpenSpecCliVersion, p as deriveOpenSpecCliCapabilities } from "./openspec-compat-B246EQNW.mjs";
19
+ import { h as parseOpenSpecCliVersion, p as deriveOpenSpecCliCapabilities, u as OPENSPEC_CLI_TARGET_SERIES } from "./openspec-compat-DidEO359.mjs";
20
+ import { n as TERMINAL_BELL_SOUND_VALUES, r as TerminalBellSoundSchema, t as TERMINAL_BELL_SOUND_OPTIONS } from "./terminal-audio-CLEDFFpW.mjs";
21
+ import { a as TERMINAL_THEME_VALUES, i as TERMINAL_THEME_MODE_VALUES, n as DEFAULT_TERMINAL_LIGHT_THEME, r as DEFAULT_TERMINAL_THEME_MODE, t as DEFAULT_TERMINAL_DARK_THEME } from "./terminal-theme-Bse1UdaX.mjs";
22
+ import { i as selectLocalDownloadGroup, n as buildLocalDownloadPlanFromRepositoryFiles, r as buildLocalDownloadPlanFromRuntimeProfileFiles, t as LOCAL_MODEL_PROFILE_DEFINITIONS } from "./local-download-profiles-3I8AOUJj.mjs";
23
+ import { n as inferLocalDirectionalModelLanguagePair, t as checkLocalDirectionalModelLanguagePair } from "./translation-language-pair-BTfLQehX.mjs";
24
+ import { C as SchemaResolutionSchema, D as isGlobPattern, E as TemplatesSchema, S as SchemaInfoSchema, T as TemplateContentSchema, _ as OpsxCliEvidenceSchema, a as PlanningCliProjectionDataSchema, b as SchemaArtifactSchema, c as ApplyInstructionsContextFilesSchema, d as ApplyTaskSchema, f as ArchiveInstructionsSchema, g as DependencyInfoSchema, h as ChangeStatusSchema, i as EnvironmentGlobalProjectionStateSchema, l as ApplyInstructionsProjectionSchema, m as ArtifactStatusSchema, n as EnvironmentGlobalFileProjectionStateSchema, o as PlanningCliProjectionSelectorSchema, p as ArtifactInstructionsSchema, r as EnvironmentGlobalProjectionDataSchema, s as PlanningCliProjectionStateSchema, t as EnvironmentGlobalFileProjectionDataSchema, u as ApplyInstructionsSchema, v as OpsxConfigBundleSchema, w as TemplateContentMapSchema, x as SchemaDetailSchema, y as OpsxStatusEvidenceSchema } from "./planning-cli-projection-BTkiQ7PG.mjs";
25
25
  import { a as OPSX_CORE_PROFILE_WORKFLOWS, c as OPSX_WORKFLOW_TO_SKILL_DIR, i as OPSX_COMMAND_CAPABLE_WORKFLOWS, l as isOpsxCoreWorkflowSelection, n as OPSX_ARTIFACT_INPUT_ACTIONS, o as OPSX_TEXT_INPUT_ACTIONS, r as OPSX_CHANGE_INPUT_ACTIONS, s as OPSX_WORKFLOW_LABELS, t as OPSX_ALL_WORKFLOWS } from "./opsx-workflows-BA-46T7_.mjs";
26
26
  import { a as DASHBOARD_METRIC_KEYS, c as DashboardSummaryProjectionSchema, i as DashboardSummaryProjectionStateSchema, l as DashboardTrendsProjectionSchema, n as DashboardSummaryInvalidationCauseSchema, o as DashboardGitSnapshotSchema, r as DashboardSummaryInvalidationSchema, s as DashboardOverviewSchema, t as DashboardSummaryIdentitySchema } from "./dashboard-summary-transport-Do8pzSES.mjs";
27
27
  import { a as StoreListResultSchema, n as StoreDoctorResultSchema, o as classifyStoreCliResult, s as toStoreFeatureResult } from "./store-types-C87SlrJ3.mjs";
@@ -38,7 +38,7 @@ import { createHash, randomBytes, randomUUID } from "node:crypto";
38
38
  import { access, lstat, mkdir as mkdir$1, open, readFile, readdir, realpath, rename, rm, stat, writeFile as writeFile$1 } from "node:fs/promises";
39
39
  import { basename, dirname as dirname$1, extname, isAbsolute, join as join$1, matchesGlob, posix, relative, resolve, sep, win32 } from "node:path";
40
40
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
41
- import { existsSync, lstatSync, readFileSync, realpathSync } from "node:fs";
41
+ import { existsSync, lstatSync, readFileSync, realpathSync, statSync } from "node:fs";
42
42
  import { AsyncLocalStorage } from "node:async_hooks";
43
43
  import { z } from "zod";
44
44
  import { EventEmitter } from "events";
@@ -2738,6 +2738,11 @@ function sanitizePersistedSettings(value, rules) {
2738
2738
  //#region src/child-process-tree.ts
2739
2739
  const execFileAsync$1 = promisify$1(execFile$1);
2740
2740
  const WINDOWS_PROCESS_TABLE_MAX_BUFFER = 16 * 1024 * 1024;
2741
+ /**
2742
+ * In-flight serialization for Win32_Process reads. Multiple tests reading the full
2743
+ * process table concurrently delays WMI settlement past their bounded timeouts.
2744
+ */
2745
+ let processTableReadInFlight = null;
2741
2746
  function hasChildExited(child) {
2742
2747
  return child.exitCode !== null || child.signalCode !== null;
2743
2748
  }
@@ -2751,21 +2756,29 @@ function isWindowsProcessRecord(value) {
2751
2756
  }
2752
2757
  /** Read the current Windows process table used for exact ancestry and root ownership checks. */
2753
2758
  async function readWindowsProcessTable() {
2754
- const { stdout } = await execFileAsync$1("powershell.exe", [
2755
- "-NoLogo",
2756
- "-NoProfile",
2757
- "-NonInteractive",
2758
- "-Command",
2759
- "[Console]::OutputEncoding = [Text.UTF8Encoding]::new($false); Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,ExecutablePath | ConvertTo-Json -Compress"
2760
- ], {
2761
- encoding: "utf8",
2762
- maxBuffer: WINDOWS_PROCESS_TABLE_MAX_BUFFER,
2763
- windowsHide: true
2764
- });
2765
- const json = stdout.trim();
2766
- if (json.length === 0) return [];
2767
- const parsed = JSON.parse(json);
2768
- return (Array.isArray(parsed) ? parsed : [parsed]).filter(isWindowsProcessRecord);
2759
+ if (processTableReadInFlight) return processTableReadInFlight;
2760
+ processTableReadInFlight = (async () => {
2761
+ const { stdout } = await execFileAsync$1("powershell.exe", [
2762
+ "-NoLogo",
2763
+ "-NoProfile",
2764
+ "-NonInteractive",
2765
+ "-Command",
2766
+ "[Console]::OutputEncoding = [Text.UTF8Encoding]::new($false); Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,ExecutablePath | ConvertTo-Json -Compress"
2767
+ ], {
2768
+ encoding: "utf8",
2769
+ maxBuffer: WINDOWS_PROCESS_TABLE_MAX_BUFFER,
2770
+ windowsHide: true
2771
+ });
2772
+ const json = stdout.trim();
2773
+ if (json.length === 0) return [];
2774
+ const parsed = JSON.parse(json);
2775
+ return (Array.isArray(parsed) ? parsed : [parsed]).filter(isWindowsProcessRecord);
2776
+ })();
2777
+ try {
2778
+ return await processTableReadInFlight;
2779
+ } finally {
2780
+ processTableReadInFlight = null;
2781
+ }
2769
2782
  }
2770
2783
  /** Terminate a Windows tree only when the root PID still owns the expected executable. */
2771
2784
  async function terminateWindowsProcessTreeByIdentity(rootPid, expectedExecutablePath) {
@@ -2808,12 +2821,16 @@ async function terminateChildProcessTree(child, signal = "SIGTERM") {
2808
2821
  //#endregion
2809
2822
  //#region src/command-invocation.ts
2810
2823
  /**
2811
- * Orthogonal intents (created 2026-08-09 Asia/Shanghai):
2824
+ * Orthogonal intents (updated 2026-08-28 Asia/Shanghai):
2812
2825
  * 1. Resolve caller-environment Windows commands to native argv-preserving executable boundaries.
2813
2826
  * 2. Project standard npm-style shims and explicit Node shebang launchers onto their real Node executable.
2814
2827
  * 3. Prefer native executables, route shell-sensitive pnpm through Corepack, and reject opaque command shims.
2828
+ * 4. Extract modern (`%dp0%`) and legacy (`%~dp0`) npm shim entries under hardened containment
2829
+ * that admits only real files inside the shim directory or its `.bin` parent.
2815
2830
  *
2816
2831
  * Original request (2026-08-04): "Make pnpm openspecui start and equivalent package scripts work on Windows."
2832
+ * Original request (2026-08-28, issue #258): "No available OpenSpec CLI runner." — npm ≥7 `cmd-shim`
2833
+ * references its entry through the `%dp0%` variable, which the legacy-only extractor missed.
2817
2834
  */
2818
2835
  const WINDOWS_NATIVE_EXTENSIONS = new Set([".com", ".exe"]);
2819
2836
  function isBareCommand(command$1) {
@@ -2837,7 +2854,7 @@ function findWindowsCommandCandidates(command$1, options) {
2837
2854
  windowsHide: true
2838
2855
  });
2839
2856
  if (result.error) throw result.error;
2840
- if (result.status !== 0) throw new Error(result.stderr.trim() || `Unable to resolve ${command$1} from PATH.`);
2857
+ if (result.status !== 0) throw Object.assign(new Error(result.stderr.trim() || `Unable to resolve ${command$1} from PATH.`), { code: "ENOENT" });
2841
2858
  return result.stdout.split(/\r?\n/).map((candidate) => candidate.trim()).filter(Boolean);
2842
2859
  }
2843
2860
  function tryFindWindowsCommandCandidates(command$1, options) {
@@ -2871,17 +2888,76 @@ function findNodeExecutable(commandShim, options) {
2871
2888
  if (process$1.release.name === "node" && extname(process$1.execPath).toLowerCase() === ".exe") return process$1.execPath;
2872
2889
  throw new Error(`Unable to resolve the Node executable required by ${commandShim}.`);
2873
2890
  }
2891
+ const NODE_COMMAND_SHIM_GUARD_PATTERN = /(?:node(?:\.exe)?|node_exe|npm_node_execpath|_prog)/i;
2892
+ /**
2893
+ * npm shim generations reference their entry relative to the shim directory through two shapes:
2894
+ * the legacy literal `%~dp0\path\entry.js` and the modern (cmd-shim v4+, npm ≥7) variable form
2895
+ * `SET dp0=%~dp0` … `"%dp0%\path\entry.js"`.
2896
+ */
2897
+ const NODE_COMMAND_SHIM_ENTRY_PATTERN = /%(?:~dp0|dp0%)([^"\r\n]*?\.(?:c|m)?js)/gi;
2898
+ /** Raw dp0-relative JavaScript entry references found in one npm-style command shim. */
2899
+ function extractNodeCommandShimEntryTokens(source) {
2900
+ const tokens = [];
2901
+ for (const match of source.matchAll(NODE_COMMAND_SHIM_ENTRY_PATTERN)) {
2902
+ const rawToken = match[1]?.trim() ?? "";
2903
+ if (rawToken.startsWith("\\\\") || rawToken.startsWith("//")) continue;
2904
+ const token = rawToken.replace(/^[/\\]+/, "");
2905
+ if (token) tokens.push(token);
2906
+ }
2907
+ return tokens;
2908
+ }
2909
+ function isContainableShimEntryToken(token, normalizedToken) {
2910
+ if (!token) return false;
2911
+ if (token.includes("\0")) return false;
2912
+ if (/^[a-zA-Z]:/.test(normalizedToken)) return false;
2913
+ if (token.startsWith("\\\\") || normalizedToken.startsWith("//")) return false;
2914
+ return !token.includes("%");
2915
+ }
2916
+ function isWithinDirectory(root, candidate) {
2917
+ const relativePath = relative(root, candidate);
2918
+ return relativePath !== "" && !relativePath.startsWith("..") && !isAbsolute(relativePath);
2919
+ }
2920
+ function resolveExistingShimEntry(commandShim, token) {
2921
+ const normalizedToken = token.replace(/\\/g, "/");
2922
+ if (!isContainableShimEntryToken(token, normalizedToken)) return null;
2923
+ const entry = resolve(dirname$1(commandShim), normalizedToken);
2924
+ let realEntry;
2925
+ let realShimDirectory;
2926
+ try {
2927
+ realEntry = realpathSync.native(entry);
2928
+ realShimDirectory = dirname$1(realpathSync.native(commandShim));
2929
+ } catch {
2930
+ return null;
2931
+ }
2932
+ let stats;
2933
+ try {
2934
+ stats = statSync(realEntry);
2935
+ } catch {
2936
+ return null;
2937
+ }
2938
+ if (!stats.isFile()) return null;
2939
+ const realShimParent = dirname$1(realShimDirectory);
2940
+ const withinShimDirectory = isWithinDirectory(realShimDirectory, realEntry);
2941
+ const withinDotBinParent = basename(realShimDirectory).toLowerCase() === ".bin" && isWithinDirectory(realShimParent, realEntry);
2942
+ if (!withinShimDirectory && !withinDotBinParent) return null;
2943
+ return realEntry;
2944
+ }
2945
+ /**
2946
+ * Resolve the JavaScript entry one standard npm-style Node command shim delegates to, or null
2947
+ * when no dp0-relative entry survives containment validation.
2948
+ */
2949
+ function resolveNodeCommandShimEntry(commandShim, source) {
2950
+ const tokens = extractNodeCommandShimEntryTokens(source);
2951
+ for (let index = tokens.length - 1; index >= 0; index -= 1) {
2952
+ const entry = resolveExistingShimEntry(commandShim, tokens[index] ?? "");
2953
+ if (entry) return entry;
2954
+ }
2955
+ return null;
2956
+ }
2874
2957
  function resolveNodeCommandShim(commandShim, args, options) {
2875
2958
  const source = readFileSync(commandShim, "utf8");
2876
- if (!/(?:node(?:\.exe)?|node_exe|npm_node_execpath|_prog)/i.test(source)) return null;
2877
- const entries = [];
2878
- for (const match of source.matchAll(/%~dp0([^"\r\n]*?\.(?:c|m)?js)/gi)) {
2879
- const relativeEntry = match[1]?.trim().replace(/^[\\/]+/, "");
2880
- if (!relativeEntry) continue;
2881
- const entry$1 = resolve(dirname$1(commandShim), relativeEntry);
2882
- if (existsSync(entry$1)) entries.push(entry$1);
2883
- }
2884
- const entry = entries.at(-1);
2959
+ if (!NODE_COMMAND_SHIM_GUARD_PATTERN.test(source)) return null;
2960
+ const entry = resolveNodeCommandShimEntry(commandShim, source);
2885
2961
  if (!entry) return null;
2886
2962
  return {
2887
2963
  command: findNodeExecutable(commandShim, options),
@@ -3173,7 +3249,7 @@ function runBufferedCommand(options) {
3173
3249
  //#endregion
3174
3250
  //#region src/config.ts
3175
3251
  /**
3176
- * Orthogonal intents (updated 2026-07-30 Asia/Shanghai):
3252
+ * Orthogonal intents (updated 2026-08-28 Asia/Shanghai):
3177
3253
  * 1. Define and persist project-scoped OpenSpecUI settings.
3178
3254
  * 2. Resolve, diagnose, cache, and explicitly invalidate the OpenSpec CLI runner.
3179
3255
  * 3. Prevent retired in-flight runner resolutions from reclaiming cache ownership.
@@ -3182,7 +3258,11 @@ function runBufferedCommand(options) {
3182
3258
  * extension-less script (issue #209 hotfix).
3183
3259
  * 6. Hide runner-probe subprocess console windows (`windowsHide`) so a console-less Windows daemon
3184
3260
  * never flashes a cmd window while resolving or sniffing the CLI runner.
3261
+ * 7. Pin auto-fallback runners to the supported CLI series and probe the global CLI through the
3262
+ * spawn-safe boundary so resolved `.cmd` shims execute instead of failing EINVAL (issue #258).
3185
3263
  *
3264
+ * Original request (2026-08-28, issue #258): "No available OpenSpec CLI runner." on Windows with an
3265
+ * in-range global npm CLI; the npx fallback resolved an out-of-range `@latest`.
3186
3266
  * Original request (2026-08-14): "在Windows平台上,执行命令总是会弹出cmd窗口,这个可否统一隐藏,你先调查一下原因"
3187
3267
  * Original request (2026-07-14): "openspec 1.6.0 已经放出,我们需要开始进行适配。"
3188
3268
  * Independent review correction (2026-07-20): Global CLI installation must retire cached and
@@ -3225,6 +3305,7 @@ const CodeEditorThemeSchema = z.enum(CODE_EDITOR_THEME_VALUES);
3225
3305
  function isTerminalRendererEngine(value) {
3226
3306
  return TERMINAL_RENDERER_ENGINE_VALUES.includes(value);
3227
3307
  }
3308
+ const OPENSPEC_CLI_FALLBACK_SPEC = `@fission-ai/openspec@${OPENSPEC_CLI_TARGET_SERIES}`;
3228
3309
  const BASE_PACKAGE_MANAGER_RUNNERS = [
3229
3310
  {
3230
3311
  id: "npx",
@@ -3232,13 +3313,13 @@ const BASE_PACKAGE_MANAGER_RUNNERS = [
3232
3313
  commandParts: [
3233
3314
  "npx",
3234
3315
  "-y",
3235
- "@fission-ai/openspec"
3316
+ OPENSPEC_CLI_FALLBACK_SPEC
3236
3317
  ]
3237
3318
  },
3238
3319
  {
3239
3320
  id: "bunx",
3240
3321
  source: "bunx",
3241
- commandParts: ["bunx", "@fission-ai/openspec"]
3322
+ commandParts: ["bunx", OPENSPEC_CLI_FALLBACK_SPEC]
3242
3323
  },
3243
3324
  {
3244
3325
  id: "deno",
@@ -3247,7 +3328,7 @@ const BASE_PACKAGE_MANAGER_RUNNERS = [
3247
3328
  "deno",
3248
3329
  "run",
3249
3330
  "-A",
3250
- "npm:@fission-ai/openspec"
3331
+ `npm:${OPENSPEC_CLI_FALLBACK_SPEC}`
3251
3332
  ]
3252
3333
  },
3253
3334
  {
@@ -3256,7 +3337,7 @@ const BASE_PACKAGE_MANAGER_RUNNERS = [
3256
3337
  commandParts: [
3257
3338
  "pnpm",
3258
3339
  "dlx",
3259
- "@fission-ai/openspec"
3340
+ OPENSPEC_CLI_FALLBACK_SPEC
3260
3341
  ]
3261
3342
  },
3262
3343
  {
@@ -3265,7 +3346,7 @@ const BASE_PACKAGE_MANAGER_RUNNERS = [
3265
3346
  commandParts: [
3266
3347
  "yarn",
3267
3348
  "dlx",
3268
- "@fission-ai/openspec"
3349
+ OPENSPEC_CLI_FALLBACK_SPEC
3269
3350
  ]
3270
3351
  }
3271
3352
  ];
@@ -3563,15 +3644,16 @@ async function fetchLatestVersion() {
3563
3644
  async function sniffGlobalCli() {
3564
3645
  const env = createCleanCliEnv();
3565
3646
  const resolvedCommand = await resolveShellExecutablePath("openspec", process.cwd(), env) ?? "openspec";
3566
- const [localResult, latestVersion] = await Promise.all([execFileAsync(resolvedCommand, ["--version"], {
3647
+ const [localResult, latestVersion] = await Promise.all([runBufferedCommand({
3648
+ command: resolvedCommand,
3649
+ args: ["--version"],
3650
+ cwd: process.cwd(),
3567
3651
  env,
3568
- timeout: 1e4,
3569
- encoding: "utf8",
3570
- windowsHide: true
3571
- }).catch((err) => ({ error: err })), fetchLatestVersion()]);
3572
- if ("error" in localResult) {
3573
- const error = localResult.error instanceof Error ? localResult.error.message : String(localResult.error);
3574
- if (error.includes("not found") || error.includes("ENOENT") || error.includes("not recognized")) return {
3652
+ timeoutMs: 1e4
3653
+ }), fetchLatestVersion()]);
3654
+ if (localResult.spawnError || localResult.timedOut || localResult.exitCode !== 0) {
3655
+ const message = localResult.spawnError?.message ?? (localResult.timedOut ? "Global CLI probe timed out." : localResult.stderr.trim() || `Exit code ${localResult.exitCode ?? "null"}`);
3656
+ if (localResult.spawnError?.code === "ENOENT" || /not found|ENOENT|not recognized|unable to resolve/i.test(message)) return {
3575
3657
  hasGlobal: false,
3576
3658
  latestVersion,
3577
3659
  hasUpdate: !!latestVersion
@@ -3580,7 +3662,7 @@ async function sniffGlobalCli() {
3580
3662
  hasGlobal: false,
3581
3663
  latestVersion,
3582
3664
  hasUpdate: !!latestVersion,
3583
- error
3665
+ error: message
3584
3666
  };
3585
3667
  }
3586
3668
  const version = localResult.stdout.trim();
@@ -1,4 +1,4 @@
1
- import { G as TranslationDownloadGroupPlan, Rt as TranslationModelDownloadPlan } from "./translator-CIptPzqy.mjs";
1
+ import { G as TranslationDownloadGroupPlan, Rt as TranslationModelDownloadPlan } from "./translator-4wvacuAX.mjs";
2
2
 
3
3
  //#region src/local-download-profiles.d.ts
4
4
  declare const LOCAL_MODEL_PROFILE_DEFINITIONS: readonly [{
@@ -1,3 +1,3 @@
1
- import "./translator-CIptPzqy.mjs";
2
- import { a as buildLocalDownloadPlanFromRepositoryFiles, i as LocalRuntimeProfileFiles, n as LocalModelProfileId, o as buildLocalDownloadPlanFromRuntimeProfileFiles, r as LocalRepositoryFile, s as selectLocalDownloadGroup, t as LOCAL_MODEL_PROFILE_DEFINITIONS } from "./local-download-profiles-BcWLAxXm.mjs";
1
+ import "./translator-4wvacuAX.mjs";
2
+ import { a as buildLocalDownloadPlanFromRepositoryFiles, i as LocalRuntimeProfileFiles, n as LocalModelProfileId, o as buildLocalDownloadPlanFromRuntimeProfileFiles, r as LocalRepositoryFile, s as selectLocalDownloadGroup, t as LOCAL_MODEL_PROFILE_DEFINITIONS } from "./local-download-profiles-CyAhZwxA.mjs";
3
3
  export { LOCAL_MODEL_PROFILE_DEFINITIONS, LocalModelProfileId, LocalRepositoryFile, LocalRuntimeProfileFiles, buildLocalDownloadPlanFromRepositoryFiles, buildLocalDownloadPlanFromRuntimeProfileFiles, selectLocalDownloadGroup };
@@ -1,3 +1,3 @@
1
- import { i as selectLocalDownloadGroup, n as buildLocalDownloadPlanFromRepositoryFiles, r as buildLocalDownloadPlanFromRuntimeProfileFiles, t as LOCAL_MODEL_PROFILE_DEFINITIONS } from "./local-download-profiles-BRsR1-kK.mjs";
1
+ import { i as selectLocalDownloadGroup, n as buildLocalDownloadPlanFromRepositoryFiles, r as buildLocalDownloadPlanFromRuntimeProfileFiles, t as LOCAL_MODEL_PROFILE_DEFINITIONS } from "./local-download-profiles-3I8AOUJj.mjs";
2
2
 
3
3
  export { LOCAL_MODEL_PROFILE_DEFINITIONS, buildLocalDownloadPlanFromRepositoryFiles, buildLocalDownloadPlanFromRuntimeProfileFiles, selectLocalDownloadGroup };
@@ -1,4 +1,4 @@
1
- import { x as SoundId } from "./sounds-CoSDUNQn.mjs";
1
+ import { x as SoundId } from "./sounds-DdPTMYMa.mjs";
2
2
  import { z } from "zod";
3
3
 
4
4
  //#region src/terminal-control.d.ts
@@ -468,6 +468,7 @@ declare const NotificationRecordSchema: z.ZodObject<{
468
468
  createdAt: z.ZodNumber;
469
469
  groupKey: z.ZodString;
470
470
  }, "strip", z.ZodTypeAny, {
471
+ createdAt: number;
471
472
  id: string;
472
473
  source: {
473
474
  type: "terminal";
@@ -488,7 +489,6 @@ declare const NotificationRecordSchema: z.ZodObject<{
488
489
  groupId: string;
489
490
  title?: string | undefined;
490
491
  };
491
- createdAt: number;
492
492
  title: string;
493
493
  body: string;
494
494
  actions: ({
@@ -507,6 +507,7 @@ declare const NotificationRecordSchema: z.ZodObject<{
507
507
  level: "success" | "error" | "warning" | "info";
508
508
  groupKey: string;
509
509
  }, {
510
+ createdAt: number;
510
511
  id: string;
511
512
  source: {
512
513
  type: "terminal";
@@ -527,7 +528,6 @@ declare const NotificationRecordSchema: z.ZodObject<{
527
528
  groupId: string;
528
529
  title?: string | undefined;
529
530
  };
530
- createdAt: number;
531
531
  title: string;
532
532
  groupKey: string;
533
533
  body?: string | undefined;
@@ -1,3 +1,3 @@
1
- import "./sounds-CoSDUNQn.mjs";
2
- import { C as getNotificationAggregateKey, E as groupNotifications, P as terminalNotificationEventToPublishInput, S as aggregateNotifications, T as getNotificationGroupLabel, _ as NotificationSource, a as NotificationAggregate, b as TerminalNotificationParseResult, c as NotificationGroupKeySchema, d as NotificationRecord, f as NotificationRecordSchema, g as NotificationSoundSchema, h as NotificationSound, i as NotificationActionSchema, k as TerminalControlParser, l as NotificationPublishInput, m as NotificationSettingsSchema, n as NOTIFICATION_SOUND_VALUES, o as NotificationGroup, p as NotificationSettings, r as NotificationAction, s as NotificationGroupKey, t as NOTIFICATION_SOUND_OPTIONS, u as NotificationPublishInputSchema, v as NotificationSourceSchema, w as getNotificationGroupKey, x as TerminalNotificationParser, y as TerminalNotificationEvent } from "./notifications-BytLKOTa.mjs";
1
+ import "./sounds-DdPTMYMa.mjs";
2
+ import { C as getNotificationAggregateKey, E as groupNotifications, P as terminalNotificationEventToPublishInput, S as aggregateNotifications, T as getNotificationGroupLabel, _ as NotificationSource, a as NotificationAggregate, b as TerminalNotificationParseResult, c as NotificationGroupKeySchema, d as NotificationRecord, f as NotificationRecordSchema, g as NotificationSoundSchema, h as NotificationSound, i as NotificationActionSchema, k as TerminalControlParser, l as NotificationPublishInput, m as NotificationSettingsSchema, n as NOTIFICATION_SOUND_VALUES, o as NotificationGroup, p as NotificationSettings, r as NotificationAction, s as NotificationGroupKey, t as NOTIFICATION_SOUND_OPTIONS, u as NotificationPublishInputSchema, v as NotificationSourceSchema, w as getNotificationGroupKey, x as TerminalNotificationParser, y as TerminalNotificationEvent } from "./notifications-Be5ltQeN.mjs";
3
3
  export { NOTIFICATION_SOUND_OPTIONS, NOTIFICATION_SOUND_VALUES, NotificationAction, NotificationActionSchema, NotificationAggregate, NotificationGroup, NotificationGroupKey, NotificationGroupKeySchema, NotificationPublishInput, NotificationPublishInputSchema, NotificationRecord, NotificationRecordSchema, NotificationSettings, NotificationSettingsSchema, NotificationSound, NotificationSoundSchema, NotificationSource, NotificationSourceSchema, TerminalControlParser, TerminalNotificationEvent, TerminalNotificationParseResult, TerminalNotificationParser, aggregateNotifications, getNotificationAggregateKey, getNotificationGroupKey, getNotificationGroupLabel, groupNotifications, terminalNotificationEventToPublishInput };
@@ -1,7 +1,7 @@
1
1
  import "./document-translation-CBqubtWC.mjs";
2
- import "./sounds-CoSDUNQn.mjs";
3
- import "./notifications-BytLKOTa.mjs";
4
- import { D as CliValidateReportSchema, J as CliCommandTransportSchema } from "./index-BZWtHuI2.mjs";
2
+ import "./sounds-DdPTMYMa.mjs";
3
+ import "./notifications-Be5ltQeN.mjs";
4
+ import { D as CliValidateReportSchema, J as CliCommandTransportSchema } from "./index-C7jJcSdH.mjs";
5
5
 
6
6
  //#region src/openspec-compat.d.ts
7
7
 
@@ -1,5 +1,5 @@
1
1
  import "./common-BRL_34xt.mjs";
2
2
  import { b as CliValidateReportSchema, w as CliCommandTransportSchema } from "./workflow-CmQ4pFYC.mjs";
3
- import { a as OPENSPEC_CLI_RECOMMENDED_MIN_VERSION, c as OPENSPEC_CLI_SUPPORTED_SERIES, d as classifyOpenSpecCliVersion, f as compareOpenSpecCliVersions, h as parseOpenSpecCliVersion, i as OPENSPEC_CLI_NEXT_SERIES_MIN_VERSION, l as OPENSPEC_CLI_TARGET_MIN_VERSION, m as formatOpenSpecCliVersion, n as OPENSPEC_CLI_ACCEPTED_RANGE, o as OPENSPEC_CLI_RECOMMENDED_RANGE, p as deriveOpenSpecCliCapabilities, r as OPENSPEC_CLI_MIN_VERSION, s as OPENSPEC_CLI_REFERENCE_TAG_PATTERN, t as OPENSPECUI_TARGET_MAJOR, u as OPENSPEC_CLI_TARGET_SERIES } from "./openspec-compat-B246EQNW.mjs";
3
+ import { a as OPENSPEC_CLI_RECOMMENDED_MIN_VERSION, c as OPENSPEC_CLI_SUPPORTED_SERIES, d as classifyOpenSpecCliVersion, f as compareOpenSpecCliVersions, h as parseOpenSpecCliVersion, i as OPENSPEC_CLI_NEXT_SERIES_MIN_VERSION, l as OPENSPEC_CLI_TARGET_MIN_VERSION, m as formatOpenSpecCliVersion, n as OPENSPEC_CLI_ACCEPTED_RANGE, o as OPENSPEC_CLI_RECOMMENDED_RANGE, p as deriveOpenSpecCliCapabilities, r as OPENSPEC_CLI_MIN_VERSION, s as OPENSPEC_CLI_REFERENCE_TAG_PATTERN, t as OPENSPECUI_TARGET_MAJOR, u as OPENSPEC_CLI_TARGET_SERIES } from "./openspec-compat-DidEO359.mjs";
4
4
 
5
5
  export { CliCommandTransportSchema, CliValidateReportSchema, OPENSPECUI_TARGET_MAJOR, OPENSPEC_CLI_ACCEPTED_RANGE, OPENSPEC_CLI_MIN_VERSION, OPENSPEC_CLI_NEXT_SERIES_MIN_VERSION, OPENSPEC_CLI_RECOMMENDED_MIN_VERSION, OPENSPEC_CLI_RECOMMENDED_RANGE, OPENSPEC_CLI_REFERENCE_TAG_PATTERN, OPENSPEC_CLI_SUPPORTED_SERIES, OPENSPEC_CLI_TARGET_MIN_VERSION, OPENSPEC_CLI_TARGET_SERIES, classifyOpenSpecCliVersion, compareOpenSpecCliVersions, deriveOpenSpecCliCapabilities, formatOpenSpecCliVersion, parseOpenSpecCliVersion };
@@ -1,4 +1,4 @@
1
- import { g as Spec } from "./schemas-_BT364v-.mjs";
1
+ import { g as Spec } from "./schemas-BG7Tcs8J.mjs";
2
2
  import { d as MarkdownReadingPlugin, l as MarkdownReadingDocument } from "./markdown-reading-CsLbxubT.mjs";
3
3
  import { n as OpenSpecAnnotation, t as AnnotatedOpenSpecDocument } from "./openspec-annotations-8ppmICAU.mjs";
4
4
 
@@ -1,6 +1,6 @@
1
- import "./schemas-_BT364v-.mjs";
1
+ import "./schemas-BG7Tcs8J.mjs";
2
2
  import "./markdown-facts-CEACwik1.mjs";
3
3
  import "./markdown-reading-CsLbxubT.mjs";
4
4
  import "./openspec-annotations-8ppmICAU.mjs";
5
- import { a as OpenSpecReadingSectionsProjection, c as ProjectedOpenSpecDocument, d as getOpenSpecReadingSections, f as parseOpenSpecMarkdownToSpec, i as OpenSpecProjectionOptions, l as createOpenSpecReadingPlugin, m as projectOpenSpecMarkdown, n as OPEN_SPEC_SPEC_PROJECTION_ID, o as OpenSpecRequirementBlock, p as projectAnnotatedOpenSpecToSpec, r as OpenSpecHeadingSection, s as OpenSpecScenarioBlock, t as OPEN_SPEC_READING_SECTIONS_PROJECTION_ID, u as getOpenSpecProjectionAnnotation } from "./openspec-projection-D2l0gt1a.mjs";
5
+ import { a as OpenSpecReadingSectionsProjection, c as ProjectedOpenSpecDocument, d as getOpenSpecReadingSections, f as parseOpenSpecMarkdownToSpec, i as OpenSpecProjectionOptions, l as createOpenSpecReadingPlugin, m as projectOpenSpecMarkdown, n as OPEN_SPEC_SPEC_PROJECTION_ID, o as OpenSpecRequirementBlock, p as projectAnnotatedOpenSpecToSpec, r as OpenSpecHeadingSection, s as OpenSpecScenarioBlock, t as OPEN_SPEC_READING_SECTIONS_PROJECTION_ID, u as getOpenSpecProjectionAnnotation } from "./openspec-projection-Bymnjuf9.mjs";
6
6
  export { OPEN_SPEC_READING_SECTIONS_PROJECTION_ID, OPEN_SPEC_SPEC_PROJECTION_ID, OpenSpecHeadingSection, OpenSpecProjectionOptions, OpenSpecReadingSectionsProjection, OpenSpecRequirementBlock, OpenSpecScenarioBlock, ProjectedOpenSpecDocument, createOpenSpecReadingPlugin, getOpenSpecProjectionAnnotation, getOpenSpecReadingSections, parseOpenSpecMarkdownToSpec, projectAnnotatedOpenSpecToSpec, projectOpenSpecMarkdown };
@@ -1,5 +1,5 @@
1
- import { n as ChangeFile } from "./schemas-_BT364v-.mjs";
2
- import { T as SchemaDetail } from "./opsx-types-CwR1AXgQ.mjs";
1
+ import { n as ChangeFile } from "./schemas-BG7Tcs8J.mjs";
2
+ import { T as SchemaDetail } from "./opsx-types-C2lUEACZ.mjs";
3
3
 
4
4
  //#region src/opsx-entity.d.ts
5
5
  type OpsxEntityStage = 'change' | 'archive';
@@ -1,8 +1,8 @@
1
1
  import "./document-translation-CBqubtWC.mjs";
2
- import "./sounds-CoSDUNQn.mjs";
3
- import "./notifications-BytLKOTa.mjs";
4
- import "./index-BZWtHuI2.mjs";
5
- import "./schemas-_BT364v-.mjs";
6
- import "./opsx-types-CwR1AXgQ.mjs";
7
- import { a as OpsxEntityFile, c as buildOpsxEntityDetail, d as isOpsxGlobPattern, f as normalizeOpsxEntityPath, h as parseOpsxEntityMetadata, i as OpsxEntityDiagnostic, l as getOpsxEntityMetadataPath, m as opsxPathMatchesPattern, n as OpsxEntityArtifactFile, o as OpsxEntityReadOptions, p as opsxGlobToRegex, r as OpsxEntityDetail, s as OpsxEntityStage, t as OpsxEntityArtifact, u as getOpsxEntityRootRelativePath } from "./opsx-entity-DPNoe1RP.mjs";
2
+ import "./sounds-DdPTMYMa.mjs";
3
+ import "./notifications-Be5ltQeN.mjs";
4
+ import "./index-C7jJcSdH.mjs";
5
+ import "./schemas-BG7Tcs8J.mjs";
6
+ import "./opsx-types-C2lUEACZ.mjs";
7
+ import { a as OpsxEntityFile, c as buildOpsxEntityDetail, d as isOpsxGlobPattern, f as normalizeOpsxEntityPath, h as parseOpsxEntityMetadata, i as OpsxEntityDiagnostic, l as getOpsxEntityMetadataPath, m as opsxPathMatchesPattern, n as OpsxEntityArtifactFile, o as OpsxEntityReadOptions, p as opsxGlobToRegex, r as OpsxEntityDetail, s as OpsxEntityStage, t as OpsxEntityArtifact, u as getOpsxEntityRootRelativePath } from "./opsx-entity-NFWGsreJ.mjs";
8
8
  export { OpsxEntityArtifact, OpsxEntityArtifactFile, OpsxEntityDetail, OpsxEntityDiagnostic, OpsxEntityFile, OpsxEntityReadOptions, OpsxEntityStage, buildOpsxEntityDetail, getOpsxEntityMetadataPath, getOpsxEntityRootRelativePath, isOpsxGlobPattern, normalizeOpsxEntityPath, opsxGlobToRegex, opsxPathMatchesPattern, parseOpsxEntityMetadata };
@@ -1,5 +1,5 @@
1
- import { T as SchemaDetail } from "./opsx-types-CwR1AXgQ.mjs";
2
- import { i as OpsxEntityDiagnostic } from "./opsx-entity-DPNoe1RP.mjs";
1
+ import { T as SchemaDetail } from "./opsx-types-C2lUEACZ.mjs";
2
+ import { i as OpsxEntityDiagnostic } from "./opsx-entity-NFWGsreJ.mjs";
3
3
 
4
4
  //#region src/opsx-schema-detail.d.ts
5
5
  interface ParsedOpsxSchemaDetail {
@@ -1,9 +1,9 @@
1
1
  import "./document-translation-CBqubtWC.mjs";
2
- import "./sounds-CoSDUNQn.mjs";
3
- import "./notifications-BytLKOTa.mjs";
4
- import "./index-BZWtHuI2.mjs";
5
- import "./schemas-_BT364v-.mjs";
6
- import "./opsx-types-CwR1AXgQ.mjs";
7
- import "./opsx-entity-DPNoe1RP.mjs";
8
- import { n as parseOpsxSchemaDetail, t as ParsedOpsxSchemaDetail } from "./opsx-schema-detail-Cd5Av3ge.mjs";
2
+ import "./sounds-DdPTMYMa.mjs";
3
+ import "./notifications-Be5ltQeN.mjs";
4
+ import "./index-C7jJcSdH.mjs";
5
+ import "./schemas-BG7Tcs8J.mjs";
6
+ import "./opsx-types-C2lUEACZ.mjs";
7
+ import "./opsx-entity-NFWGsreJ.mjs";
8
+ import { n as parseOpsxSchemaDetail, t as ParsedOpsxSchemaDetail } from "./opsx-schema-detail-ChaSoC8S.mjs";
9
9
  export { ParsedOpsxSchemaDetail, parseOpsxSchemaDetail };