openspecui 1.6.0 → 2.0.1

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 (33) hide show
  1. package/dist/cli.mjs +8 -9
  2. package/dist/index.mjs +1 -1
  3. package/dist/{src-Brh3druE.mjs → src-CFsMWl3_.mjs} +238 -60
  4. package/package.json +3 -3
  5. package/web/assets/{BufferResource-LpIscPOh.js → BufferResource-Cipj3hQ5.js} +1 -1
  6. package/web/assets/{CanvasRenderer-hdBAgk8Z.js → CanvasRenderer-C151fKcy.js} +1 -1
  7. package/web/assets/{Filter-DJVBXWdE.js → Filter-BpxymkGv.js} +1 -1
  8. package/web/assets/{RenderTargetSystem-CEuUrT8d.js → RenderTargetSystem-C0zk81Mh.js} +1 -1
  9. package/web/assets/{WebGLRenderer-DUSFltAk.js → WebGLRenderer-De3GrxdN.js} +1 -1
  10. package/web/assets/{WebGPURenderer-DafJULoy.js → WebGPURenderer-BkpejvST.js} +1 -1
  11. package/web/assets/{browserAll-DYvdsmhE.js → browserAll-B8KqF-Xa.js} +1 -1
  12. package/web/assets/{ghostty-web-BitlvuYh.js → ghostty-web-BO5ww0eG.js} +1 -1
  13. package/web/assets/{index-CYTyn82I.js → index-2DXouwnE.js} +1 -1
  14. package/web/assets/index-B-vvVL83.js +1541 -0
  15. package/web/assets/{index-hXwe0Xwc.js → index-Bp2dpDFJ.js} +1 -1
  16. package/web/assets/{index-CjHce-bH.js → index-Bxm-n0do.js} +1 -1
  17. package/web/assets/{index-Dge9ymDE.js → index-CDX9fioY.js} +1 -1
  18. package/web/assets/{index-CGTRVPmS.js → index-CFAzjIVm.js} +1 -1
  19. package/web/assets/{index-BhxOfd1V.js → index-Cj_nv8ue.js} +1 -1
  20. package/web/assets/{index-BwqUcS4o.js → index-Cv-LON1K.js} +1 -1
  21. package/web/assets/{index-DtJ1xKq6.js → index-CwA_uPvf.js} +1 -1
  22. package/web/assets/{index-DEgCfC-b.js → index-CxDip8xJ.js} +1 -1
  23. package/web/assets/{index-gPPYc26D.js → index-DL08rl2O.js} +1 -1
  24. package/web/assets/{index-5zLYkWge.js → index-DtTSWBHJ.js} +1 -1
  25. package/web/assets/{index-B8AH-4mO.js → index-DzK6gT7C.js} +1 -1
  26. package/web/assets/{index-DbrGteUX.js → index-Nl7iD8Yi.js} +1 -1
  27. package/web/assets/{index-CuiBRRWA.js → index-a8osabOh.js} +1 -1
  28. package/web/assets/index-aWxXp1oO.css +1 -0
  29. package/web/assets/{index-BXlwoClD.js → index-iROJdLzk.js} +1 -1
  30. package/web/assets/{webworkerAll-CFbGR7bA.js → webworkerAll-DPcI1cDK.js} +1 -1
  31. package/web/index.html +2 -2
  32. package/web/assets/index-CKfGQiMr.js +0 -1547
  33. package/web/assets/index-USotIqwU.css +0 -1
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as SchemaInfoSchema, c as toOpsxDisplayPath, d as DEFAULT_CONFIG, f as OpenSpecAdapter, i as SchemaDetailSchema, l as CliExecutor, m as __toESM, o as SchemaResolutionSchema, p as __commonJS, r as require_dist, s as TemplatesSchema, t as startServer, u as ConfigManager } from "./src-Brh3druE.mjs";
2
+ import { a as SchemaInfoSchema, c as toOpsxDisplayPath, d as DEFAULT_CONFIG, f as OpenSpecAdapter, i as SchemaDetailSchema, l as CliExecutor, m as __toESM, o as SchemaResolutionSchema, p as __commonJS, r as require_dist, s as TemplatesSchema, t as startServer, u as ConfigManager } from "./src-CFsMWl3_.mjs";
3
3
  import { createRequire } from "node:module";
