@openspecui/web 11.1.0 → 13.0.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 (72) hide show
  1. package/dist/assets/App-CYwWbLgm.css +1 -0
  2. package/dist/assets/{App-V1__U9uZ.js → App-Cq2vfNv0.js} +159 -159
  3. package/dist/assets/{main-CKiFAoXE.js → main-CjHLYXqj.js} +2 -2
  4. package/dist/assets/{trpc-BLZ0FQJV.js → trpc-BJDrN6rb.js} +1 -1
  5. package/dist/index.html +1 -1
  6. package/dist-ssg/client/.vite/ssr-manifest.json +79 -29
  7. package/dist-ssg/client/assets/CanvasRenderer-BAnUeHzl.js +1 -0
  8. package/dist-ssg/client/assets/WebGLRenderer-DehTnF66.js +1 -0
  9. package/dist-ssg/client/assets/WebGPURenderer-BCXAr50t.js +1 -0
  10. package/dist-ssg/client/assets/browserAll-Brx8TmCT.js +1 -0
  11. package/dist-ssg/client/assets/{config-guide-presentation-BuoQZFn1.js → config-guide-presentation-BYWAVHG-.js} +1 -1
  12. package/dist-ssg/client/assets/{dist-csqKQiDd.js → dist-B014oKqB.js} +1 -1
  13. package/dist-ssg/client/assets/{dist-CH33y9Yu.js → dist-B7XysJsL.js} +1 -1
  14. package/dist-ssg/client/assets/dist-BKcEPt5U.js +1 -0
  15. package/dist-ssg/client/assets/dist-BZVFJHY_.js +1 -0
  16. package/dist-ssg/client/assets/{dist-Dtpb6ue4.js → dist-CT1adEON.js} +1 -1
  17. package/dist-ssg/client/assets/{dist-2ZcaJZrJ.js → dist-DBbVV3c6.js} +1 -1
  18. package/dist-ssg/client/assets/{dist-B_-3nALe.js → dist-DFWGpO_L.js} +1 -1
  19. package/dist-ssg/client/assets/{dist-DHX5Y9iH.js → dist-DUzLJ7IR.js} +1 -1
  20. package/dist-ssg/client/assets/{dist-LQ5AvrWf.js → dist-DtpQCgKd.js} +1 -1
  21. package/dist-ssg/client/assets/{dist-Bbf-AGCl.js → dist-DvnWUGiW.js} +1 -1
  22. package/dist-ssg/client/assets/{dist-BCSOUbi7.js → dist-PNypP3x_.js} +1 -1
  23. package/dist-ssg/client/assets/dist-qdJFVZmv.js +1 -0
  24. package/dist-ssg/client/assets/{ghostty-web-CvjC3u3U.js → ghostty-web-DSqlIAa4.js} +1 -1
  25. package/dist-ssg/client/assets/index-CMfi0IZJ.css +1 -0
  26. package/dist-ssg/client/assets/index.ssg-CJP1DN4-.js +1650 -0
  27. package/dist-ssg/client/assets/{init-DkFTD8N9.js → init-ORkrPTI8.js} +1 -1
  28. package/dist-ssg/client/assets/{trpc-CeLyGxLD.js → trpc-DimmQX0m.js} +1 -1
  29. package/dist-ssg/client/assets/webworkerAll-DjsDtAjh.js +1 -0
  30. package/dist-ssg/client/index.ssg.html +2 -2
  31. package/dist-ssg/server/assets/CanvasRenderer-CvVvHnla.js +3 -0
  32. package/dist-ssg/server/assets/WebGLRenderer-ZTMKqKjr.js +3 -0
  33. package/dist-ssg/server/assets/WebGPURenderer-BaTRp8M6.js +3 -0
  34. package/dist-ssg/server/assets/{browserAll-B9JXZQ_b.js → browserAll-BoaMSEnC.js} +2 -2
  35. package/dist-ssg/server/assets/{config-guide-presentation-D921NMVc.js → config-guide-presentation-B5oRLCcX.js} +1 -1
  36. package/dist-ssg/server/assets/{dist-D5RQw1xh.js → dist-BTp4dJw4.js} +1 -1
  37. package/dist-ssg/server/assets/{dist-BJhwVaSw.js → dist-Bi2hyX2D.js} +1 -1
  38. package/dist-ssg/server/assets/{dist-D6j5GTM2.js → dist-C4EXY8oH.js} +1 -1
  39. package/dist-ssg/server/assets/{dist-BjB76DhT.js → dist-CHiBYKhO.js} +1 -1
  40. package/dist-ssg/server/assets/dist-CIVGOe5c.js +3 -0
  41. package/dist-ssg/server/assets/{dist-CX9PVvRC.js → dist-CLOFOKCn.js} +1 -1
  42. package/dist-ssg/server/assets/{dist-CbRRi2nf.js → dist-CUmPwPDw.js} +1 -1
  43. package/dist-ssg/server/assets/dist-DAIXBI5T.js +3 -0
  44. package/dist-ssg/server/assets/{dist-BhaY9Mk5.js → dist-DQpyDhfS.js} +1 -1
  45. package/dist-ssg/server/assets/{dist-D4O-5WhW.js → dist-DVnu9zoA.js} +1 -1
  46. package/dist-ssg/server/assets/{dist-CXVf0s87.js → dist-D_mnjXV3.js} +1 -1
  47. package/dist-ssg/server/assets/dist-fy1m8mbf.js +3 -0
  48. package/dist-ssg/server/assets/{entry-server-QFuPLrwO.js → entry-server-CXwaLjrK.js} +938 -144
  49. package/dist-ssg/server/assets/{init-B0dChRpm.js → init-B1eN597N.js} +1 -1
  50. package/dist-ssg/server/assets/trpc-BQ6eyI7t.js +3 -0
  51. package/dist-ssg/server/assets/webworkerAll-bAKoC1FD.js +4 -0
  52. package/dist-ssg/server/ssr-entry-manifest.json +24 -24
  53. package/package.json +3 -3
  54. package/dist/assets/App-wF-eA1hn.css +0 -1
  55. package/dist-ssg/client/assets/CanvasRenderer-DcF6YeUw.js +0 -1
  56. package/dist-ssg/client/assets/WebGLRenderer-CUyEgGvz.js +0 -1
  57. package/dist-ssg/client/assets/WebGPURenderer-HO--KqMy.js +0 -1
  58. package/dist-ssg/client/assets/browserAll-CK2e9DJ7.js +0 -1
  59. package/dist-ssg/client/assets/dist-B8CANbA6.js +0 -1
  60. package/dist-ssg/client/assets/dist-BM2XFyj7.js +0 -1
  61. package/dist-ssg/client/assets/dist-CzvTcdIB.js +0 -1
  62. package/dist-ssg/client/assets/index-CTUS2FEE.css +0 -1
  63. package/dist-ssg/client/assets/index.ssg-qirBkhbD.js +0 -1650
  64. package/dist-ssg/client/assets/webworkerAll-D9xesa9H.js +0 -1
  65. package/dist-ssg/server/assets/CanvasRenderer-Bvd3pXBF.js +0 -3
  66. package/dist-ssg/server/assets/WebGLRenderer-jIngAd_2.js +0 -3
  67. package/dist-ssg/server/assets/WebGPURenderer-C6g3K2oe.js +0 -3
  68. package/dist-ssg/server/assets/dist-1rQWAJV4.js +0 -3
  69. package/dist-ssg/server/assets/dist-BIgXEKIS.js +0 -3
  70. package/dist-ssg/server/assets/dist-CzCglUOQ.js +0 -3
  71. package/dist-ssg/server/assets/trpc-CbiCXi-L.js +0 -3
  72. package/dist-ssg/server/assets/webworkerAll-DukCMCoQ.js +0 -4
@@ -30908,7 +30908,7 @@ var NavController = class {
30908
30908
  this.storageKey = scopedStorageKey;
30909
30909
  this.rebindProjectScopedLayout(scopedStorageKey);
30910
30910
  }
30911
- const { trpcClient } = await import("./trpc-CbiCXi-L.js");
30911
+ const { trpcClient } = await import("./trpc-BQ6eyI7t.js");
30912
30912
  const remote = parsePersistedLayout(await trpcClient.kv.get.query({ key: this.storageKey }));