4
4
  import { basename, dirname, extname, join, normalize, relative, resolve } from "path";
5
5
  import { readFile } from "node:fs/promises";
@@ -4507,7 +4507,7 @@ var yargs_default = Yargs;
4507
4507
  //#endregion
4508
4508
  //#region package.json
4509
4509
  var import_dist = require_dist();
4510
- var version = "1.6.0";
4510
+ var version = "2.0.1";
4511
4511
 
4512
4512
  //#endregion
4513
4513
  //#region src/export.ts
@@ -4766,12 +4766,11 @@ async function generateSnapshot(projectDir) {
4766
4766
  const changesMeta = await adapter.listChangesWithMeta();
4767
4767
  const changes = await Promise.all(changesMeta.map(async (meta) => {
4768
4768
  const change = await adapter.readChange(meta.id);
4769
- if (!change) return null;
4770
4769
  const files = await adapter.readChangeFiles(meta.id);
4771
4770
  const proposalFile = files.find((f) => f.path === "proposal.md");
4772
4771
  const tasksFile = files.find((f) => f.path === "tasks.md");
4773
4772
  const designFile = files.find((f) => f.path === "design.md");
4774
- const deltas = (change.deltaSpecs || []).map((ds) => ({
4773
+ const deltas = (change?.deltaSpecs || []).map((ds) => ({
4775
4774
  capability: ds.specId,
4776
4775
  content: ds.content || ""
4777
4776
  }));
@@ -4781,11 +4780,11 @@ async function generateSnapshot(projectDir) {
4781
4780
  proposal: proposalFile?.content || "",
4782
4781
  tasks: tasksFile?.content,
4783
4782
  design: designFile?.content,
4784
- why: change.why || "",
4785
- whatChanges: change.whatChanges || "",
4786
- parsedTasks: change.tasks || [],
4783
+ why: change?.why || "",
4784
+ whatChanges: change?.whatChanges || "",
4785
+ parsedTasks: change?.tasks || [],
4787
4786
  deltas,
4788
- progress: meta.progress,
4787
+ progress: change?.progress ?? meta.progress,
4789
4788
  createdAt: meta.createdAt,
4790
4789
  updatedAt: meta.updatedAt
4791
4790
  };
@@ -4917,7 +4916,7 @@ async function generateSnapshot(projectDir) {
4917
4916
  git,
4918
4917
  config: uiConfig,
4919
4918
  specs,
4920
- changes: changes.filter((c) => c !== null),
4919
+ changes,
4921
4920
  archives,
4922
4921
  projectMd,
4923
4922
  agentsMd,
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { n as createServer, t as startServer } from "./src-Brh3druE.mjs";
1
+ import { n as createServer, t as startServer } from "./src-CFsMWl3_.mjs";
2
2
 
3
3
  export { createServer, startServer };
@@ -1817,47 +1817,50 @@ var OpenSpecAdapter = class {
1817
1817
  }
1818
1818
  /**
1819
1819
  * List changes with metadata (id, name, progress, and time info)
1820
- * Only returns changes that have valid proposal.md
1820
+ * Returns every change directory, including schema-specific layouts that
1821
+ * don't use proposal.md/tasks.md.
1821
1822
  * Sorted by updatedAt descending (most recent first)
1822
1823
  */
1823
1824
  async listChangesWithMeta() {
1824
1825
  const ids = await this.listChanges();
1825
1826
  return (await Promise.all(ids.map(async (id) => {
1826
1827
  const change = await this.readChange(id);
1827
- if (!change) return null;
1828
- const proposalPath = join(this.changesDir, id, "proposal.md");
1829
- const timeInfo = await this.getFileTimeInfo(proposalPath);
1828
+ const changeDir = join(this.changesDir, id);
1829
+ const timeInfo = await this.getFileTimeInfo(changeDir);
1830
1830
  return {
1831
1831
  id,
1832
- name: change.name,
1833
- progress: change.progress,
1832
+ name: change?.name ?? id,
1833
+ progress: change?.progress ?? {
1834
+ total: 0,
1835
+ completed: 0
1836
+ },
1834
1837
  createdAt: timeInfo?.createdAt ?? 0,
1835
1838
  updatedAt: timeInfo?.updatedAt ?? 0
1836
1839
  };
1837
- }))).filter((r) => r !== null).sort((a, b) => b.updatedAt - a.updatedAt);
1840
+ }))).sort((a, b) => b.updatedAt - a.updatedAt);
1838
1841
  }
1839
1842
  async listArchivedChanges() {
1840
1843
  return reactiveReadDir(this.archiveDir, { directoriesOnly: true });
1841
1844
  }
1842
1845
  /**
1843
1846
  * List archived changes with metadata and time info
1844
- * Only returns archives that have valid proposal.md
1847
+ * Returns every archive directory, including schema-specific layouts that
1848
+ * don't use proposal.md/tasks.md.
1845
1849
  * Sorted by updatedAt descending (most recent first)
1846
1850
  */
1847
1851
  async listArchivedChangesWithMeta() {
1848
1852
  const ids = await this.listArchivedChanges();
1849
1853
  return (await Promise.all(ids.map(async (id) => {
1850
1854
  const change = await this.readArchivedChange(id);
1851
- if (!change) return null;
1852
- const proposalPath = join(this.archiveDir, id, "proposal.md");
1853
- const timeInfo = await this.getFileTimeInfo(proposalPath);
1855
+ const archiveDir = join(this.archiveDir, id);
1856
+ const timeInfo = await this.getFileTimeInfo(archiveDir);
1854
1857
  return {
1855
1858
  id,
1856
- name: change.name,
1859
+ name: change?.name ?? id,
1857
1860
  createdAt: timeInfo?.createdAt ?? 0,
1858
1861
  updatedAt: timeInfo?.updatedAt ?? 0
1859
1862
  };
1860
- }))).filter((r) => r !== null).sort((a, b) => b.updatedAt - a.updatedAt);
1863
+ }))).sort((a, b) => b.updatedAt - a.updatedAt);
1861
1864
  }
1862
1865
  /**
1863
1866
  * Read project.md content (reactive)
@@ -1923,7 +1926,7 @@ var OpenSpecAdapter = class {
1923
1926
  });
1924
1927
  }
1925
1928
  async collectChangeFiles(root, dir) {
1926
- const names = await reactiveReadDir(dir, { includeHidden: false });
1929
+ const names = await reactiveReadDir(dir, { includeHidden: true });
1927
1930
  const files = [];
1928
1931
  for (const name of names) {
1929
1932
  const fullPath = join(dir, name);
@@ -5939,8 +5942,18 @@ const CURSOR_STYLE_VALUES = [
5939
5942
  "underline",
5940
5943
  "bar"
5941
5944
  ];
5945
+ const CODE_EDITOR_THEME_VALUES = [
5946
+ "github",
5947
+ "material",
5948
+ "vscode",
5949
+ "tokyo",
5950
+ "gruvbox",
5951
+ "monokai",
5952
+ "nord"
5953
+ ];
5942
5954
  const TERMINAL_RENDERER_ENGINE_VALUES = ["xterm", "ghostty"];
5943
5955
  const TerminalRendererEngineSchema = enumType(TERMINAL_RENDERER_ENGINE_VALUES);
5956
+ const CodeEditorThemeSchema = enumType(CODE_EDITOR_THEME_VALUES);
5944
5957
  const BASE_PACKAGE_MANAGER_RUNNERS = [
5945
5958
  {
5946
5959
  id: "npx",
@@ -6282,6 +6295,7 @@ const TerminalConfigSchema = objectType({
6282
6295
  rendererEngine: stringType().default("xterm")
6283
6296
  });
6284
6297
  const DashboardConfigSchema = objectType({ trendPointLimit: numberType().int().min(20).max(500).default(100) });
6298
+ const CodeEditorConfigSchema = objectType({ theme: CodeEditorThemeSchema.default("github") });
6285
6299
  /**
6286
6300
  * OpenSpecUI 配置 Schema
6287
6301
  *
@@ -6293,6 +6307,7 @@ const OpenSpecUIConfigSchema = objectType({
6293
6307
  args: arrayType(stringType()).optional()
6294
6308
  }).default({}),
6295
6309
  theme: enumType(THEME_VALUES).default("system"),
6310
+ codeEditor: CodeEditorConfigSchema.default(CodeEditorConfigSchema.parse({})),
6296
6311
  terminal: TerminalConfigSchema.default(TerminalConfigSchema.parse({})),
6297
6312
  dashboard: DashboardConfigSchema.default(DashboardConfigSchema.parse({}))
6298
6313
  });
@@ -6300,6 +6315,7 @@ const OpenSpecUIConfigSchema = objectType({
6300
6315
  const DEFAULT_CONFIG = {
6301
6316
  cli: {},
6302
6317
  theme: "system",
6318
+ codeEditor: CodeEditorConfigSchema.parse({}),
6303
6319
  terminal: TerminalConfigSchema.parse({}),
6304
6320
  dashboard: DashboardConfigSchema.parse({})
6305
6321
  };
@@ -6364,6 +6380,10 @@ var ConfigManager = class {
6364
6380
  ...current,
6365
6381
  cli: nextCli,
6366
6382
  theme: config.theme ?? current.theme,
6383
+ codeEditor: {
6384
+ ...current.codeEditor,
6385
+ ...config.codeEditor
6386
+ },
6367
6387
  terminal: {
6368
6388
  ...current.terminal,
6369
6389
  ...config.terminal
@@ -6577,13 +6597,15 @@ var CliExecutor = class {
6577
6597
  /**
6578
6598
  * 执行 openspec init(非交互式)
6579
6599
  */