30913
30913
  if (remote) {
30914
30914
  if (remote.updatedAt > this.state.updatedAt) this.dispatch({
@@ -31051,7 +31051,7 @@ var NavController = class {
31051
31051
  this.cancelPersistTimer();
31052
31052
  this.persistTimer = setTimeout(() => {
31053
31053
  this.persistTimer = null;
31054
- import("./trpc-CbiCXi-L.js").then(({ trpcClient }) => trpcClient.kv.set.mutate({
31054
+ import("./trpc-BQ6eyI7t.js").then(({ trpcClient }) => trpcClient.kv.set.mutate({
31055
31055
  key: this.storageKey,
31056
31056
  value: {
31057
31057
  mainTabs: this.state.mainTabs,
@@ -39116,6 +39116,8 @@ unionType([objectType({
39116
39116
  "ready"
39117
39117
  ]),
39118
39118
  missingArtifacts: arrayType(stringType()).optional(),
39119
+ missingPrerequisites: arrayType(stringType()).optional(),
39120
+ warnings: arrayType(stringType()).optional(),
39119
39121
  instruction: stringType(),
39120
39122
  references: arrayType(CliReferenceIndexEntrySchema).optional(),
39121
39123
  context: stringType().optional(),
@@ -39144,23 +39146,109 @@ var CliValidationTotalsSchema = objectType({
39144
39146
  passed: numberType(),
39145
39147
  failed: numberType()
39146
39148
  }).passthrough();
39149
+ /** One bulk Validate item: verdict, full issue array, and runtime-dependent duration. */
39150
+ var CliValidateItemSchema = objectType({
39151
+ id: stringType(),
39152
+ type: enumType(["change", "spec"]),
39153
+ valid: booleanType(),
39154
+ issues: arrayType(CliValidationIssueSchema),
39155
+ durationMs: numberType()
39156
+ }).passthrough();
39157
+ /** Shared Validate summary: full-run totals plus per-type totals, never the filtered view. */
39158
+ var CliValidateSummarySchema = objectType({
39159
+ totals: CliValidationTotalsSchema,
39160
+ byType: recordType(CliValidationTotalsSchema)
39161
+ }).passthrough();
39147
39162
  /** Typed ordinary Validate report, also used by 1.9 `validate --archived --json`. */
39148
39163
  var CliValidateReportSchema = objectType({
39149
- items: arrayType(objectType({
39150
- id: stringType(),
39151
- type: enumType(["change", "spec"]),
39152
- valid: booleanType(),
39153
- issues: arrayType(CliValidationIssueSchema),
39154
- durationMs: numberType()
39155
- }).passthrough()),
39156
- summary: objectType({
39157
- totals: CliValidationTotalsSchema,
39158
- byType: recordType(CliValidationTotalsSchema)
39159
- }).passthrough(),
39164
+ items: arrayType(CliValidateItemSchema),
39165
+ summary: CliValidateSummarySchema,
39160
39166
  version: stringType(),
39161
39167
  root: CliRootSchema
39162
39168
  }).passthrough();
39163
39169
  unionType([CliValidateReportSchema, CliDiagnosticFailureSchema]);
39170
+ /**
39171
+ * Typed OpenSpec 1.12 `validate --report findings` document.
39172
+ *
39173
+ * The findings report is a filtered evidence transport beside the full report, never the
39174
+ * validation truth: `itemFindings` carries only items with issues, while `summary` and
39175
+ * `root` stay the full-run values the CLI computed over every item in scope.
39176
+ * `report.returnedItems`/`report.totalItems` distinguish the filtered view from the run
39177
+ * size, and the process exit code keeps the full-run rule (`failed > 0 -> 1`), so decoding
39178
+ * never consults it. An empty scope is the success document
39179
+ * `{ returnedItems: 0, totalItems: 0, itemFindings: [] }`, not a failure sum type.
39180
+ *
39181
+ * Two upstream-guaranteed invariants are decode-level facts (pinned v1.12.0
39182
+ * `projectValidationFindings`): every `itemFindings` entry carries at least one issue
39183
+ * (upstream filters `item.issues.length > 0`), and `returnedItems` never exceeds
39184
+ * `totalItems` (the filtered view is a subset of the full run). Upstream also happens to
39185
+ * set `returnedItems === itemFindings.length` today; that equality stays unasserted so a
39186
+ * future patch-level count adjustment inside the admitted range cannot fabricate a
39187
+ * contract error out of otherwise well-formed CLI evidence.
39188
+ */
39189
+ var CliValidateFindingsSchema = objectType({
39190
+ report: objectType({
39191
+ kind: literalType("validation-findings"),
39192
+ version: stringType(),
39193
+ scope: enumType([
39194
+ "all",
39195
+ "changes",
39196
+ "specs",
39197
+ "archived"
39198
+ ]),
39199
+ returnedItems: numberType(),
39200
+ totalItems: numberType()
39201
+ }).passthrough(),
39202
+ itemFindings: arrayType(CliValidateItemSchema),
39203
+ summary: CliValidateSummarySchema,
39204
+ root: CliRootSchema
39205
+ }).passthrough().superRefine((document, ctx) => {
39206
+ if (document.report.returnedItems > document.report.totalItems) ctx.addIssue({
39207
+ code: ZodIssueCode.custom,
39208
+ path: ["report", "returnedItems"],
39209
+ message: `returnedItems (${document.report.returnedItems}) must not exceed totalItems (${document.report.totalItems}).`
39210
+ });
39211
+ document.itemFindings.forEach((finding, index) => {
39212
+ if (finding.issues.length === 0) ctx.addIssue({
39213
+ code: ZodIssueCode.custom,
39214
+ path: [
39215
+ "itemFindings",
39216
+ index,
39217
+ "issues"
39218
+ ],
39219
+ message: "Every findings item must carry at least one issue."
39220
+ });
39221
+ });
39222
+ });
39223
+ /**
39224
+ * Typed findings or request-failure result of `validate --report findings --json`.
39225
+ *
39226
+ * Invalid requests (no bulk scope, an item name, archived+active mixing, or an unknown
39227
+ * report value) produce the shared status-array failure envelope with code
39228
+ * `invalid_validation_report_request`, decoded here through the shared diagnostic
39229
+ * failure schema including its optional `fix` string.
39230
+ */
39231
+ var CliValidateFindingsResultSchema = unionType([CliValidateFindingsSchema, CliDiagnosticFailureSchema]);
39232
+ /**
39233
+ * Whether a findings result is the findings document rather than the request-failure
39234
+ * envelope. Passthrough tolerance means a failure envelope may legally carry unknown
39235
+ * keys, so mere `report`-key presence cannot discriminate the union: the guard validates
39236
+ * the upstream discriminator shape — `report` is an object whose `kind` is the
39237
+ * `validation-findings` literal and whose count fields are numbers.
39238
+ *
39239
+ * The input is deliberately `unknown`: route and evidence consumers receive the union
39240
+ * of every validate transport (`CliValidate | CliValidateFindingsResult | null`), so the
39241
+ * guard must accept the consumed boundary, not only the already-narrowed findings union.
39242
+ * It stays a cheap shape check, never a second decode: schema-level invariants
39243
+ * (issue presence, count bounds) belong to `CliValidateFindingsSchema` alone.
39244
+ */
39245
+ function isCliValidateFindings(result) {
39246
+ if (typeof result !== "object" || result === null) return false;
39247
+ const report = result.report;
39248
+ if (typeof report !== "object" || report === null) return false;
39249
+ const { kind, returnedItems, totalItems } = report;
39250
+ return kind === "validation-findings" && typeof returnedItems === "number" && typeof totalItems === "number";
39251
+ }
39164
39252
  var CliArchiveTotalsSchema = objectType({
39165
39253
  added: numberType(),
39166
39254
  modified: numberType(),
@@ -43257,15 +43345,19 @@ function createApplyInstructionProgress(input, trackedTaskProgress) {
43257
43345
  //#endregion
43258
43346
  //#region ../core/src/opsx-types.ts
43259
43347
  /**
43260
- * Orthogonal intents (updated 2026-08-15 Asia/Shanghai):
43348
+ * Orthogonal intents (updated 2026-09-12 Asia/Shanghai):
43261
43349
  * 1. Publish runtime schemas for final Projection Work payloads, including transformed Apply progress.
43262
43350
  * 2. Keep isPlanningComplete as the authoritative planning fact over any local tracked alias.
43263
43351
  * 3. Carry CLI status evidence, diagnostics, and per-artifact requires as typed facts.
43264
43352
  * 4. Preserve root-context and store projections as browser-safe contracts.
43265
43353
  * 5. Keep projection notices distinct from payload data so failures never masquerade as results.
43354
+ * 6. Project the OpenSpec 1.13 Apply `warnings` and `missingPrerequisites` fields through the
43355
+ * input and final projection schemas verbatim: optional everywhere, never defaulted to
43356
+ * empty arrays, and never allowed to alter state/progress/tasks semantics.
43266
43357
  *
43267
43358
  * Original request (2026-07-15): "为内核载荷建立强类型。"
43268
43359
  * Original request (2026-08-15): "v9的适配需要同时适配 1.8和1.9。"
43360
+ * Original request (2026-09-12): "Openspec 1.13.0 释放了,你更新一下,调查变更内容,然后开始规划适配工作,我们将用标准工作流worktree来推进。让 codex 参与。"
43269
43361
  */
43270
43362
  /** Runtime schema for one JSON value retained from a CLI Status stdout document. */
43271
43363
  var OpsxCliJsonValueSchema = lazyType(() => unionType([
@@ -43359,6 +43451,8 @@ var ApplyInstructionsInputSchema = objectType({
43359
43451
  "ready"
43360
43452
  ]),
43361
43453
  missingArtifacts: arrayType(stringType()).optional(),
43454
+ missingPrerequisites: arrayType(stringType()).optional(),
43455
+ warnings: arrayType(stringType()).optional(),
43362
43456
  instruction: stringType(),
43363
43457
  references: arrayType(CliReferenceIndexEntrySchema).optional(),
43364
43458
  context: stringType().optional(),
@@ -43408,6 +43502,8 @@ var ApplyInstructionsProjectionSchema = objectType({
43408
43502
  "ready"
43409
43503
  ]),
43410
43504
  missingArtifacts: arrayType(stringType()).optional(),
43505
+ missingPrerequisites: arrayType(stringType()).optional(),
43506
+ warnings: arrayType(stringType()).optional(),
43411
43507
  instruction: stringType(),
43412
43508
  references: arrayType(CliReferenceIndexEntrySchema).optional(),
43413
43509
  context: stringType().optional(),
@@ -46880,6 +46976,32 @@ var ListChecks = createLucideIcon("ListChecks", [
46880
46976
  key: "oe0vm4"
46881
46977
  }]
46882
46978
  ]);
46979
+ var ListOrdered = createLucideIcon("ListOrdered", [
46980
+ ["path", {
46981
+ d: "M10 12h11",
46982
+ key: "6m4ad9"
46983
+ }],
46984
+ ["path", {
46985
+ d: "M10 18h11",
46986
+ key: "11hvi2"
46987
+ }],
46988
+ ["path", {
46989
+ d: "M10 6h11",
46990
+ key: "c7qv1k"
46991
+ }],
46992
+ ["path", {
46993
+ d: "M4 10h2",
46994
+ key: "16xx2s"
46995
+ }],
46996
+ ["path", {
46997
+ d: "M4 6h1v4",
46998
+ key: "cnovpq"
46999
+ }],
47000
+ ["path", {
47001
+ d: "M6 18H4c0-1 2-2 2-3s-1-1.5-2-1",
47002
+ key: "m9a95d"
47003
+ }]
47004
+ ]);
46883
47005
  var ListTodo = createLucideIcon("ListTodo", [
46884
47006
  ["rect", {
46885
47007
  x: "3",
@@ -47051,6 +47173,20 @@ var Moon = createLucideIcon("Moon", [["path", {
47051
47173
  d: "M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z",
47052
47174
  key: "a7tn18"
47053
47175
  }]]);
47176
+ var OctagonAlert = createLucideIcon("OctagonAlert", [
47177
+ ["path", {
47178
+ d: "M12 16h.01",
47179
+ key: "1drbdi"
47180
+ }],
47181
+ ["path", {
47182
+ d: "M12 8v4",
47183
+ key: "1got3b"
47184
+ }],
47185
+ ["path", {
47186
+ d: "M15.312 2a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586l-4.688-4.688A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2z",
47187
+ key: "1fd625"
47188
+ }]
47189
+ ]);
47054
47190
  var PackageOpen = createLucideIcon("PackageOpen", [
47055
47191
  ["path", {
47056
47192
  d: "M12 22v-9",
@@ -71180,7 +71316,7 @@ var browserExt = {
71180
71316
  },
71181
71317
  test: () => true,
71182
71318
  load: async () => {
71183
- await import("./browserAll-B9JXZQ_b.js");
71319
+ await import("./browserAll-BoaMSEnC.js");
71184
71320
  }
71185
71321
  };
71186
71322
  //#endregion
@@ -71193,7 +71329,7 @@ var webworkerExt = {
71193
71329
  },
71194
71330
  test: () => typeof self !== "undefined" && self.WorkerGlobalScope !== void 0,
71195
71331
  load: async () => {
71196
- await import("./webworkerAll-DukCMCoQ.js");
71332
+ await import("./webworkerAll-bAKoC1FD.js");
71197
71333
  }
71198
71334
  };
71199
71335
  //#endregion
@@ -73787,7 +73923,7 @@ async function autoDetectRenderer(options) {
73787
73923
  for (let i = 0; i < preferredOrder.length; i++) {
73788
73924
  const rendererType = preferredOrder[i];
73789
73925
  if (rendererType === "webgpu" && await isWebGPUSupported()) {
73790
- const { WebGPURenderer } = await import("./WebGPURenderer-C6g3K2oe.js");
73926
+ const { WebGPURenderer } = await import("./WebGPURenderer-BaTRp8M6.js");
73791
73927
  RendererClass = WebGPURenderer;
73792
73928
  finalOptions = {
73793
73929
  ...options,
@@ -73795,7 +73931,7 @@ async function autoDetectRenderer(options) {
73795
73931
  };
73796
73932
  break;
73797
73933
  } else if (rendererType === "webgl" && isWebGLSupported(options.failIfMajorPerformanceCaveat ?? AbstractRenderer.defaultOptions.failIfMajorPerformanceCaveat)) {
73798
- const { WebGLRenderer } = await import("./WebGLRenderer-jIngAd_2.js");
73934
+ const { WebGLRenderer } = await import("./WebGLRenderer-ZTMKqKjr.js");
73799
73935
  RendererClass = WebGLRenderer;
73800
73936
  finalOptions = {
73801
73937
  ...options,
@@ -73803,7 +73939,7 @@ async function autoDetectRenderer(options) {
73803
73939
  };
73804
73940
  break;
73805
73941
  } else if (rendererType === "canvas") {
73806
- const { CanvasRenderer } = await import("./CanvasRenderer-Bvd3pXBF.js");
73942
+ const { CanvasRenderer } = await import("./CanvasRenderer-CvVvHnla.js");
73807
73943
  RendererClass = CanvasRenderer;
73808
73944
  finalOptions = {
73809
73945
  ...options,
@@ -97552,7 +97688,7 @@ var TerminalController = class {
97552
97688
  if (this.configPersistTimer) clearTimeout(this.configPersistTimer);
97553
97689
  this.configPersistTimer = setTimeout(() => {
97554
97690
  this.configPersistTimer = null;
97555
- import("./trpc-CbiCXi-L.js").then(({ trpcClient }) => {
97691
+ import("./trpc-BQ6eyI7t.js").then(({ trpcClient }) => {
97556
97692
  trpcClient.config.update.mutate({ terminal: { fontSize: this.config.fontSize } });
97557
97693
  }).catch(() => {});
97558
97694
  }, CONFIG_PERSIST_DEBOUNCE);
@@ -108113,7 +108249,7 @@ var languages = [
108113
108249
  name: "CSS",
108114
108250
  extensions: ["css"],
108115
108251
  load() {
108116
- return import("./dist-1rQWAJV4.js").then((m) => m.css());
108252
+ return import("./dist-fy1m8mbf.js").then((m) => m.css());
108117
108253
  }
108118
108254
  }),
108119
108255
  /* @__PURE__ */ LanguageDescription.of({
@@ -108133,7 +108269,7 @@ var languages = [
108133
108269
  "hbs"
108134
108270
  ],
108135
108271
  load() {
108136
- return import("./dist-D6j5GTM2.js").then((m) => m.html());
108272
+ return import("./dist-C4EXY8oH.js").then((m) => m.html());
108137
108273
  }
108138
108274
  }),
108139
108275
  /* @__PURE__ */ LanguageDescription.of({
@@ -108167,7 +108303,7 @@ var languages = [
108167
108303
  "jinja2"
108168
108304
  ],
108169
108305
  load() {
108170
- return import("./dist-D5RQw1xh.js").then((m) => m.jinja());
108306
+ return import("./dist-BTp4dJw4.js").then((m) => m.jinja());
108171
108307
  }
108172
108308
  }),
108173
108309
  /* @__PURE__ */ LanguageDescription.of({
@@ -108175,7 +108311,7 @@ var languages = [
108175
108311
  alias: ["json5"],
108176
108312
  extensions: ["json", "map"],
108177
108313
  load() {
108178
- return import("./dist-BIgXEKIS.js").then((m) => m.json());
108314
+ return import("./dist-DAIXBI5T.js").then((m) => m.json());
108179
108315
  }
108180
108316
  }),
108181
108317
  /* @__PURE__ */ LanguageDescription.of({
@@ -108189,14 +108325,14 @@ var languages = [
108189
108325
  name: "LESS",
108190
108326
  extensions: ["less"],
108191
108327
  load() {
108192
- return import("./dist-BhaY9Mk5.js").then((m) => m.less());
108328
+ return import("./dist-DQpyDhfS.js").then((m) => m.less());
108193
108329
  }
108194
108330
  }),
108195
108331
  /* @__PURE__ */ LanguageDescription.of({
108196
108332
  name: "Liquid",
108197
108333
  extensions: ["liquid"],
108198
108334
  load() {
108199
- return import("./dist-BjB76DhT.js").then((m) => m.liquid());
108335
+ return import("./dist-CHiBYKhO.js").then((m) => m.liquid());
108200
108336
  }
108201
108337
  }),
108202
108338
  /* @__PURE__ */ LanguageDescription.of({
@@ -108213,7 +108349,7 @@ var languages = [
108213
108349
  "mkd"
108214
108350
  ],
108215
108351
  load() {
108216
- return import("./dist-D4O-5WhW.js").then((m) => m.markdown());
108352
+ return import("./dist-DVnu9zoA.js").then((m) => m.markdown());
108217
108353
  }
108218
108354
  }),
108219
108355
  /* @__PURE__ */ LanguageDescription.of({
@@ -108239,7 +108375,7 @@ var languages = [
108239
108375
  "phtml"
108240
108376
  ],
108241
108377
  load() {
108242
- return import("./dist-CbRRi2nf.js").then((m) => m.php());
108378
+ return import("./dist-CUmPwPDw.js").then((m) => m.php());
108243
108379
  }
108244
108380
  }),
108245
108381
  /* @__PURE__ */ LanguageDescription.of({
@@ -108279,14 +108415,14 @@ var languages = [
108279
108415
  name: "Sass",
108280
108416
  extensions: ["sass"],
108281
108417
  load() {
108282
- return import("./dist-BJhwVaSw.js").then((m) => m.sass({ indented: true }));
108418
+ return import("./dist-Bi2hyX2D.js").then((m) => m.sass({ indented: true }));
108283
108419
  }
108284
108420
  }),
108285
108421
  /* @__PURE__ */ LanguageDescription.of({
108286
108422
  name: "SCSS",
108287
108423
  extensions: ["scss"],
108288
108424
  load() {
108289
- return import("./dist-BJhwVaSw.js").then((m) => m.sass());
108425
+ return import("./dist-Bi2hyX2D.js").then((m) => m.sass());
108290
108426
  }
108291
108427
  }),
108292
108428
  /* @__PURE__ */ LanguageDescription.of({
@@ -108353,7 +108489,7 @@ var languages = [
108353
108489
  alias: ["yml"],
108354
108490
  extensions: ["yaml", "yml"],
108355
108491
  load() {
108356
- return import("./dist-CzCglUOQ.js").then((m) => m.yaml());
108492
+ return import("./dist-CIVGOe5c.js").then((m) => m.yaml());
108357
108493
  }
108358
108494
  }),
108359
108495
  /* @__PURE__ */ LanguageDescription.of({
@@ -109240,13 +109376,13 @@ var languages = [
109240
109376
  name: "Vue",
109241
109377
  extensions: ["vue"],
109242
109378
  load() {
109243
- return import("./dist-CXVf0s87.js").then((m) => m.vue());
109379
+ return import("./dist-D_mnjXV3.js").then((m) => m.vue());
109244
109380
  }
109245
109381
  }),
109246
109382
  /* @__PURE__ */ LanguageDescription.of({
109247
109383
  name: "Angular Template",
109248
109384
  load() {
109249
- return import("./dist-CX9PVvRC.js").then((m) => m.angular());
109385
+ return import("./dist-CLOFOKCn.js").then((m) => m.angular());
109250
109386
  }
109251
109387
  })
109252
109388
  ];
@@ -169958,6 +170094,36 @@ function ChangeRowChevron() {
169958
170094
  });
169959
170095
  }
169960
170096
  //#endregion
170097
+ //#region src/lib/change-display-title.ts
170098
+ /**
170099
+ * Orthogonal intents (created 2026-09-12 Asia/Shanghai):
170100
+ * 1. Derive one shared display title for a Change across list, dashboard, and detail surfaces.
170101
+ * 2. Treat the proposal H1 as a human-readable title only when it is informative.
170102
+ * 3. Fall back to the change id (the CLI's own canonical name) otherwise.
170103
+ *
170104
+ * Original request (2026-09-12): Owner walkthrough: the Changes list showed the generic proposal
170105
+ * heading "Proposal" as the row title while Change Detail showed the change id — unify the scheme.
170106
+ */
170107
+ /**
170108
+ * Heading texts that carry no identity information. `openspec new change` scaffolds proposals with
170109
+ * the bare heading "# Proposal"; showing it as a row title reads as a parsing bug rather than a name.
170110
+ */
170111
+ var GENERIC_PROPOSAL_HEADINGS = new Set(["proposal"]);
170112
+ /**
170113
+ * One display title for a Change, identical on every surface.
170114
+ *
170115
+ * `name` is the legacy parser's proposal H1 (absent for parser-less custom schemas); the change id
170116
+ * is the CLI-owned canonical identity (`openspec list --json` names changes by directory). The H1
170117
+ * wins only when it is a real, differentiated title; generic headings and the id itself fall back
170118
+ * to the id, so no surface ever shows two different titles for the same Change.
170119
+ */
170120
+ function changeDisplayTitle(changeId, name) {
170121
+ const trimmed = name?.trim();
170122
+ if (!trimmed || trimmed === changeId) return changeId;
170123
+ if (GENERIC_PROPOSAL_HEADINGS.has(trimmed.toLowerCase())) return changeId;
170124
+ return trimmed;
170125
+ }
170126
+ //#endregion
169961
170127
  //#region src/lib/change-workflow-phase.ts
169962
170128
  function classifyChangeWorkflowPhase(params) {
169963
170129
  if (params.hasStatus && params.trackedArtifactStatus === "blocked") return {
@@ -170080,6 +170246,8 @@ function useChangeListContinuity(incomingChanges, containerRef) {
170080
170246
  * Original request (2026-07-21): "Changes页面的右上角没有 New,你要不要快速补一个"
170081
170247
 
170082
170248
  * Original request (2026-08-15): "v9的适配需要同时适配 1.8和1.9。"
170249
+ * Original request (2026-09-12): Owner walkthrough: unify the Change display title — generic
170250
+ * "# Proposal" headings fall back to the change id on every surface.
170083
170251
  */
170084
170252
  function buildStatusMap(statuses) {
170085
170253
  return new Map((statuses ?? []).map((status) => [status.changeName, status]));
@@ -170229,7 +170397,7 @@ function ChangeList() {
170229
170397
  __vtHandoff: {
170230
170398
  family: "changes",
170231
170399
  entityId: change.id,
170232
- title: change.name,
170400
+ title: changeDisplayTitle(change.id, change.name),
170233
170401
  subtitle: change.id
170234
170402
  }
170235
170403
  }),
@@ -170240,7 +170408,7 @@ function ChangeList() {
170240
170408
  className: "flex items-center gap-3",
170241
170409
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeRow, {
170242
170410
  changeId: change.id,
170243
- name: change.name,
170411
+ name: changeDisplayTitle(change.id, change.name),
170244
170412
  phase,
170245
170413
  updatedAt: change.updatedAt,
170246
170414
  formatTime: formatRelativeTime,
@@ -171286,16 +171454,27 @@ function EvidenceDisclosure({ title, children, summary, defaultOpen = false, cla
171286
171454
  //#endregion
171287
171455
  //#region src/components/apply-progress-notice.tsx
171288
171456
  /**
171289
- * Orthogonal intents (updated 2026-08-15 Asia/Shanghai):
171457
+ * Orthogonal intents (updated 2026-09-12 Asia/Shanghai):
171290
171458
  * 1. Attribute Apply instruction counts to the upstream Apply command.
171291
171459
  * 2. Compress agreement to one subtitle badge; keep divergence a direct blocker.
171292
171460
  * 3. Keep divergence's two objective source counts side by side with their causes.
171293
171461
  * 4. Keep tooltips as the keyboard-reachable explanation for every compact count.
171462
+ * 5. Render OpenSpec 1.13 Apply `warnings`/`missingPrerequisites` as ONE always-visible summary
171463
+ * row (count + build-order chain, CLI attribution) whose verbatim evidence is one explicit
171464
+ * expansion away on the same direct plane — advisory guidance must stay discoverable without
171465
+ * consuming the page; a Tooltip-only surface remains forbidden.
171466
+ * 6. Keep `missingPrerequisites` visually and semantically distinct from blockers (status
171467
+ * semantics), including when the Apply state is already `ready`.
171468
+ * 7. Degrade to the previous presentation when either 1.13 field is absent — absent keys
171469
+ * are the upstream encoding for "none", so no empty state is ever synthesized.
171294
171470
  *
171295
171471
  * Original request (2026-07-15): "与 tracked glob 进度分歧时各自归因展示。"
171296
171472
  * Original request (2026-07-28): supporting 6.x evidence should use Badge + Tooltip or Accordion.
171297
171473
  * Original request (2026-08-15): Owner walkthrough: agreement is one badge in the subtitle row,
171298
171474
  * not a two-line block; only divergence owns a notice.
171475
+ * Original request (2026-09-12): "Openspec 1.13.0 释放了,你更新一下,调查变更内容,然后开始规划适配工作,我们将用标准工作流worktree来推进。让 codex 参与。"
171476
+ * Original request (2026-09-12): Owner walkthrough: the always-expanded warning/build-order blocks
171477
+ * consumed the page; collapse them behind one summary row while keeping direct-plane discovery.
171299
171478
  */
171300
171479
  /**
171301
171480
  * One compact, source-attributed Apply progress badge for the Change subtitle row.
@@ -171316,54 +171495,143 @@ function ApplyProgressBadge({ applyInstructionProgress }) {
171316
171495
  ]
171317
171496
  });
171318
171497
  }
171498
+ /** Upstream command that owns every fact rendered by these notices. */
171499
+ var APPLY_COMMAND_ATTRIBUTION = "openspec instructions apply";
171500
+ var GUIDANCE_DETAIL_ID = "apply-readiness-guidance-detail";
171319
171501
  /**
171320
- * Render the Apply/tracked divergence as one direct, source-attributed blocker. Returns
171321
- * null when the sources agree — the agreement case lives in the subtitle badge row via
171322
- * {@link ApplyProgressBadge}.
171502
+ * Render the Apply/tracked divergence as one direct, source-attributed blocker, plus the
171503
+ * OpenSpec 1.13 `warnings` and `missingPrerequisites` evidence as one collapsible summary row:
171504
+ * the row itself names the warning count and the build-order chain (discovery needs no hover),
171505
+ * and expanding reveals the verbatim upstream evidence on the same direct plane.
171506
+ * Returns null when none apply — the agreement case lives in the subtitle badge row via
171507
+ * {@link ApplyProgressBadge}, and absent 1.13 keys render nothing.
171323
171508
  */
171324
- function ApplyProgressNotice({ applyInstructionProgress }) {
171509
+ function ApplyProgressNotice({ applyInstructionProgress, warnings, missingPrerequisites }) {
171325
171510
  const divergence = applyInstructionProgress.divergence;
171326
- if (!divergence) return null;
171327
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171328
- role: "status",
171329
- "aria-label": "Task progress source divergence",
171330
- className: "flex min-w-0 items-start gap-2 border border-amber-300 bg-amber-50 px-3 py-2 text-xs text-amber-950 dark:border-amber-700 dark:bg-amber-950/40 dark:text-amber-100",
171331
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, {
171332
- className: "mt-0.5 h-4 w-4 shrink-0",
171333
- "aria-hidden": "true"
171334
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171335
- className: "min-w-0 space-y-2",
171511
+ const hasWarnings = (warnings?.length ?? 0) > 0;
171512
+ const hasPrerequisites = (missingPrerequisites?.length ?? 0) > 0;
171513
+ const [expanded, setExpanded] = (0, import_react.useState)(false);
171514
+ if (!divergence && !hasWarnings && !hasPrerequisites) return null;
171515
+ const guidanceSummaryParts = [];
171516
+ if (hasWarnings) {
171517
+ const count = warnings.length;
171518
+ guidanceSummaryParts.push(`${count} apply warning${count > 1 ? "s" : ""}`);
171519
+ }
171520
+ if (hasPrerequisites) guidanceSummaryParts.push(`next in build order: ${missingPrerequisites.join(" → ")}`);
171521
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
171522
+ hasWarnings || hasPrerequisites ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171523
+ role: "status",
171524
+ "data-apply-notice": "summary",
171525
+ "aria-label": `Apply readiness guidance from ${APPLY_COMMAND_ATTRIBUTION}`,
171526
+ className: hasWarnings ? "flex min-w-0 items-center gap-2 border border-amber-300 bg-amber-50 px-3 py-1.5 text-xs text-amber-950 dark:border-amber-700 dark:bg-amber-950/40 dark:text-amber-100" : "text-muted-foreground flex min-w-0 items-center gap-2 rounded-md border px-3 py-1.5 text-xs",
171336
171527
  children: [
171337
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
171338
- className: "font-medium",
171339
- children: "Upstream task progress divergence"
171528
+ hasWarnings ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, {
171529
+ className: "h-4 w-4 shrink-0",
171530
+ "aria-hidden": "true"
171531
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ListOrdered, {
171532
+ className: "h-4 w-4 shrink-0",
171533
+ "aria-hidden": "true"
171340
171534
  }),
171341
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: divergence.message }),
171342
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171343
- className: "flex flex-wrap gap-1.5",
171344
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(InformationBadge, {
171345
- ariaLabel: `Apply instructions progress ${applyInstructionProgress.complete} of ${applyInstructionProgress.total}`,
171346
- tooltip: "Progress reported by openspec instructions apply.",
171347
- children: [
171348
- "Apply ",
171349
- applyInstructionProgress.complete,
171350
- "/",
171351
- applyInstructionProgress.total
171352
- ]
171353
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(InformationBadge, {
171354
- ariaLabel: `Tracked artifact glob progress ${divergence.tracked.completed} of ${divergence.tracked.total}`,
171355
- tooltip: "Progress computed from the workflow's tracked task artifact glob.",
171356
- children: [
171357
- "Tracked ",
171358
- divergence.tracked.completed,
171359
- "/",
171360
- divergence.tracked.total
171361
- ]
171535
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
171536
+ type: "button",
171537
+ onClick: () => setExpanded((value) => !value),
171538
+ "aria-expanded": expanded,
171539
+ "aria-controls": GUIDANCE_DETAIL_ID,
171540
+ className: "flex min-w-0 flex-1 cursor-pointer items-center gap-2 text-left",
171541
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
171542
+ className: "truncate font-medium",
171543
+ children: guidanceSummaryParts.join(" · ")
171544
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
171545
+ className: "text-muted-foreground shrink-0 font-normal",
171546
+ children: ["— ", APPLY_COMMAND_ATTRIBUTION]
171362
171547
  })]
171548
+ }),
171549
+ expanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronDown, {
171550
+ className: "h-4 w-4 shrink-0",
171551
+ "aria-hidden": "true"
171552
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronRight, {
171553
+ className: "h-4 w-4 shrink-0",
171554
+ "aria-hidden": "true"
171363
171555
  })
171364
171556
  ]
171365
- })]
171366
- });
171557
+ }) : null,
171558
+ expanded && (hasWarnings || hasPrerequisites) ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171559
+ id: GUIDANCE_DETAIL_ID,
171560
+ className: "text-muted-foreground space-y-2 rounded-md border px-3 py-2 text-xs",
171561
+ children: [hasWarnings ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171562
+ "data-apply-notice": "warnings",
171563
+ className: "min-w-0 space-y-1",
171564
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171565
+ className: "text-foreground font-medium",
171566
+ children: ["Apply warnings — reported by ", APPLY_COMMAND_ATTRIBUTION]
171567
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", {
171568
+ className: "space-y-1",
171569
+ children: warnings?.map((warning) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", {
171570
+ className: "break-words",
171571
+ children: warning
171572
+ }, warning))
171573
+ })]
171574
+ }) : null, hasPrerequisites ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171575
+ "data-apply-notice": "build-order",
171576
+ className: "min-w-0 space-y-1",
171577
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171578
+ className: "text-foreground font-medium",
171579
+ children: ["Next in build order — reported by ", APPLY_COMMAND_ATTRIBUTION]
171580
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
171581
+ className: "flex flex-wrap items-center gap-1",
171582
+ children: missingPrerequisites?.map((artifactId, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.Fragment, { children: [index > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
171583
+ className: "text-muted-foreground/70",
171584
+ "aria-hidden": "true",
171585
+ children: "→"
171586
+ }) : null, /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
171587
+ className: "bg-muted break-words rounded border px-1 py-0.5 font-mono [overflow-wrap:anywhere]",
171588
+ children: artifactId
171589
+ })] }, artifactId))
171590
+ })]
171591
+ }) : null]
171592
+ }) : null,
171593
+ divergence ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171594
+ role: "status",
171595
+ "data-apply-notice": "divergence",
171596
+ "aria-label": "Task progress source divergence",
171597
+ className: "flex min-w-0 items-start gap-2 border border-amber-300 bg-amber-50 px-3 py-2 text-xs text-amber-950 dark:border-amber-700 dark:bg-amber-950/40 dark:text-amber-100",
171598
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, {
171599
+ className: "mt-0.5 h-4 w-4 shrink-0",
171600
+ "aria-hidden": "true"
171601
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171602
+ className: "min-w-0 space-y-2",
171603
+ children: [
171604
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
171605
+ className: "font-medium",
171606
+ children: "Upstream task progress divergence"
171607
+ }),
171608
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: divergence.message }),
171609
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171610
+ className: "flex flex-wrap gap-1.5",
171611
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(InformationBadge, {
171612
+ ariaLabel: `Apply instructions progress ${applyInstructionProgress.complete} of ${applyInstructionProgress.total}`,
171613
+ tooltip: "Progress reported by openspec instructions apply.",
171614
+ children: [
171615
+ "Apply ",
171616
+ applyInstructionProgress.complete,
171617
+ "/",
171618
+ applyInstructionProgress.total
171619
+ ]
171620
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(InformationBadge, {
171621
+ ariaLabel: `Tracked artifact glob progress ${divergence.tracked.completed} of ${divergence.tracked.total}`,
171622
+ tooltip: "Progress computed from the workflow's tracked task artifact glob.",
171623
+ children: [
171624
+ "Tracked ",
171625
+ divergence.tracked.completed,
171626
+ "/",
171627
+ divergence.tracked.total
171628
+ ]
171629
+ })]
171630
+ })
171631
+ ]
171632
+ })]
171633
+ }) : null
171634
+ ] });
171367
171635
  }
171368
171636
  //#endregion
171369
171637
  //#region src/components/change-context-summary.tsx
@@ -171483,17 +171751,31 @@ function ChangeReferenceFailureNotice({ referenceEvidence }) {
171483
171751
  });
171484
171752
  }
171485
171753
  //#endregion
171754
+ //#region src/components/evidence-layer-header.tsx
171755
+ function EvidenceLayerHeader({ title, summary }) {
171756
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
171757
+ className: "border-border mb-4 flex min-w-0 flex-wrap items-baseline justify-between gap-x-3 gap-y-1 border-b py-2.5",
171758
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", {
171759
+ className: "min-w-0 text-sm font-semibold tracking-tight",
171760
+ children: title
171761
+ }), summary ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
171762
+ className: "text-muted-foreground min-w-0 text-[11px]",
171763
+ children: summary
171764
+ }) : null]
171765
+ });
171766
+ }
171767
+ //#endregion
171486
171768
  //#region ../core/src/openspec-compat.ts