6580
- async init(tools = "all") {
6581
- const toolsArg = Array.isArray(tools) ? tools.join(",") : tools;
6582
- return this.execute([
6583
- "init",
6584
- "--tools",
6585
- toolsArg
6586
- ]);
6600
+ async init(options) {
6601
+ const args = ["init"];
6602
+ if (options?.tools !== void 0) {
6603
+ const toolsArg = Array.isArray(options.tools) ? options.tools.join(",") : options.tools;
6604
+ args.push("--tools", toolsArg);
6605
+ }
6606
+ if (options?.profile) args.push("--profile", options.profile);
6607
+ if (options?.force) args.push("--force");
6608
+ return this.execute(args);
6587
6609
  }
6588
6610
  /**
6589
6611
  * 执行 openspec archive <changeId>(非交互式)
@@ -6750,13 +6772,15 @@ var CliExecutor = class {
6750
6772
  /**
6751
6773
  * 流式执行 openspec init
6752
6774
  */
6753
- initStream(tools, onEvent) {
6754
- const toolsArg = Array.isArray(tools) ? tools.join(",") : tools;
6755
- return this.executeStream([
6756
- "init",
6757
- "--tools",
6758
- toolsArg
6759
- ], onEvent);
6775
+ initStream(options, onEvent) {
6776
+ const args = ["init"];
6777
+ if (options.tools !== void 0) {
6778
+ const toolsArg = Array.isArray(options.tools) ? options.tools.join(",") : options.tools;
6779
+ args.push("--tools", toolsArg);
6780
+ }
6781
+ if (options.profile) args.push("--profile", options.profile);
6782
+ if (options.force) args.push("--force");
6783
+ return this.executeStream(args, onEvent);
6760
6784
  }
6761
6785
  /**
6762
6786
  * 流式执行 openspec archive
@@ -6841,7 +6865,9 @@ const SKILL_NAMES = [
6841
6865
  "openspec-sync-specs",
6842
6866
  "openspec-archive-change",
6843
6867
  "openspec-bulk-archive-change",
6844
- "openspec-verify-change"
6868
+ "openspec-verify-change",
6869
+ "openspec-onboard",
6870
+ "openspec-propose"
6845
6871
  ];
6846
6872
  /**
6847
6873
  * 所有支持的 AI 工具配置
@@ -6960,6 +6986,13 @@ const AI_TOOLS = [
6960
6986
  successLabel: "Kilo Code",
6961
6987
  skillsDir: ".kilocode"
6962
6988
  },
6989
+ {
6990
+ name: "Kiro",
6991
+ value: "kiro",
6992
+ available: true,
6993
+ successLabel: "Kiro",
6994
+ skillsDir: ".kiro"
6995
+ },
6963
6996
  {
6964
6997
  name: "OpenCode",
6965
6998
  value: "opencode",
@@ -6967,6 +7000,13 @@ const AI_TOOLS = [
6967
7000
  successLabel: "OpenCode",
6968
7001
  skillsDir: ".opencode"
6969
7002
  },
7003
+ {
7004
+ name: "Pi",
7005
+ value: "pi",
7006
+ available: true,
7007
+ successLabel: "Pi",
7008
+ skillsDir: ".pi"
7009
+ },
6970
7010
  {
6971
7011
  name: "Qoder",
6972
7012
  value: "qoder",
@@ -23950,6 +23990,12 @@ const t = initTRPC.context().create();
23950
23990
  const router = t.router;
23951
23991
  const publicProcedure = t.procedure;
23952
23992
  const execFileAsync = promisify$1(execFile);
23993
+ const OPSX_CORE_PROFILE_WORKFLOWS = [
23994
+ "propose",
23995
+ "explore",
23996
+ "apply",
23997
+ "archive"
23998
+ ];
23953
23999
  const dashboardGitTaskStatusEmitter = new EventEmitter$1();
23954
24000
  dashboardGitTaskStatusEmitter.setMaxListeners(200);
23955
24001
  const dashboardGitTaskStatus = {
@@ -24023,6 +24069,94 @@ function requireChangeId(changeId) {
24023
24069
  if (!changeId) throw new Error("change is required");
24024
24070
  return changeId;
24025
24071
  }
24072
+ function parseOpsxProfileListJson(stdout) {
24073
+ try {
24074
+ const parsed = JSON.parse(stdout);
24075
+ const profile = parsed.profile === "custom" ? "custom" : "core";
24076
+ return {
24077
+ profile,
24078
+ delivery: parsed.delivery === "skills" || parsed.delivery === "commands" ? parsed.delivery : "both",
24079
+ workflows: Array.isArray(parsed.workflows) ? parsed.workflows.filter((item) => typeof item === "string" && item.length > 0) : profile === "core" ? [...OPSX_CORE_PROFILE_WORKFLOWS] : []
24080
+ };
24081
+ } catch {
24082
+ return null;
24083
+ }
24084
+ }
24085
+ function parseOpsxConfigDrift(output) {
24086
+ const lines = output.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
24087
+ const warningLine = lines.find((line) => /global config.+not applied.+project/i.test(line)) ?? lines.find((line) => /out of sync/i.test(line)) ?? lines.find((line) => /run\s+`?openspec\s+update`?/i.test(line)) ?? null;
24088
+ return {
24089
+ drift: warningLine !== null,
24090
+ warningText: warningLine
24091
+ };
24092
+ }
24093
+ async function fetchOpsxProfileState(ctx) {
24094
+ const configListJson = await ctx.cliExecutor.execute([
24095
+ "config",
24096
+ "list",
24097
+ "--json"
24098
+ ]);
24099
+ if (!configListJson.success) return {
24100
+ available: false,
24101
+ profile: null,
24102
+ delivery: null,
24103
+ workflows: [],
24104
+ driftStatus: "unknown",
24105
+ warningText: null,
24106
+ error: configListJson.stderr || "Failed to load profile config."
24107
+ };
24108
+ const parsed = parseOpsxProfileListJson(configListJson.stdout);
24109
+ if (!parsed) return {
24110
+ available: false,
24111
+ profile: null,
24112
+ delivery: null,
24113
+ workflows: [],
24114
+ driftStatus: "unknown",
24115
+ warningText: null,
24116
+ error: "Invalid JSON from `openspec config list --json`."
24117
+ };
24118
+ const configListText = await ctx.cliExecutor.execute(["config", "list"]);
24119
+ if (!configListText.success) return {
24120
+ available: true,
24121
+ profile: parsed.profile,
24122
+ delivery: parsed.delivery,
24123
+ workflows: parsed.workflows,
24124
+ driftStatus: "unknown",
24125
+ warningText: null
24126
+ };
24127
+ const drift = parseOpsxConfigDrift(`${configListText.stdout}\n${configListText.stderr}`);
24128
+ return {
24129
+ available: true,
24130
+ profile: parsed.profile,
24131
+ delivery: parsed.delivery,
24132
+ workflows: parsed.workflows,
24133
+ driftStatus: drift.drift ? "drift" : "in-sync",
24134
+ warningText: drift.warningText
24135
+ };
24136
+ }
24137
+ async function resolveGlobalConfigPath(ctx) {
24138
+ const result = await ctx.cliExecutor.execute(["config", "path"]);
24139
+ if (!result.success) throw new Error(result.stderr || "Failed to resolve OpenSpec global config path.");
24140
+ const path$1 = result.stdout.trim();
24141
+ if (!path$1) throw new Error("OpenSpec global config path is empty.");
24142
+ return path$1;
24143
+ }
24144
+ async function fetchGlobalConfigJson(ctx) {
24145
+ const result = await ctx.cliExecutor.execute([
24146
+ "config",
24147
+ "list",
24148
+ "--json"
24149
+ ]);
24150
+ if (!result.success) throw new Error(result.stderr || "Failed to load OpenSpec global config.");
24151
+ try {
24152
+ const parsed = JSON.parse(result.stdout);
24153
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("OpenSpec global config must be a JSON object.");
24154
+ return parsed;
24155
+ } catch (error) {
24156
+ const message = error instanceof Error ? error.message : String(error);
24157
+ throw new Error(`Invalid JSON from \`openspec config list --json\`: ${message}`);
24158
+ }
24159
+ }
24026
24160
  function ensureEditableSource(source, label) {
24027
24161
  if (source === "package") throw new Error(`${label} is read-only (package source)`);
24028
24162
  }
@@ -24145,6 +24279,35 @@ async function fetchDashboardOverview(ctx, reason = "dashboard-refresh") {
24145
24279
  ctx.adapter.listChangesWithMeta(),
24146
24280
  ctx.adapter.listArchivedChangesWithMeta()
24147
24281
  ]);
24282
+ await ctx.kernel.waitForWarmup();
24283
+ await ctx.kernel.ensureStatusList();
24284
+ const statusList = ctx.kernel.getStatusList();
24285
+ const changeMetaMap = new Map(changeMetas.map((change) => [change.id, change]));
24286
+ const activeChangeIds = new Set([...changeMetas.map((change) => change.id), ...statusList.map((status) => status.changeName)]);
24287
+ const statusByChange = new Map(statusList.map((status) => [status.changeName, status]));
24288
+ const activeChanges = (await Promise.all([...activeChangeIds].map(async (changeId) => {
24289
+ const status = statusByChange.get(changeId);
24290
+ const changeMeta = changeMetaMap.get(changeId);
24291
+ const statInfo = await reactiveStat(join$1(ctx.projectDir, "openspec", "changes", changeId));
24292
+ let progress = changeMeta?.progress ?? {
24293
+ total: 0,
24294
+ completed: 0
24295
+ };
24296
+ if (status) try {
24297
+ await ctx.kernel.ensureApplyInstructions(changeId, status.schemaName);
24298
+ const apply = ctx.kernel.getApplyInstructions(changeId, status.schemaName);
24299
+ progress = {
24300
+ total: apply.progress.total,
24301
+ completed: apply.progress.complete
24302
+ };
24303
+ } catch {}
24304
+ return {
24305
+ id: changeId,
24306
+ name: changeMeta?.name ?? changeId,
24307
+ progress,
24308
+ updatedAt: changeMeta?.updatedAt ?? statInfo?.mtime ?? 0
24309
+ };
24310
+ }))).sort((a, b) => b.updatedAt - a.updatedAt);
24148
24311
  const archivedChanges = (await Promise.all(archiveMetas.map(async (meta) => {
24149
24312
  const change = await ctx.adapter.readArchivedChange(meta.id);
24150
24313
  if (!change) return null;
@@ -24165,12 +24328,6 @@ async function fetchDashboardOverview(ctx, reason = "dashboard-refresh") {
24165
24328
  updatedAt: meta.updatedAt
24166
24329
  };
24167
24330
  }))).filter((item) => item !== null).sort((a, b) => b.requirements - a.requirements || b.updatedAt - a.updatedAt);
24168
- const activeChanges = changeMetas.map((change) => ({
24169
- id: change.id,
24170
- name: change.name,
24171
- progress: change.progress,
24172
- updatedAt: change.updatedAt
24173
- }));
24174
24331
  const requirements = specifications.reduce((sum, spec) => sum + spec.requirements, 0);
24175
24332
  const tasksTotal = activeChanges.reduce((sum, change) => sum + change.progress.total, 0);
24176
24333
  const tasksCompleted = activeChanges.reduce((sum, change) => sum + change.progress.completed, 0);
@@ -24501,6 +24658,7 @@ const configRouter = router({
24501
24658
  "dark",
24502
24659
  "system"
24503
24660
  ]).optional(),
24661
+ codeEditor: objectType({ theme: CodeEditorThemeSchema.optional() }).optional(),
24504
24662
  terminal: TerminalConfigSchema.omit({ rendererEngine: true }).partial().extend({ rendererEngine: TerminalRendererEngineSchema.optional() }).optional(),
24505
24663
  dashboard: DashboardConfigSchema.partial().optional()
24506
24664
  })).mutation(async ({ ctx, input }) => {
@@ -24508,8 +24666,9 @@ const configRouter = router({
24508
24666
  const hasCliArgs = input.cli !== void 0 && Object.prototype.hasOwnProperty.call(input.cli, "args");
24509
24667
  if (hasCliCommand && !hasCliArgs) {
24510
24668
  await ctx.configManager.setCliCommand(input.cli?.command ?? "");
24511
- if (input.theme !== void 0 || input.terminal !== void 0 || input.dashboard !== void 0) await ctx.configManager.writeConfig({
24669
+ if (input.theme !== void 0 || input.codeEditor !== void 0 || input.terminal !== void 0 || input.dashboard !== void 0) await ctx.configManager.writeConfig({
24512
24670
  theme: input.theme,
24671
+ codeEditor: input.codeEditor,
24513
24672
  terminal: input.terminal,
24514
24673
  dashboard: input.dashboard
24515
24674
  });
@@ -24570,18 +24729,41 @@ const cliRouter = router({
24570
24729
  successLabel: tool.successLabel
24571
24730
  }));
24572
24731
  }),
24732
+ getProfileState: publicProcedure.query(async ({ ctx }) => {
24733
+ return fetchOpsxProfileState(ctx);
24734
+ }),
24735
+ getGlobalConfigPath: publicProcedure.query(async ({ ctx }) => {
24736
+ return { path: await resolveGlobalConfigPath(ctx) };
24737
+ }),
24738
+ getGlobalConfig: publicProcedure.query(async ({ ctx }) => {
24739
+ return fetchGlobalConfigJson(ctx);
24740
+ }),
24741
+ setGlobalConfig: publicProcedure.input(objectType({ config: recordType(stringType(), unknownType()) })).mutation(async ({ ctx, input }) => {
24742
+ const configPath = await resolveGlobalConfigPath(ctx);
24743
+ await mkdir$1(dirname$1(configPath), { recursive: true });
24744
+ await writeFile$1(configPath, `${JSON.stringify(input.config, null, 2)}\n`, "utf8");
24745
+ return { success: true };
24746
+ }),
24573
24747
  getConfiguredTools: publicProcedure.query(async ({ ctx }) => {
24574
24748
  return getConfiguredTools(ctx.projectDir);
24575
24749
  }),
24576
24750
  subscribeConfiguredTools: publicProcedure.subscription(({ ctx }) => {
24577
24751
  return createReactiveSubscription(() => getConfiguredTools(ctx.projectDir));
24578
24752
  }),
24579
- init: publicProcedure.input(objectType({ tools: unionType([
24580
- arrayType(stringType()),
24581
- literalType("all"),
24582
- literalType("none")
24583
- ]).optional() }).optional()).mutation(async ({ ctx, input }) => {
24584
- return ctx.cliExecutor.init(input?.tools ?? "all");
24753
+ init: publicProcedure.input(objectType({
24754
+ tools: unionType([
24755
+ arrayType(stringType()),
24756
+ literalType("all"),
24757
+ literalType("none")
24758
+ ]).optional(),
24759
+ profile: enumType(["core", "custom"]).optional(),
24760
+ force: booleanType().optional()
24761
+ }).optional()).mutation(async ({ ctx, input }) => {
24762
+ return ctx.cliExecutor.init({
24763
+ tools: input?.tools,
24764
+ profile: input?.profile,
24765
+ force: input?.force
24766
+ });
24585
24767
  }),
24586
24768
  archive: publicProcedure.input(objectType({
24587
24769
  changeId: stringType(),
@@ -24608,12 +24790,20 @@ const cliRouter = router({
24608
24790
  execute: publicProcedure.input(objectType({ args: arrayType(stringType()) })).mutation(async ({ ctx, input }) => {
24609
24791
  return ctx.cliExecutor.execute(input.args);
24610
24792
  }),
24611
- initStream: publicProcedure.input(objectType({ tools: unionType([
24612
- arrayType(stringType()),
24613
- literalType("all"),
24614
- literalType("none")
24615
- ]).optional() }).optional()).subscription(({ ctx, input }) => {
24616
- return createCliStreamObservable((onEvent) => ctx.cliExecutor.initStream(input?.tools ?? "all", onEvent));
24793
+ initStream: publicProcedure.input(objectType({
24794
+ tools: unionType([
24795
+ arrayType(stringType()),
24796
+ literalType("all"),
24797
+ literalType("none")
24798
+ ]).optional(),
24799
+ profile: enumType(["core", "custom"]).optional(),
24800
+ force: booleanType().optional()
24801
+ }).optional()).subscription(({ ctx, input }) => {
24802
+ return createCliStreamObservable((onEvent) => ctx.cliExecutor.initStream({
24803
+ tools: input?.tools,
24804
+ profile: input?.profile,
24805
+ force: input?.force
24806
+ }, onEvent));
24617
24807
  }),
24618
24808
  archiveStream: publicProcedure.input(objectType({
24619
24809
  changeId: stringType(),
@@ -24847,18 +25037,6 @@ const opsxRouter = router({
24847
25037
  return ctx.kernel.getChangeIds();
24848
25038
  });
24849
25039
  }),
24850
- changeMetadata: publicProcedure.input(objectType({ changeId: stringType() })).query(async ({ ctx, input }) => {
24851
- await ctx.kernel.waitForWarmup();
24852
- await ctx.kernel.ensureChangeMetadata(input.changeId);
24853
- return ctx.kernel.getChangeMetadata(input.changeId);
24854
- }),
24855
- subscribeChangeMetadata: publicProcedure.input(objectType({ changeId: stringType() })).subscription(({ ctx, input }) => {
24856
- return createReactiveSubscription(async () => {
24857
- await ctx.kernel.waitForWarmup();
24858
- await ctx.kernel.ensureChangeMetadata(input.changeId);
24859
- return ctx.kernel.getChangeMetadata(input.changeId);
24860
- });
24861
- }),
24862
25040
  readArtifactOutput: publicProcedure.input(objectType({
24863
25041
  changeId: stringType(),
24864
25042
  outputPath: stringType()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openspecui",
3
- "version": "1.6.0",
3
+ "version": "2.0.1",
4
4
  "description": "OpenSpec UI - Visual interface for spec-driven development",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
@@ -33,8 +33,8 @@
33
33
  "typescript": "^5.7.2",
34
34
  "vitest": "^2.1.8",
35
35
  "yargs": "^18.0.0",
36
- "@openspecui/server": "1.6.0",
37
- "@openspecui/web": "1.6.0"
36
+ "@openspecui/web": "2.0.1",
37
+ "@openspecui/server": "2.0.0"
38
38
  },
39
39
  "scripts": {
40
40
  "build": "pnpm run build:web && pnpm run build:copy-web && tsdown",
@@ -1,4 +1,4 @@
1
- import{y as U,z as g,A as c,B as S,D as _,F as m,H as I,J as p}from"./index-CKfGQiMr.js";const x={name:"local-uniform-bit",vertex:{header:`
1
+ import{y as U,z as g,A as c,B as S,D as _,F as m,H as I,J as p}from"./index-B-vvVL83.js";const x={name:"local-uniform-bit",vertex:{header:`
2
2
 
3
3
  struct LocalUniforms {
4
4
  uTransformMatrix:mat3x3<f32>,