171487
- var OPENSPEC_CLI_TARGET_SERIES = "1.11";
171488
- var OPENSPEC_CLI_SUPPORTED_SERIES = ["1.10", "1.11"];
171489
- var OPENSPEC_CLI_ACCEPTED_RANGE = ">=1.10.0 <1.12.0";
171769
+ var OPENSPEC_CLI_TARGET_SERIES = "1.13";
171770
+ var OPENSPEC_CLI_SUPPORTED_SERIES = ["1.13"];
171771
+ var OPENSPEC_CLI_ACCEPTED_RANGE = ">=1.13.0 <1.14.0";
171490
171772
  /**
171491
171773
  * Derive command capabilities from one parsed CLI version.
171492
171774
  *
171493
171775
  * Only an admitted version — stable inside the accepted range — can select version-specific
171494
- * capabilities. Unsupported forms (prereleases, >=1.12, below-range) and unparseable output
171776
+ * capabilities. Unsupported forms (prereleases, >=1.14, below-range) and unparseable output
171495
171777
  * keep their mismatch evidence and expose no capability, so a page-level version bypass can
171496
- * never manufacture a 1.11 command surface for a CLI the release line does not admit.
171778
+ * never manufacture a 1.13 command surface for a CLI the release line does not admit.
171497
171779
  */
171498
171780
  function deriveOpenSpecCliCapabilities(version) {
171499
171781
  if (!isAdmittedVersion(version)) return {
@@ -171501,7 +171783,8 @@ function deriveOpenSpecCliCapabilities(version) {
171501
171783
  archivedValidation: false,
171502
171784
  initLanguage: false,
171503
171785
  batchStatus: false,
171504
- requirementDiff: false
171786
+ requirementDiff: false,
171787
+ findingsReport: false
171505
171788
  };
171506
171789
  const onTargetSeries = isSeries(version, OPENSPEC_CLI_TARGET_SERIES);
171507
171790
  return {
@@ -171509,7 +171792,8 @@ function deriveOpenSpecCliCapabilities(version) {
171509
171792
  archivedValidation: true,
171510
171793
  initLanguage: true,
171511
171794
  batchStatus: onTargetSeries,
171512
- requirementDiff: onTargetSeries
171795
+ requirementDiff: onTargetSeries,
171796
+ findingsReport: onTargetSeries
171513
171797
  };
171514
171798
  }
171515
171799
  function parseOpenSpecCliVersion(raw) {
@@ -171533,7 +171817,7 @@ function isStable(version) {
171533
171817
  /** True only for stable versions inside the accepted range (current or supported non-current). */
171534
171818
  function isAdmittedVersion(version) {
171535
171819
  if (!version || !isStable(version)) return false;
171536
- return isSeries(version, "1.11") || isSupportedNonCurrentSeries(version);
171820
+ return isSeries(version, "1.13") || isSupportedNonCurrentSeries(version);
171537
171821
  }
171538
171822
  function isSupportedNonCurrentSeries(version) {
171539
171823
  return OPENSPEC_CLI_SUPPORTED_SERIES.filter((series) => series !== OPENSPEC_CLI_TARGET_SERIES).some((series) => isSeries(version, series));
@@ -171541,12 +171825,12 @@ function isSupportedNonCurrentSeries(version) {
171541
171825
  //#endregion
171542
171826
  //#region src/components/archived-validation-evidence.tsx
171543
171827
  /**
171544
- * Orthogonal intents (updated 2026-08-28 Asia/Shanghai):
171828
+ * Orthogonal intents (updated 2026-09-12 Asia/Shanghai):
171545
171829
  * 1. Present OpenSpec `validate --archived --json` as typed CLI evidence.
171546
171830
  * 2. Preserve item issues, totals, root, and exit/failure evidence without repair actions.
171547
171831
  * 3. Identify the evidence as unavailable in static snapshots instead of fabricating it.
171548
- * 4. Derive the capability from the detected admitted CLI; both admitted v11 lines (1.10 and
171549
- * 1.11) declare it, so the unavailable branch names the accepted range, not one series.
171832
+ * 4. Derive the capability from the detected admitted CLI; the admitted 1.13 line declares
171833
+ * it, so the unavailable branch names the accepted range, not one series.
171550
171834
  * 5. Validate report payloads with the Core contract schema, never shallow shape guards.
171551
171835
  * 6. Mount directly inside the Evidence workspace detail pane: the Accordion shell is gone, the
171552
171836
  * section header keeps the title and summary facts, and `onChip` reports only derived facts
@@ -171555,6 +171839,9 @@ function isSupportedNonCurrentSeries(version) {
171555
171839
  * Original request (2026-08-15): "v9的适配需要同时适配 1.8和1.9。"
171556
171840
  * Original request (2026-08-28): "直接将 0.10.0 和 0.11.0 一起适配,然后发布 v11。"
171557
171841
  * Original request (2026-08-28): "使用移动端的 list-detail 思维……分成两栏,左侧 list,右侧详情。这种结构替代手风琴会更好"
171842
+ * Original request (2026-09-03): "Openspec 1.12.0 刚刚放出来,你更新一下,调查变更内容,然后开始规划适配工作,我们将用标准工作流worktree来推进"
171843
+ * Owner walkthrough correction (2026-09-04): every Evidence detail layer renders the shared EvidenceLayerHeader contract (title dominant over body, house-standard border padding); this replaces each layer's local weak header.
171844
+ * Original request (2026-09-12): "Openspec 1.13.0 释放了,你更新一下,调查变更内容,然后开始规划适配工作,我们将用标准工作流worktree来推进。让 codex 参与。"
171558
171845
  */
171559
171846
  function parseValidationReport$1(value) {
171560
171847
  const parsed = CliValidateReportSchema.safeParse(value);
@@ -171586,7 +171873,7 @@ function IssueList$1({ issues }) {
171586
171873
  }, index))
171587
171874
  });
171588
171875
  }
171589
- function RunButton$1({ pending, label, onRun }) {
171876
+ function RunButton$2({ pending, label, onRun }) {
171590
171877
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
171591
171878
  type: "button",
171592
171879
  onClick: onRun,
@@ -171612,17 +171899,11 @@ function ArchivedValidationSection({ summary, children }) {
171612
171899
  "data-evidence-section": "archived-validation",
171613
171900
  "aria-label": "Archived validation",
171614
171901
  className: "min-w-0",
171615
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
171616
- className: "border-border/60 flex min-w-0 flex-wrap items-baseline justify-between gap-x-3 gap-y-1 border-b pb-2",
171617
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", {
171618
- className: "min-w-0 text-xs font-semibold",
171619
- children: "Archived validation"
171620
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
171621
- className: "text-muted-foreground min-w-0 text-[11px]",
171622
- children: summary
171623
- })]
171902
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(EvidenceLayerHeader, {
171903
+ title: "Archived validation",
171904
+ summary
171624
171905
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
171625
- className: "min-w-0 pt-3",
171906
+ className: "min-w-0 text-xs",
171626
171907
  children
171627
171908
  })]
171628
171909
  });
@@ -171716,7 +171997,7 @@ function ArchivedValidationEvidence({ onChip } = {}) {
171716
171997
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
171717
171998
  className: "text-muted-foreground",
171718
171999
  children: "Run the official CLI's archived-task validation and keep its typed report as evidence. OpenSpecUI never repairs or archives from here."
171719
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunButton$1, {
172000
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunButton$2, {
171720
172001
  pending,
171721
172002
  label: "Validate archived tasks",
171722
172003
  onRun: () => void run()
@@ -171744,7 +172025,7 @@ function ArchivedValidationEvidence({ onChip } = {}) {
171744
172025
  className: "min-w-0 break-all",
171745
172026
  children: error ?? report?.contractError ?? schemaDiagnostic ?? report?.stderr.trim() ?? "The archived validation command failed."
171746
172027
  })]
171747
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunButton$1, {
172028
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunButton$2, {
171748
172029
  pending,
171749
172030
  label: "Rerun",
171750
172031
  onRun: () => void run()
@@ -171812,7 +172093,7 @@ function ArchivedValidationEvidence({ onChip } = {}) {
171812
172093
  })]
171813
172094
  }, item.id))
171814
172095
  }),
171815
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunButton$1, {
172096
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunButton$2, {
171816
172097
  pending,
171817
172098
  label: "Rerun",
171818
172099
  onRun: () => void run()
@@ -171824,12 +172105,13 @@ function ArchivedValidationEvidence({ onChip } = {}) {
171824
172105
  //#endregion
171825
172106
  //#region src/components/change-diff-evidence.tsx
171826
172107
  /**
171827
- * Orthogonal intents (updated 2026-08-28 Asia/Shanghai):
172108
+ * Orthogonal intents (updated 2026-09-03 Asia/Shanghai):
171828
172109
  * 1. Present the CLI-provided MODIFIED-delta `diff`/`warning` fields as Change Detail evidence.
171829
172110
  * 2. Color the unified diff body by line role (+/-/@@) without recomputing anything locally.
171830
172111
  * 3. Render the exact upstream warning text beside its diff so a near-miss never swallows evidence.
171831
- * 4. Gate the fetch on the detected admitted CLI's `requirementDiff` capability (1.11 only) and on
171832
- * live mode: static snapshots and 1.10 sessions never issue the transport call.
172112
+ * 4. Gate the fetch on the detected admitted CLI's `requirementDiff` capability (the admitted
172113
+ * 1.12 line) and on live mode: static snapshots and retired sessions never issue the
172114
+ * transport call.
171833
172115
  * 5. Degrade to the existing delta presentation when the fields are absent — no fabricated diff
171834
172116
  * or warning may appear.
171835
172117
  * 6. Mount directly inside the Evidence workspace detail pane: the Accordion shell is gone, the
@@ -171838,6 +172120,8 @@ function ArchivedValidationEvidence({ onChip } = {}) {
171838
172120
  *
171839
172121
  * Original request (2026-08-28): "直接将 0.10.0 和 0.11.0 一起适配,然后发布 v11。"
171840
172122
  * Original request (2026-08-28): "使用移动端的 list-detail 思维……分成两栏,左侧 list,右侧详情。这种结构替代手风琴会更好"
172123
+ * Original request (2026-09-03): "Openspec 1.12.0 刚刚放出来,你更新一下,调查变更内容,然后开始规划适配工作,我们将用标准工作流worktree来推进"
172124
+ * Owner walkthrough correction (2026-09-04): every Evidence detail layer renders the shared EvidenceLayerHeader contract (title dominant over body, house-standard border padding); this replaces each layer's local weak header.
171841
172125
  */
171842
172126
  function diffLineRole(line) {
171843
172127
  if (line.startsWith("@@")) return "hunk";
@@ -171928,22 +172212,16 @@ function RequirementDiffsSection({ summary, children }) {
171928
172212
  "data-evidence-section": "requirement-diffs",
171929
172213
  "aria-label": "Requirement diffs",
171930
172214
  className: "min-w-0",
171931
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
171932
- className: "border-border/60 flex min-w-0 flex-wrap items-baseline justify-between gap-x-3 gap-y-1 border-b pb-2",
171933
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", {
171934
- className: "min-w-0 text-xs font-semibold",
171935
- children: "Requirement diffs"
171936
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
171937
- className: "text-muted-foreground min-w-0 text-[11px]",
171938
- children: summary
171939
- })]
172215
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(EvidenceLayerHeader, {
172216
+ title: "Requirement diffs",
172217
+ summary
171940
172218
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
171941
- className: "min-w-0 pt-3",
172219
+ className: "min-w-0 text-xs",
171942
172220
  children
171943
172221
  })]
171944
172222
  });
171945
172223
  }
171946
- /** CLI MODIFIED-delta diff evidence for the Change Evidence workspace (live 1.11 sessions only). */
172224
+ /** CLI MODIFIED-delta diff evidence for the Change Evidence workspace (admitted-line live sessions only). */
171947
172225
  function ChangeDiffEvidence({ changeId, onChip }) {
171948
172226
  const cli = useRootActionState().context?.cli;
171949
172227
  const diffCapable = deriveOpenSpecCliCapabilities(cli?.available ? parseOpenSpecCliVersion(cli.version) : null).requirementDiff;
@@ -172017,9 +172295,13 @@ function ChangeDiffEvidence({ changeId, onChip }) {
172017
172295
  if (!diffCapable) {
172018
172296
  if (cli?.available !== true) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RequirementDiffsSection, {
172019
172297
  summary: "CLI diff evidence",
172020
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
172298
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
172021
172299
  className: "text-muted-foreground",
172022
- children: "Requirement diff evidence from `show --diff` appears here on admitted OpenSpec CLI 1.11 sessions once the CLI is detected."
172300
+ children: [
172301
+ "Requirement diff evidence from `show --diff` appears here on admitted OpenSpec CLI sessions (",
172302
+ OPENSPEC_CLI_ACCEPTED_RANGE,
172303
+ ") once the CLI is detected."
172304
+ ]
172023
172305
  })
172024
172306
  });
172025
172307
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RequirementDiffsSection, {
@@ -172027,7 +172309,9 @@ function ChangeDiffEvidence({ changeId, onChip }) {
172027
172309
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
172028
172310
  className: "text-muted-foreground",
172029
172311
  children: [
172030
- "Requirement diffs require an admitted OpenSpec CLI 1.11 session",
172312
+ "Requirement diffs require an admitted OpenSpec CLI session (",
172313
+ OPENSPEC_CLI_ACCEPTED_RANGE,
172314
+ ")",
172031
172315
  cli.version ? ` (detected ${cli.version.trim()})` : "",
172032
172316
  ". This session's CLI does not declare the `show --diff` capability, so the delta presentation keeps using the captured local content."
172033
172317
  ]
@@ -172062,11 +172346,11 @@ function ChangeDiffEvidence({ changeId, onChip }) {
172062
172346
  summary: "CLI diff evidence",
172063
172347
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
172064
172348
  className: "text-muted-foreground",
172065
- children: "Requirement diff evidence from `show --diff` appears here on 1.11 sessions."
172349
+ children: "Requirement diff evidence from `show --diff` appears here on admitted CLI sessions."
172066
172350
  })
172067
172351
  });
172068
172352
  if (evidence.kind !== "executed") {
172069
- const detail = evidence.reason === "command-failed" ? evidence.detail : evidence.reason === "capability" ? "The detected OpenSpec CLI does not declare the 1.11 requirement-diff capability." : "The planning root is unavailable, so requirement-diff evidence cannot be fetched.";
172353
+ const detail = evidence.reason === "command-failed" ? evidence.detail : evidence.reason === "capability" ? "The detected OpenSpec CLI does not declare the requirement-diff capability." : "The planning root is unavailable, so requirement-diff evidence cannot be fetched.";
172070
172354
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RequirementDiffsSection, {
172071
172355
  summary: "CLI evidence unavailable",
172072
172356
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
@@ -172149,6 +172433,7 @@ function ChangeDiffEvidence({ changeId, onChip }) {
172149
172433
  *
172150
172434
  * Original request (2026-08-03): use an Evidence tab to carry complete Change Detail information.
172151
172435
  * Original request (2026-08-28): "使用移动端的 list-detail 思维……分成两栏,左侧 list,右侧详情。这种结构替代手风琴会更好"
172436
+ * Owner walkthrough correction (2026-09-04): every Evidence detail layer renders the shared EvidenceLayerHeader contract (title dominant over body, house-standard border padding); this replaces each layer's local weak header.
172152
172437
  */
172153
172438
  /** Shared section frame for the Evidence workspace detail pane; keeps the a11y heading. */
172154
172439
  function WorkspaceSection({ id, title, summary, children, container = false }) {
@@ -172156,17 +172441,11 @@ function WorkspaceSection({ id, title, summary, children, container = false }) {
172156
172441
  "data-evidence-section": id,
172157
172442
  "aria-label": title,
172158
172443
  className: container ? "@container min-w-0" : "min-w-0",
172159
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
172160
- className: "border-border/60 flex min-w-0 flex-wrap items-baseline justify-between gap-x-3 gap-y-1 border-b pb-2",
172161
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", {
172162
- className: "min-w-0 text-xs font-semibold",
172163
- children: title
172164
- }), summary ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
172165
- className: "text-muted-foreground min-w-0 text-[11px]",
172166
- children: summary
172167
- }) : null]
172444
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(EvidenceLayerHeader, {
172445
+ title,
172446
+ summary
172168
172447
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
172169
- className: "min-w-0 pt-3 text-xs",
172448
+ className: "min-w-0 text-xs",
172170
172449
  children
172171
172450
  })]
172172
172451
  });
@@ -172454,20 +172733,505 @@ function EvidenceList({ label, values }) {
172454
172733
  });
172455
172734
  }
172456
172735
  //#endregion
172736
+ //#region src/components/validation-findings-evidence.tsx
172737
+ /**
172738
+ * Orthogonal intents (updated 2026-09-12 Asia/Shanghai):
172739
+ * 1. Present the OpenSpec 1.12+ `validate --report findings` document (the admitted 1.13
172740
+ * line carries the capability) as typed CLI evidence.
172741
+ * 2. Attribute every item finding to its owning change: entries owned by the current change
172742
+ * render as the primary "This change" list, while entries owned by other active changes
172743
+ * stay in a clearly-labeled secondary disclosure with prominent change attribution — a
172744
+ * finding never presents as this change's finding just because the scope is shared.
172745
+ * 3. Render INFO as a first-class informational class, distinct from warnings and errors.
172746
+ * 4. Show the filtered view honestly: `returnedItems` beside the preserved full-run totals,
172747
+ * labeled as filtered, never presented as the complete validation result. Scope-level
172748
+ * counts are never filtered to the current change.
172749
+ * 5. Gate the affordance behind the admitted line's `findingsReport` capability: non-admitted
172750
+ * sessions get no findings action; static snapshots state the evidence is unavailable.
172751
+ * 6. Validate transport and findings payloads with the Core contract schemas, never shallow
172752
+ * guards, and keep the CLI-owned request-error envelope on the direct plane.
172753
+ *
172754
+ * Original request (2026-09-03): "Openspec 1.12.0 刚刚放出来,你更新一下,调查变更内容,然后开始规划适配工作,我们将用标准工作流worktree来推进"
172755
+ * Owner walkthrough correction (2026-09-04): findings must attribute their owning change; the Evidence detail panel styling follows the vision review and every detail layer renders the shared EvidenceLayerHeader contract (title dominant over body, house-standard border padding) instead of a local weak header.
172756
+ * Original request (2026-09-12): "Openspec 1.13.0 释放了,你更新一下,调查变更内容,然后开始规划适配工作,我们将用标准工作流worktree来推进。让 codex 参与。"
172757
+ */
172758
+ function parseFindingsPayload(value) {
172759
+ const parsed = CliValidateFindingsResultSchema.safeParse(value);
172760
+ if (parsed.success) return isCliValidateFindings(parsed.data) ? {
172761
+ kind: "findings",
172762
+ findings: parsed.data
172763
+ } : {
172764
+ kind: "request-failure",
172765
+ failure: parsed.data
172766
+ };
172767
+ const document = CliValidateFindingsSchema.safeParse(value);
172768
+ return {
172769
+ kind: "malformed",
172770
+ schemaIssues: (document.success ? parsed.error : document.error).issues.map((issue) => `${issue.path.length > 0 ? issue.path.join(".") : "<root>"}: ${issue.message}`)
172771
+ };
172772
+ }
172773
+ /** Semantic level chip: box-radius geometry, distinct glyph per class, tinted never flooded. */
172774
+ var LEVEL_CHIP_CLASS = {
172775
+ INFO: "border-blue-600/40 bg-blue-500/5 text-blue-600 dark:text-blue-400",
172776
+ WARNING: "border-amber-600/40 bg-amber-500/5 text-amber-600 dark:text-amber-400",
172777
+ ERROR: "border-red-600/40 bg-red-500/5 text-red-600 dark:text-red-400"
172778
+ };
172779
+ var LEVEL_CHIP_GLYPH = {
172780
+ INFO: Info$1,
172781
+ WARNING: TriangleAlert,
172782
+ ERROR: OctagonAlert
172783
+ };
172784
+ function LevelChip({ level }) {
172785
+ const Glyph = LEVEL_CHIP_GLYPH[level];
172786
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
172787
+ "data-findings-level": level,
172788
+ className: `inline-flex shrink-0 items-center gap-1 border px-1.5 py-0.5 text-[11px] font-semibold uppercase tracking-wide ${LEVEL_CHIP_CLASS[level]}`,
172789
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Glyph, {
172790
+ className: "h-3 w-3",
172791
+ "aria-hidden": true
172792
+ }), level]
172793
+ });
172794
+ }
172795
+ /**
172796
+ * One findings item as a header/body card. Each issue owns a header row (level chip, issue
172797
+ * path, item identity) and a neutral message body; multiple issues stack as divided rows.
172798
+ * The message itself never carries the level color — the chip is the only color carrier.
172799
+ */
172800
+ function FindingCard({ item }) {
172801
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("article", {
172802
+ "data-findings-item": item.id,
172803
+ className: "border-border bg-card min-w-0 overflow-hidden rounded border",
172804
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", {
172805
+ className: "border-border/60 m-0 list-none divide-y p-0",
172806
+ children: item.issues.map((issue, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", {
172807
+ "data-findings-issue": issue.level,
172808
+ className: "min-w-0",
172809
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
172810
+ className: "border-border flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1 border-b px-2.5 py-1.5",
172811
+ children: [
172812
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LevelChip, { level: issue.level }),
172813
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
172814
+ className: "text-foreground min-w-0 flex-1 basis-[6rem] font-mono text-xs [overflow-wrap:anywhere]",
172815
+ children: issue.path
172816
+ }),
172817
+ index === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
172818
+ className: "text-muted-foreground max-w-full shrink-0 text-right font-mono text-[11px] [overflow-wrap:anywhere]",
172819
+ children: [
172820
+ item.id,
172821
+ " · ",
172822
+ item.type,
172823
+ " · ",
172824
+ item.valid ? "valid" : "invalid"
172825
+ ]
172826
+ }) : null
172827
+ ]
172828
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
172829
+ className: "text-foreground/90 px-2.5 py-2 text-xs leading-relaxed [overflow-wrap:anywhere]",
172830
+ children: issue.message
172831
+ })]
172832
+ }, index))
172833
+ })
172834
+ });
172835
+ }
172836
+ /** Compact count chip (box radius; pill geometry stays reserved for bare numeric counts). */
172837
+ function CountChip({ label, tone }) {
172838
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
172839
+ className: cn$1("inline-flex shrink-0 items-center rounded border px-1.5 py-0.5 text-xs font-medium", tone === "passed" && "border-emerald-600/40 bg-emerald-500/5 text-emerald-700 dark:text-emerald-400", tone === "failed" && "border-red-600/40 bg-red-500/5 text-red-600 dark:text-red-400", tone === "muted" && "border-border bg-muted/50 text-muted-foreground"),
172840
+ children: label
172841
+ });
172842
+ }
172843
+ function RunButton$1({ pending, label, onRun }) {
172844
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
172845
+ type: "button",
172846
+ onClick: onRun,
172847
+ disabled: pending,
172848
+ "aria-busy": pending || void 0,
172849
+ className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs disabled:opacity-50",
172850
+ children: [pending ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, {
172851
+ className: "h-3.5 w-3.5 animate-spin",
172852
+ "aria-hidden": true
172853
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCw, {
172854
+ className: "h-3.5 w-3.5 shrink-0",
172855
+ "aria-hidden": true
172856
+ }), label]
172857
+ });
172858
+ }
172859
+ /**
172860
+ * Structure-agnostic section frame for the Evidence workspace detail pane: heading plus
172861
+ * summary facts stay on the record; the workspace, not a disclosure, owns reveal behavior.
172862
+ * The header follows the workspace's one header contract: rule, baseline padding, margin.
172863
+ */
172864
+ function ValidationFindingsSection({ summary, children }) {
172865
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
172866
+ "data-evidence-section": "validation-findings",
172867
+ "aria-label": "Validation findings",
172868
+ className: "min-w-0",
172869
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(EvidenceLayerHeader, {
172870
+ title: "Validation findings",
172871
+ summary
172872
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
172873
+ className: "min-w-0 text-xs",
172874
+ children
172875
+ })]
172876
+ });
172877
+ }
172878
+ /**
172879
+ * On-demand, read-only validation findings evidence for the Change Evidence workspace.
172880
+ *
172881
+ * The findings report is a filtered view — only items with issues — over the same full-run
172882
+ * totals the complete validation report carries, so the section always presents
172883
+ * `returnedItems` beside the preserved totals and never claims to be the complete result.
172884
+ * The report covers the whole changes scope, so every item finding is attributed: the
172885
+ * current change's entries render as the primary list and other changes' entries stay in a
172886
+ * labeled secondary disclosure with the owning change id prominent.
172887
+ */
172888
+ function ValidationFindingsEvidence({ changeId, onChip }) {
172889
+ const [report, setReport] = (0, import_react.useState)(null);
172890
+ const [error, setError] = (0, import_react.useState)(null);
172891
+ const [pending, setPending] = (0, import_react.useState)(false);
172892
+ const cli = useRootActionState().context?.cli;
172893
+ const staticMode = isStaticMode();
172894
+ const capabilities = deriveOpenSpecCliCapabilities(cli?.available ? parseOpenSpecCliVersion(cli.version) : null);
172895
+ const chip = (0, import_react.useMemo)(() => {
172896
+ if (staticMode) return {
172897
+ label: "unavailable",
172898
+ tone: "unavailable"
172899
+ };
172900
+ if (cli?.available === true && !capabilities.findingsReport) return {
172901
+ label: "unavailable",
172902
+ tone: "unavailable"
172903
+ };
172904
+ if (!report && !error) return null;
172905
+ const parsed = report ? parseFindingsPayload(report.data) : null;
172906
+ if (error || !parsed || parsed.kind === "malformed") return {
172907
+ label: "fail",
172908
+ tone: "negative"
172909
+ };
172910
+ if (parsed.kind === "request-failure") return {
172911
+ label: "fail",
172912
+ tone: "negative"
172913
+ };
172914
+ const findings = parsed.findings;
172915
+ return findings.summary.totals.failed > 0 ? {
172916
+ label: `${findings.summary.totals.failed} failed`,
172917
+ tone: "negative"
172918
+ } : {
172919
+ label: `${findings.report.returnedItems} findings`,
172920
+ tone: "neutral"
172921
+ };
172922
+ }, [
172923
+ capabilities.findingsReport,
172924
+ cli?.available,
172925
+ error,
172926
+ report,
172927
+ staticMode
172928
+ ]);
172929
+ (0, import_react.useEffect)(() => {
172930
+ onChip?.(chip);
172931
+ }, [chip, onChip]);
172932
+ if (staticMode) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ValidationFindingsSection, {
172933
+ summary: "Unavailable in static snapshot",
172934
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
172935
+ className: "text-muted-foreground",
172936
+ children: "Validation findings are live CLI evidence and are not captured in this static snapshot."
172937
+ })
172938
+ });
172939
+ if (cli?.available === true && !capabilities.findingsReport) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ValidationFindingsSection, {
172940
+ summary: "Unavailable on this CLI line",
172941
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
172942
+ className: "text-muted-foreground",
172943
+ children: [
172944
+ "Validation findings require the admitted OpenSpec CLI line (",
172945
+ OPENSPEC_CLI_ACCEPTED_RANGE,
172946
+ ")",
172947
+ cli.version ? ` (detected ${cli.version.trim()})` : "",
172948
+ ". This session's CLI does not declare the findings-report capability, so no command is offered."
172949
+ ]
172950
+ })
172951
+ });
172952
+ const run = async () => {
172953
+ setPending(true);
172954
+ setError(null);
172955
+ setReport(null);
172956
+ try {
172957
+ const result = await trpcClient.cli.validate.mutate({
172958
+ kind: "findings",
172959
+ scope: "changes"
172960
+ });
172961
+ const transport = CliCommandTransportSchema.safeParse(result);
172962
+ if (transport.success) setReport({
172963
+ ...transport.data,
172964
+ data: transport.data.data ?? null,
172965
+ payload: transport.data.payload ?? null
172966
+ });
172967
+ else setError("The validation findings transport returned an unrecognized result shape.");
172968
+ } catch (cause) {
172969
+ setError(cause instanceof Error ? cause.message : String(cause));
172970
+ } finally {
172971
+ setPending(false);
172972
+ }
172973
+ };
172974
+ if (!report && !error) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ValidationFindingsSection, {
172975
+ summary: "Not yet run",
172976
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
172977
+ className: "border-border bg-muted/20 max-w-[72ch] rounded-md border border-dashed p-6",
172978
+ children: pending ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
172979
+ className: "flex items-center gap-2",
172980
+ role: "status",
172981
+ "data-findings-running": "",
172982
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, {
172983
+ className: "text-muted-foreground h-4 w-4 animate-spin",
172984
+ "aria-hidden": true
172985
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
172986
+ className: "text-xs font-medium",
172987
+ children: "Running findings report…"
172988
+ })]
172989
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
172990
+ className: "space-y-3",
172991
+ children: [
172992
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
172993
+ className: "text-xs font-semibold",
172994
+ children: "No findings loaded"
172995
+ }),
172996
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
172997
+ className: "text-muted-foreground",
172998
+ children: "Load the official CLI's validation findings to see advisory issues reported for the active changes in this scope — including archive-merge advisories. This is read-only evidence; nothing is repaired from here."
172999
+ }),
173000
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", {
173001
+ className: "border-border bg-muted rounded border px-1 py-0.5 font-mono text-[11px]",
173002
+ children: "openspec validate --report findings"
173003
+ }) }),
173004
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunButton$1, {
173005
+ pending,
173006
+ label: "Load validation findings",
173007
+ onRun: () => void run()
173008
+ })
173009
+ ]
173010
+ })
173011
+ })
173012
+ });
173013
+ const parsed = report ? parseFindingsPayload(report.data) : null;
173014
+ if (error || !parsed || parsed.kind === "malformed") {
173015
+ const schemaDiagnostic = parsed?.kind === "malformed" && parsed.schemaIssues.length > 0 ? parsed.schemaIssues.join("; ") : null;
173016
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ValidationFindingsSection, {
173017
+ summary: "CLI failure evidence",
173018
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
173019
+ className: "space-y-2",
173020
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
173021
+ className: "text-destructive flex items-start gap-2 break-words",
173022
+ role: "alert",
173023
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, {
173024
+ className: "mt-0.5 h-3.5 w-3.5 shrink-0",
173025
+ "aria-hidden": true
173026
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
173027
+ className: "min-w-0 [overflow-wrap:anywhere]",
173028
+ children: error ?? report?.contractError ?? schemaDiagnostic ?? report?.stderr.trim() ?? "The validation findings command failed."
173029
+ })]
173030
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunButton$1, {
173031
+ pending,
173032
+ label: "Rerun",
173033
+ onRun: () => void run()
173034
+ })]
173035
+ })
173036
+ });
173037
+ }
173038
+ if (parsed.kind === "request-failure") {
173039
+ const entries = parsed.failure.status;
173040
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ValidationFindingsSection, {
173041
+ summary: "CLI request failure",
173042
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
173043
+ className: "space-y-2",
173044
+ children: [
173045
+ entries.map((entry, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
173046
+ "data-findings-request-error": entry.code,
173047
+ className: "text-destructive flex items-start gap-2 break-words",
173048
+ role: "alert",
173049
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, {
173050
+ className: "mt-0.5 h-3.5 w-3.5 shrink-0",
173051
+ "aria-hidden": true
173052
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
173053
+ className: "min-w-0 [overflow-wrap:anywhere]",
173054
+ children: [
173055
+ entry.code,
173056
+ ": ",
173057
+ entry.message
173058
+ ]
173059
+ })]
173060
+ }, index)),
173061
+ entries.some((entry) => entry.fix !== void 0) ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
173062
+ className: "break-words",
173063
+ "data-findings-request-fix": true,
173064
+ children: ["CLI fix suggestion: ", entries.find((entry) => entry.fix !== void 0)?.fix]
173065
+ }) : null,
173066
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunButton$1, {
173067
+ pending,
173068
+ label: "Rerun",
173069
+ onRun: () => void run()
173070
+ })
173071
+ ]
173072
+ })
173073
+ });
173074
+ }
173075
+ const findings = parsed.findings;
173076
+ const totals = findings.summary.totals;
173077
+ const ownFindings = findings.itemFindings.filter((item) => item.id === changeId);
173078
+ const otherFindings = findings.itemFindings.filter((item) => item.id !== changeId);
173079
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ValidationFindingsSection, {
173080
+ summary: `Filtered view · ${findings.report.returnedItems} of ${findings.report.totalItems} items with findings`,
173081
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
173082
+ className: "space-y-3",
173083
+ children: [
173084
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
173085
+ className: "text-muted-foreground",
173086
+ "data-findings-filtered-note": true,
173087
+ children: "Filtered CLI evidence: only items that reported issues are listed. The complete validation result remains the full report; totals below are the full-run values the CLI preserved."
173088
+ }),
173089
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("dl", {
173090
+ "data-findings-provenance": "",
173091
+ className: "@[28rem]:grid-cols-[150px_1fr] grid min-w-0 grid-cols-1 gap-x-3 gap-y-1",
173092
+ children: [
173093
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
173094
+ className: "text-muted-foreground",
173095
+ children: "Root"
173096
+ }),
173097
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", {
173098
+ className: "min-w-0 font-mono text-xs [overflow-wrap:anywhere]",
173099
+ children: findings.root.path
173100
+ }),
173101
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
173102
+ className: "text-muted-foreground",
173103
+ children: "Exit status"
173104
+ }),
173105
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", {
173106
+ className: "min-w-0 font-mono text-xs",
173107
+ children: report?.exitCode === null || report?.exitCode === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
173108
+ className: "text-muted-foreground",
173109
+ children: "—"
173110
+ }) : report.exitCode
173111
+ }),
173112
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
173113
+ className: "text-muted-foreground",
173114
+ children: "Items with findings"
173115
+ }),
173116
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("dd", {
173117
+ className: "min-w-0 font-mono text-xs",
173118
+ children: [
173119
+ findings.report.returnedItems,
173120
+ " of ",
173121
+ findings.report.totalItems,
173122
+ " (",
173123
+ findings.report.scope,
173124
+ " ",
173125
+ "scope)"
173126
+ ]
173127
+ })
173128
+ ]
173129
+ }),
173130
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
173131
+ className: "space-y-1.5",
173132
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
173133
+ className: "text-muted-foreground text-[11px]",
173134
+ children: "Full-run totals"
173135
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
173136
+ className: "flex flex-wrap gap-1.5",
173137
+ "data-findings-totals": "",
173138
+ children: [
173139
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CountChip, {
173140
+ label: `${totals.passed} passed`,
173141
+ tone: "passed"
173142
+ }),
173143
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CountChip, {
173144
+ label: `${totals.failed} failed`,
173145
+ tone: totals.failed > 0 ? "failed" : "muted"
173146
+ }),
173147
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CountChip, {
173148
+ label: `${totals.items} items`,
173149
+ tone: "muted"
173150
+ })
173151
+ ]
173152
+ })]
173153
+ }),
173154
+ findings.itemFindings.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
173155
+ className: "text-muted-foreground",
173156
+ children: "No item in this scope reported an issue. This filtered view lists issues only — it is not the complete validation result."
173157
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
173158
+ className: "space-y-2",
173159
+ "data-findings-own": "",
173160
+ children: [
173161
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h4", {
173162
+ className: "text-xs font-semibold",
173163
+ children: "This change"
173164
+ }),
173165
+ ownFindings.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FindingCard, { item }, item.id)),
173166
+ ownFindings.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
173167
+ className: "text-muted-foreground",
173168
+ "data-findings-own-empty": "",
173169
+ children: "No findings for this change in the filtered scope. Other entries below belong to other active changes."
173170
+ }) : null
173171
+ ]
173172
+ }), otherFindings.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", {
173173
+ "data-findings-other": "",
173174
+ className: "border-border rounded border",
173175
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("summary", {
173176
+ className: "cursor-pointer select-none px-2.5 py-2 text-xs font-medium",
173177
+ children: [
173178
+ "Findings from other active changes (",
173179
+ otherFindings.length,
173180
+ ")"
173181
+ ]
173182
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
173183
+ className: "border-border space-y-3 border-t px-2.5 py-2.5",
173184
+ children: otherFindings.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
173185
+ className: "min-w-0 space-y-1",
173186
+ "data-findings-other-item": "",
173187
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
173188
+ className: "text-foreground font-mono text-xs font-medium",
173189
+ children: item.id
173190
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FindingCard, { item })]
173191
+ }, item.id))
173192
+ })]
173193
+ }) : null] }),
173194
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("footer", {
173195
+ className: "border-border mt-4 flex flex-wrap items-center justify-between gap-x-4 gap-y-2 border-t pt-3",
173196
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
173197
+ className: "text-muted-foreground font-mono text-[11px] [overflow-wrap:anywhere]",
173198
+ children: [
173199
+ "openspec validate --report findings · ",
173200
+ findings.report.scope,
173201
+ " scope"
173202
+ ]
173203
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunButton$1, {
173204
+ pending,
173205
+ label: "Rerun",
173206
+ onRun: () => void run()
173207
+ })]
173208
+ })
173209
+ ]
173210
+ })
173211
+ });
173212
+ }
173213
+ //#endregion
172457
173214
  //#region src/components/evidence-workspace.tsx
172458
173215
  /**
172459
- * Orthogonal intents (created 2026-08-28 Asia/Shanghai):
173216
+ * Orthogonal intents (updated 2026-09-04 Asia/Shanghai):
172460
173217
  * 1. Own the Change Evidence tab's container-responsive list-detail workspace topology.
172461
173218
  * 2. Preserve the decision-plane evidence layer order (summary/paths -> requirement diffs ->
172462
- * archived validation -> CLI/raw payload) in keyboard-reachable list rows.
173219
+ * validation findings -> archived validation -> CLI/raw payload) in keyboard-reachable
173220
+ * list rows.
172463
173221
  * 3. Derive row chips only from settled section facts; never fabricate counts or verdicts.
172464
173222
  * 4. Keep the crowded drill presentational: the detail replaces the list with a back
172465
173223
  * affordance, and back restores the list without unmounting settled evidence; focus
172466
173224
  * follows the drill (row -> back affordance -> originating row) so keyboard users never
172467
173225
  * land on a hidden element.
172468
173226
  * 5. Keep sub-selection local runtime state — it never enters routes or browser storage.
173227
+ * 6. Separate the workspace planes visually: the list column is the muted rail and the
173228
+ * detail column is the card surface; detail prose caps its measure, and only the
173229
+ * selected row ever carries a row fill.
172469
173230
  *
172470
173231
  * Original request (2026-08-28): "使用移动端的 list-detail 思维……分成两栏,左侧 list,右侧详情。这种结构替代手风琴会更好"
173232
+ * Original request (2026-09-03): "Openspec 1.12.0 刚刚放出来,你更新一下,调查变更内容,然后开始规划适配工作,我们将用标准工作流worktree来推进"
173233
+ * Owner walkthrough correction (2026-09-04): findings must attribute their owning change; the Evidence detail panel styling follows the vision review and every detail layer renders the shared EvidenceLayerHeader contract (title dominant over body, house-standard border padding) instead of a local weak header.
173234
+ * Original request (2026-09-12): "Openspec 1.13.0 释放了,你更新一下,调查变更内容,然后开始规划适配工作,我们将用标准工作流worktree来推进。让 codex 参与。"
172471
173235
  */
172472
173236
  /**
172473
173237
  * Spacious threshold: below this inline size the workspace collapses to one column and the
@@ -172518,10 +173282,14 @@ function EvidenceWorkspace({ changeId, status, referenceEvidence }) {
172518
173282
  const pendingRestoreRowId = (0, import_react.useRef)(null);
172519
173283
  const backHadFocus = (0, import_react.useRef)(false);
172520
173284
  const [diffChip, setDiffChip] = (0, import_react.useState)(null);
173285
+ const [findingsChip, setFindingsChip] = (0, import_react.useState)(null);
172521
173286
  const [validationChip, setValidationChip] = (0, import_react.useState)(null);
172522
173287
  const handleDiffChip = (0, import_react.useCallback)((chip) => {
172523
173288
  setDiffChip(chip);
172524
173289
  }, []);
173290
+ const handleFindingsChip = (0, import_react.useCallback)((chip) => {
173291
+ setFindingsChip(chip);
173292
+ }, []);
172525
173293
  const handleValidationChip = (0, import_react.useCallback)((chip) => {
172526
173294
  setValidationChip(chip);
172527
173295
  }, []);
@@ -172549,6 +173317,15 @@ function EvidenceWorkspace({ changeId, status, referenceEvidence }) {
172549
173317
  onChip: handleDiffChip
172550
173318
  })
172551
173319
  },
173320
+ {
173321
+ id: "validation-findings",
173322
+ label: "Validation findings",
173323
+ chip: findingsChip,
173324
+ content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ValidationFindingsEvidence, {
173325
+ changeId,
173326
+ onChip: handleFindingsChip
173327
+ })
173328
+ },
172552
173329
  {
172553
173330
  id: "archived-validation",
172554
173331
  label: "Archived validation",
@@ -172560,7 +173337,9 @@ function EvidenceWorkspace({ changeId, status, referenceEvidence }) {
172560
173337
  }, [
172561
173338
  changeId,
172562
173339
  diffChip,
173340
+ findingsChip,
172563
173341
  handleDiffChip,
173342
+ handleFindingsChip,
172564
173343
  handleValidationChip,
172565
173344
  referenceEvidence,
172566
173345
  status,
@@ -172608,7 +173387,7 @@ function EvidenceWorkspace({ changeId, status, referenceEvidence }) {
172608
173387
  "aria-label": "Evidence sections",
172609
173388
  "data-evidence-pane": "list",
172610
173389
  hidden: !showList || void 0,
172611
- className: cn$1("scrollbar-thin scrollbar-track-transparent border-border/60 @[40rem]:border-r min-h-0 min-w-0 overflow-y-auto overflow-x-hidden overscroll-contain", !showList && "hidden"),
173390
+ className: cn$1("scrollbar-thin scrollbar-track-transparent bg-muted/40 border-border @[40rem]:border-r min-h-0 min-w-0 overflow-y-auto overflow-x-hidden overscroll-contain", !showList && "hidden"),
172612
173391
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", {
172613
173392
  className: "divide-border/20 m-0 list-none divide-y p-0",
172614
173393
  children: sections.map((section) => {
@@ -172639,7 +173418,7 @@ function EvidenceWorkspace({ changeId, status, referenceEvidence }) {
172639
173418
  "data-evidence-pane": "detail",
172640
173419
  "data-change-evidence-scroll-owner": "",
172641
173420
  hidden: !showDetail || void 0,
172642
- className: cn$1("scrollbar-thin scrollbar-track-transparent min-h-0 min-w-0 overflow-y-auto overflow-x-hidden overscroll-contain", showDetail ? "flex flex-col" : "hidden"),
173421
+ className: cn$1("scrollbar-thin scrollbar-track-transparent bg-card min-h-0 min-w-0 overflow-y-auto overflow-x-hidden overscroll-contain", showDetail ? "flex flex-col" : "hidden"),
172643
173422
  children: [!spacious && drilled ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
172644
173423
  ref: backRef,
172645
173424
  type: "button",
@@ -172652,7 +173431,7 @@ function EvidenceWorkspace({ changeId, status, referenceEvidence }) {
172652
173431
  backHadFocus.current = false;
172653
173432
  },
172654
173433
  onClick: backToList,
172655
- className: "bg-background/95 border-border/60 text-muted-foreground hover:text-foreground focus-visible:ring-primary sticky top-0 z-10 flex min-h-9 w-full min-w-0 items-center gap-1.5 border-b px-3 text-xs outline-none backdrop-blur focus-visible:ring-2 focus-visible:ring-inset",
173434
+ className: "bg-card/95 border-border/60 text-muted-foreground hover:text-foreground focus-visible:ring-primary sticky top-0 z-10 flex min-h-9 w-full min-w-0 items-center gap-1.5 border-b px-3 text-xs outline-none backdrop-blur focus-visible:ring-2 focus-visible:ring-inset",
172656
173435
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowLeft, {
172657
173436
  className: "h-3.5 w-3.5 shrink-0",
172658
173437
  "aria-hidden": true
@@ -172660,7 +173439,7 @@ function EvidenceWorkspace({ changeId, status, referenceEvidence }) {
172660
173439
  }) : null, sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
172661
173440
  "data-evidence-detail": section.id,
172662
173441
  hidden: section.id !== activeSection.id,
172663
- className: "min-w-0 px-4 pb-4",
173442
+ className: "min-w-0 px-4 pb-6 pt-3 [&_p]:max-w-[88ch]",
172664
173443
  children: section.content
172665
173444
  }, section.id))]
172666
173445
  })]
@@ -172903,13 +173682,14 @@ function RootActionNotice({ state }) {
172903
173682
  //#endregion
172904
173683
  //#region src/routes/change-view.tsx
172905
173684
  /**
172906
- * Orthogonal intents (updated 2026-08-28 Asia/Shanghai):
173685
+ * Orthogonal intents (updated 2026-09-12 Asia/Shanghai):
172907
173686
  * 1. Render schema-aware change artifacts and source files while retaining terminal status errors.
172908
173687
  * 2. Dispatch change workflows through routed compose/verify surfaces and the shared Operator launcher.
172909
173688
  * 3. Lock every change workflow action behind current Root Context and Status projection authority.
172910
173689
  * 4. Present Apply progress directly and expose project context/guidance through a Header Action Dialog.
172911
173690
  * 5. Keep compact Change facts in subtitle badges while routing complete CLI evidence through a dedicated tab.
172912
173691
  * 6. Mount the container-responsive list-detail Evidence workspace as the sole Evidence tab surface.
173692
+ * 7. Mount OpenSpec 1.13 Apply warnings and the build-order chain on the direct status plane.
172913
173693
  *
172914
173694
  * Original request (2026-07-15): "Root-dependent actions remain locked until root selection succeeds."
172915
173695
  * Review request (2026-07-23): "代码已经提交,开始review。如果有问题,那么可更新change。"
@@ -172919,8 +173699,14 @@ function RootActionNotice({ state }) {
172919
173699
  * Owner correction (2026-08-03): move Actions inline with the title, unify subtitle badges, and localize unavailable Tooltips.
172920
173700
  * Original request (2026-08-15): 刷新/解析中状态收敛为副标题行内的 shiny 徽章,不再占据 statusRegion 块。
172921
173701
  * Original request (2026-08-28): "直接将 0.10.0 和 0.11.0 一起适配,然后发布 v11。" — the Evidence
172922
- * tab gains the 1.11-gated CLI MODIFIED-delta diff evidence beside the existing layers.
173702
+ * tab gains the capability-gated CLI MODIFIED-delta diff evidence beside the existing layers.
173703
+ * Original request (2026-09-03): "Openspec 1.12.0 刚刚放出来,你更新一下,调查变更内容,然后开始规划适配工作,我们将用标准工作流worktree来推进" — the Evidence tab gains the findings evidence section.
172923
173704
  * Original request (2026-08-28): "使用移动端的 list-detail 思维……分成两栏,左侧 list,右侧详情。这种结构替代手风琴会更好"
173705
+ * Original request (2026-09-12): "Openspec 1.13.0 释放了,你更新一下,调查变更内容,然后开始规划适配工作,我们将用标准工作流worktree来推进。让 codex 参与。"
173706
+ * Original request (2026-09-12): Owner walkthrough: unify the Change display title (generic "# Proposal"
173707
+ * headings fall back to the change id) and collapse Apply readiness guidance into one summary row.
173708
+ * — the status region gains the OpenSpec 1.13 Apply `warnings` and `missingPrerequisites`
173709
+ * direct-plane evidence beside the existing divergence notice.
172924
173710
  */
172925
173711
  function ChangeView() {
172926
173712
  const { changeId } = useParams({ from: "/changes/$changeId" });
@@ -172931,6 +173717,8 @@ function ChangeView() {
172931
173717
  const { data: status, isLoading, error } = statusProjection;
172932
173718
  const { data: applyInstructions } = useOpsxApplyInstructionsSubscription({ change: changeId });
172933
173719
  const { data: files } = useChangeFilesSubscription(changeId);
173720
+ const changesRows = useChangesSubscription().data;
173721
+ const displayTitle = changeDisplayTitle(changeId, changesRows?.find((row) => row.id === changeId)?.name ?? status?.changeName);
172934
173722
  const handleComposeAction = (0, import_react.useCallback)((actionId, artifactId) => {
172935
173723
  if (actionId === "apply") {
172936
173724
  launchApply({
@@ -173001,14 +173789,14 @@ function ChangeView() {
173001
173789
  })
173002
173790
  }] : [], [referenceEvidence, status]);
173003
173791
  const hasReferenceFailures = referenceEvidence.state !== "unavailable" && referenceEvidence.references.some((reference) => reference.status.some((diagnostic) => diagnostic.severity === "error"));
173004
- const hasDirectStatus = Boolean(error) || rootAction.status === "blocked" || hasReferenceFailures || Boolean(applyInstructions?.applyInstructionProgress.divergence);
173792
+ const hasDirectStatus = Boolean(error) || rootAction.status === "blocked" || hasReferenceFailures || Boolean(applyInstructions?.applyInstructionProgress.divergence) || (applyInstructions?.warnings?.length ?? 0) > 0 || (applyInstructions?.missingPrerequisites?.length ?? 0) > 0;
173005
173793
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OpsxEntityDetailView, {
173006
173794
  entityId: changeId,
173007
173795
  sharedFamily: "changes",
173008
173796
  backTo: "/changes",
173009
173797
  backTitle: "Back to Changes",
173010
173798
  icon: GitBranch,
173011
- title: status?.changeName,
173799
+ title: displayTitle,
173012
173800
  subtitle: status ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeContextSummary, {
173013
173801
  status,
173014
173802
  referenceEvidence,
@@ -173076,7 +173864,11 @@ function ChangeView() {
173076
173864
  }) : null,
173077
173865
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RootActionNotice, { state: rootAction }),
173078
173866
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeReferenceFailureNotice, { referenceEvidence }),
173079
- applyInstructions ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ApplyProgressNotice, { applyInstructionProgress: applyInstructions.applyInstructionProgress }) : null
173867
+ applyInstructions ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ApplyProgressNotice, {
173868
+ applyInstructionProgress: applyInstructions.applyInstructionProgress,
173869
+ warnings: applyInstructions.warnings,
173870
+ missingPrerequisites: applyInstructions.missingPrerequisites
173871
+ }) : null
173080
173872
  ]
173081
173873
  }) : null
173082
173874
  });
@@ -173116,7 +173908,7 @@ var CONFIG_GUIDE_STAGE_META = {
173116
173908
  //#region src/components/config/config-guide.tsx
173117
173909
  var ConfigGuideContext = (0, import_react.createContext)(null);
173118
173910
  (0, import_react.lazy)(async () => {
173119
- return { default: (await import("./config-guide-presentation-D921NMVc.js")).ConfigGuidePresentationLayer };
173911
+ return { default: (await import("./config-guide-presentation-B5oRLCcX.js")).ConfigGuidePresentationLayer };
173120
173912
  });
173121
173913
  /** Access the root-owned adaptive Guide runtime. */
173122
173914
  function useConfigGuide() {
@@ -178158,6 +178950,8 @@ async function refreshDashboardGitSnapshot(reason, expectedBindingToken) {
178158
178950
  * Original request (2026-07-31): "基于真实的布局去做骨架屏,或者说是直接让卡片自身去支持 Pending 样式"
178159
178951
  * Original request (2026-07-31): "Code Git Snapshot 的 Other Worktrees 默认隐藏 (detached)。然后commitList这里默认显示5个就好"
178160
178952
  * Original request (2026-07-31): "检查目前的这个 Code Git Snapshot,它非常慢,有时候甚至要十几秒"
178953
+ * Original request (2026-09-12): Owner walkthrough: unify the Change display title — generic
178954
+ * "# Proposal" headings fall back to the change id on every surface.
178161
178955
  * Owner correction (2026-07-31): Hidden documents pause the timer; visibility resumes the remaining delay or refreshes once when the absolute deadline elapsed.
178162
178956
 
178163
178957
  */
@@ -178646,7 +179440,7 @@ function Dashboard() {
178646
179440
  __vtHandoff: {
178647
179441
  family: "changes",
178648
179442
  entityId: change.id,
178649
- title: change.name,
179443
+ title: changeDisplayTitle(change.id, change.name),
178650
179444
  subtitle: change.id
178651
179445
  }
178652
179446
  }),
@@ -178663,7 +179457,7 @@ function Dashboard() {
178663
179457
  className: "flex min-w-0 items-center gap-3",
178664
179458
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeRow, {
178665
179459
  changeId: change.id,
178666
- name: change.name,
179460
+ name: changeDisplayTitle(change.id, change.name),
178667
179461
  phase,
178668
179462
  updatedAt: change.updatedAt,
178669
179463
  formatTime: formatRelativeTime,