@openspecui/web 7.0.2 → 9.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-BvtmL_DV.css +1 -0
  2. package/dist/assets/{App-DZbK_VKF.js → App-pfObbe6n.js} +158 -157
  3. package/dist/assets/{main-DvWl4ArY.js → main-Bc_Hy41u.js} +2 -2
  4. package/dist/assets/{trpc-CUrXyPaH.js → trpc--JMUaLps.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-BFbMT1Ul.js +1 -0
  8. package/dist-ssg/client/assets/WebGLRenderer-C7eR_UnH.js +1 -0
  9. package/dist-ssg/client/assets/WebGPURenderer-BTQYx5S7.js +1 -0
  10. package/dist-ssg/client/assets/browserAll-C88S5YfV.js +1 -0
  11. package/dist-ssg/client/assets/{config-guide-presentation-PYNWYVfd.js → config-guide-presentation-BOR0ydhm.js} +1 -1
  12. package/dist-ssg/client/assets/{dist-CD337m0H.js → dist-0yxWvQWL.js} +1 -1
  13. package/dist-ssg/client/assets/dist-4fNILwqh.js +1 -0
  14. package/dist-ssg/client/assets/{dist-B6_zeP9X.js → dist-BXnglWxe.js} +1 -1
  15. package/dist-ssg/client/assets/{dist-C8koIGSO.js → dist-CcTAgsaD.js} +1 -1
  16. package/dist-ssg/client/assets/dist-Cd3-dF0O.js +1 -0
  17. package/dist-ssg/client/assets/{dist-n_0I1u31.js → dist-CqBkec9X.js} +1 -1
  18. package/dist-ssg/client/assets/{dist-f2vnkzi9.js → dist-Cqsy4GXU.js} +1 -1
  19. package/dist-ssg/client/assets/{dist-DZMoaNp9.js → dist-DFrBPW6S.js} +1 -1
  20. package/dist-ssg/client/assets/{dist-BxLfQE_c.js → dist-DR4ycVu1.js} +1 -1
  21. package/dist-ssg/client/assets/{dist-BXD-ZTAM.js → dist-DclbMTMt.js} +1 -1
  22. package/dist-ssg/client/assets/dist-DxTZTTY6.js +1 -0
  23. package/dist-ssg/client/assets/{dist-Cb1nIvKO.js → dist-biv4iN0V.js} +1 -1
  24. package/dist-ssg/client/assets/{ghostty-web-DEm8ZrOM.js → ghostty-web-D2QuMH_Q.js} +1 -1
  25. package/dist-ssg/client/assets/index-CrVhSCmS.css +1 -0
  26. package/dist-ssg/client/assets/index.ssg-JS2ceq7d.js +1649 -0
  27. package/dist-ssg/client/assets/{init-mhU1_WMm.js → init-CHYK3_IX.js} +1 -1
  28. package/dist-ssg/client/assets/{trpc-DcBLtyHb.js → trpc-B-w8tA8C.js} +1 -1
  29. package/dist-ssg/client/assets/webworkerAll-DFRsQGYS.js +1 -0
  30. package/dist-ssg/client/index.ssg.html +2 -2
  31. package/dist-ssg/server/assets/CanvasRenderer-Cud3mH2M.js +3 -0
  32. package/dist-ssg/server/assets/WebGLRenderer-BG7MkvqA.js +3 -0
  33. package/dist-ssg/server/assets/WebGPURenderer--JR4o1Id.js +3 -0
  34. package/dist-ssg/server/assets/{browserAll-C3TgySxy.js → browserAll-BNHXRTWn.js} +2 -2
  35. package/dist-ssg/server/assets/{config-guide-presentation-DluN0NgQ.js → config-guide-presentation-CmUNOJoP.js} +1 -1
  36. package/dist-ssg/server/assets/{dist-CqznyH3C.js → dist-BTzm9CCH.js} +1 -1
  37. package/dist-ssg/server/assets/{dist-CcweeoW2.js → dist-BZwNiEjE.js} +1 -1
  38. package/dist-ssg/server/assets/{dist-DukPjaq8.js → dist-Bg6kJ4lE.js} +1 -1
  39. package/dist-ssg/server/assets/{dist-C0UE33e7.js → dist-CD_P89TI.js} +1 -1
  40. package/dist-ssg/server/assets/{dist-DxUyXTq1.js → dist-CSnQ9MUZ.js} +1 -1
  41. package/dist-ssg/server/assets/{dist-BQhB00FX.js → dist-CkE7XypO.js} +1 -1
  42. package/dist-ssg/server/assets/dist-CpgxMd46.js +3 -0
  43. package/dist-ssg/server/assets/{dist-BSYA61e0.js → dist-CzfcaAEs.js} +1 -1
  44. package/dist-ssg/server/assets/{dist-BQopLPgi.js → dist-TFBLKdTC.js} +1 -1
  45. package/dist-ssg/server/assets/dist-gfV2B0G7.js +3 -0
  46. package/dist-ssg/server/assets/{dist-DHRASvmg.js → dist-tvIcsOn0.js} +1 -1
  47. package/dist-ssg/server/assets/dist-vPFtDCqy.js +3 -0
  48. package/dist-ssg/server/assets/{entry-server-CByGxb_0.js → entry-server-C_EGBt5m.js} +706 -245
  49. package/dist-ssg/server/assets/{init-C33dwfW5.js → init-Ds70MQGb.js} +1 -1
  50. package/dist-ssg/server/assets/trpc-DMtttD_4.js +3 -0
  51. package/dist-ssg/server/assets/webworkerAll-6pG_bTSk.js +4 -0
  52. package/dist-ssg/server/ssr-entry-manifest.json +25 -25
  53. package/package.json +3 -3
  54. package/dist/assets/App-Ddx3wr17.css +0 -1
  55. package/dist-ssg/client/assets/CanvasRenderer-DbReVIDE.js +0 -1
  56. package/dist-ssg/client/assets/WebGLRenderer-DYji4Hjk.js +0 -1
  57. package/dist-ssg/client/assets/WebGPURenderer-DCzgl3HP.js +0 -1
  58. package/dist-ssg/client/assets/browserAll-DyJwsAsx.js +0 -1
  59. package/dist-ssg/client/assets/dist-DOqQmBHc.js +0 -1
  60. package/dist-ssg/client/assets/dist-DUhJ59_2.js +0 -1
  61. package/dist-ssg/client/assets/dist-osbHiFDv.js +0 -1
  62. package/dist-ssg/client/assets/index-Dcu2Vogo.css +0 -1
  63. package/dist-ssg/client/assets/index.ssg-5ak0Ru-F.js +0 -1648
  64. package/dist-ssg/client/assets/webworkerAll-BZhOzVEX.js +0 -1
  65. package/dist-ssg/server/assets/CanvasRenderer-2gUSLPR3.js +0 -3
  66. package/dist-ssg/server/assets/WebGLRenderer-VYeMuiRZ.js +0 -3
  67. package/dist-ssg/server/assets/WebGPURenderer-CzqH7K0F.js +0 -3
  68. package/dist-ssg/server/assets/dist-Cr2VaH_X.js +0 -3
  69. package/dist-ssg/server/assets/dist-CuufxmlH.js +0 -3
  70. package/dist-ssg/server/assets/dist-D-tZhX9W.js +0 -3
  71. package/dist-ssg/server/assets/trpc-BZ-LKmoQ.js +0 -3
  72. package/dist-ssg/server/assets/webworkerAll-jouzdRxg.js +0 -4
@@ -29590,13 +29590,13 @@ var CliDiagnosticFailureSchema = objectType({ status: arrayType(CliDiagnosticSch
29590
29590
  *
29591
29591
  * Original request (2026-07-26): "即便现在有正在的任务,界面上仍然可以读到缓存,但它也能知道这个缓存现在正在被更新中。"
29592
29592
  */
29593
- var CliJsonValueSchema$1 = lazyType(() => unionType([
29593
+ var CliJsonValueSchema$2 = lazyType(() => unionType([
29594
29594
  stringType(),
29595
29595
  numberType(),
29596
29596
  booleanType(),
29597
29597
  nullType(),
29598
- arrayType(CliJsonValueSchema$1),
29599
- recordType(stringType(), CliJsonValueSchema$1)
29598
+ arrayType(CliJsonValueSchema$2),
29599
+ recordType(stringType(), CliJsonValueSchema$2)
29600
29600
  ]));
29601
29601
  /** Complete CLI attempt evidence retained when a Projection Work command rejects. */
29602
29602
  var CliProjectionCommandEvidenceSchema = objectType({
@@ -29604,7 +29604,7 @@ var CliProjectionCommandEvidenceSchema = objectType({
29604
29604
  stdout: stringType(),
29605
29605
  stderr: stringType(),
29606
29606
  exitCode: numberType().int().nullable(),
29607
- payload: CliJsonValueSchema$1.nullable(),
29607
+ payload: CliJsonValueSchema$2.nullable(),
29608
29608
  diagnostics: arrayType(CliDiagnosticSchema),
29609
29609
  contractError: stringType().optional()
29610
29610
  });
@@ -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-BZ-LKmoQ.js");
30911
+ const { trpcClient } = await import("./trpc-DMtttD_4.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-BZ-LKmoQ.js").then(({ trpcClient }) => trpcClient.kv.set.mutate({
31054
+ import("./trpc-DMtttD_4.js").then(({ trpcClient }) => trpcClient.kv.set.mutate({
31055
31055
  key: this.storageKey,
31056
31056
  value: {
31057
31057
  mainTabs: this.state.mainTabs,
@@ -38941,6 +38941,65 @@ function F$1(t) {
38941
38941
  throw new I$2(t);
38942
38942
  }
38943
38943
  //#endregion
38944
+ //#region ../core/src/cli-contracts/command-result.ts
38945
+ /**
38946
+ * Orthogonal intents (updated 2026-08-15 Asia/Shanghai):
38947
+ * 1. Preserve every process-level fact from an OpenSpec CLI invocation.
38948
+ * 2. Validate command payloads without discarding the raw JSON document.
38949
+ * 3. Surface contract drift separately from CLI command failure.
38950
+ * 4. Provide the runtime transport-envelope schema for browser evidence boundaries.
38951
+ *
38952
+ * Original request (2026-07-15): "对新增字段保持可扩展,对必需语义严格验证。"
38953
+ * Original request (2026-08-15): "v9的适配需要同时适配 1.8和1.9。"
38954
+ */
38955
+ /** Runtime schema for one JSON value retained verbatim from CLI stdout. */
38956
+ var CliJsonValueSchema$1 = lazyType(() => unionType([
38957
+ stringType(),
38958
+ numberType(),
38959
+ booleanType(),
38960
+ nullType(),
38961
+ arrayType(CliJsonValueSchema$1),
38962
+ recordType(stringType(), CliJsonValueSchema$1)
38963
+ ]));
38964
+ /** Runtime transport envelope for one CLI command result. */
38965
+ var CliCommandTransportSchema = objectType({
38966
+ success: booleanType(),
38967
+ stdout: stringType(),
38968
+ stderr: stringType(),
38969
+ exitCode: numberType().int().nullable(),
38970
+ data: CliJsonValueSchema$1.nullable(),
38971
+ payload: CliJsonValueSchema$1.nullable(),
38972
+ diagnostics: arrayType(CliDiagnosticSchema),
38973
+ contractError: stringType().optional()
38974
+ });
38975
+ //#endregion
38976
+ //#region ../core/src/cli-contracts/schema-resolution.ts
38977
+ /**
38978
+ * Orthogonal intents (created 2026-08-15 Asia/Shanghai):
38979
+ * 1. Decode `schemas --json` as a success-array or selected-Root failure sum type.
38980
+ * 2. Keep the 1.9 failure envelope's diagnostics and absent Root distinct from an empty catalog.
38981
+ * 3. Reuse the shared SchemaInfo entry shape across success and failure envelopes.
38982
+ * 4. Keep the sum type importable from browser-safe Core consumers without workflow contracts.
38983
+ *
38984
+ * Original request (2026-08-15): "v9的适配需要同时适配 1.8和1.9。"
38985
+ */
38986
+ /** One workflow schema discovered by the CLI-selected OpenSpec runtime. */
38987
+ var CliSchemaInfoSchema = objectType({
38988
+ name: stringType(),
38989
+ description: stringType().optional(),
38990
+ artifacts: arrayType(stringType()),
38991
+ source: enumType([
38992
+ "project",
38993
+ "user",
38994
+ "package"
38995
+ ])
38996
+ }).passthrough();
38997
+ unionType([arrayType(CliSchemaInfoSchema), objectType({
38998
+ schemas: arrayType(CliSchemaInfoSchema),
38999
+ root: nullType(),
39000
+ status: arrayType(CliDiagnosticSchema).min(1)
39001
+ }).passthrough()]);
39002
+ //#endregion
38944
39003
  //#region ../core/src/cli-contracts/store.ts
38945
39004
  /**
38946
39005
  * Orthogonal intents (created 2026-07-15 Asia/Shanghai):
@@ -39088,18 +39147,6 @@ objectType({
39088
39147
  root: CliRootSchema.nullable(),
39089
39148
  status: arrayType(CliDiagnosticSchema).optional()
39090
39149
  }).passthrough();
39091
- /** One workflow schema discovered by the CLI-selected OpenSpec runtime. */
39092
- var CliSchemaInfoSchema = objectType({
39093
- name: stringType(),
39094
- description: stringType().optional(),
39095
- artifacts: arrayType(stringType()),
39096
- source: enumType([
39097
- "project",
39098
- "user",
39099
- "package"
39100
- ])
39101
- }).passthrough();
39102
- arrayType(CliSchemaInfoSchema);
39103
39150
  /** CLI resolution for one schema, including lower-priority shadows. */
39104
39151
  var CliSchemaShadowSchema = objectType({
39105
39152
  source: enumType([
@@ -39189,7 +39236,8 @@ unionType([objectType({
39189
39236
  planningHome: CliPlanningHomeSchema,
39190
39237
  changeRoot: stringType(),
39191
39238
  artifactPaths: recordType(CliArtifactPathSchema),
39192
- isComplete: booleanType(),
39239
+ isPlanningComplete: booleanType(),
39240
+ isComplete: booleanType().optional(),
39193
39241
  applyRequires: arrayType(stringType()),
39194
39242
  nextSteps: arrayType(stringType()),
39195
39243
  actionContext: CliActionContextSchema,
@@ -39272,7 +39320,8 @@ var CliValidationTotalsSchema = objectType({
39272
39320
  passed: numberType(),
39273
39321
  failed: numberType()
39274
39322
  }).passthrough();
39275
- unionType([objectType({
39323
+ /** Typed ordinary Validate report, also used by 1.9 `validate --archived --json`. */
39324
+ var CliValidateReportSchema = objectType({
39276
39325
  items: arrayType(objectType({
39277
39326
  id: stringType(),
39278
39327
  type: enumType(["change", "spec"]),
@@ -39286,7 +39335,8 @@ unionType([objectType({
39286
39335
  }).passthrough(),
39287
39336
  version: stringType(),
39288
39337
  root: CliRootSchema
39289
- }).passthrough(), CliDiagnosticFailureSchema]);
39338
+ }).passthrough();
39339
+ unionType([CliValidateReportSchema, CliDiagnosticFailureSchema]);
39290
39340
  var CliArchiveTotalsSchema = objectType({
39291
39341
  added: numberType(),
39292
39342
  modified: numberType(),
@@ -39299,7 +39349,8 @@ objectType({
39299
39349
  archivedAs: stringType(),
39300
39350
  path: stringType(),
39301
39351
  specsUpdated: booleanType(),
39302
- totals: CliArchiveTotalsSchema.optional()
39352
+ totals: CliArchiveTotalsSchema.optional(),
39353
+ warnings: arrayType(stringType()).optional()
39303
39354
  }).passthrough().nullable(),
39304
39355
  root: CliRootSchema.optional(),
39305
39356
  status: arrayType(CliDiagnosticSchema).optional()
@@ -39993,7 +40044,7 @@ function buildChangeStatus(snapshot, change, preferredSchema) {
39993
40044
  return {
39994
40045
  changeName: change.id,
39995
40046
  schemaName,
39996
- isComplete: artifacts.length > 0 && artifacts.every((artifact) => artifact.status === "done"),
40047
+ isPlanningComplete: artifacts.length > 0 && artifacts.every((artifact) => artifact.status === "done"),
39997
40048
  applyRequires: schemaDetail.applyRequires ?? [],
39998
40049
  artifacts,
39999
40050
  provenance: { kind: "static" }
@@ -40180,6 +40231,7 @@ async function getDashboardOverview() {
40180
40231
  id: change.id,
40181
40232
  name: change.name,
40182
40233
  trackedTaskProgress: change.trackedTaskProgress,
40234
+ cliTaskSummary: change.cliTaskSummary ?? null,
40183
40235
  updatedAt: change.updatedAt
40184
40236
  }));
40185
40237
  const activeChanges = selectRecentDashboardItems(allActiveChanges);
@@ -40311,7 +40363,8 @@ async function getChanges() {
40311
40363
  trackedTaskProgress: change.trackedTaskProgress,
40312
40364
  documentChecklistSummary: change.documentChecklistSummary,
40313
40365
  createdAt: change.createdAt,
40314
- updatedAt: change.updatedAt
40366
+ updatedAt: change.updatedAt,
40367
+ cliTaskSummary: change.cliTaskSummary ?? null
40315
40368
  }));
40316
40369
  }
40317
40370
  /**
@@ -40465,9 +40518,23 @@ async function getConfig$1() {
40465
40518
  async function getOpsxProjectConfig() {
40466
40519
  return (await loadSnapshot())?.opsx?.configYaml ?? null;
40467
40520
  }
40521
+ /** Typed static projection error raised when the export captured a schemas-observation failure. */
40522
+ var StaticSchemasCaptureError = class extends Error {
40523
+ constructor(capture) {
40524
+ super(capture.diagnostics.length > 0 ? capture.diagnostics.map((diagnostic) => diagnostic.message).join("\n") : capture.stderr.trim() || "The static schemas observation failed.");
40525
+ this.capture = capture;
40526
+ this.name = "StaticSchemasCaptureError";
40527
+ }
40528
+ };
40529
+ /** Reject list and bundle reads when the export captured a schemas-observation failure. */
40530
+ function assertSchemasCaptureCaptured(snapshot) {
40531
+ const capture = snapshot?.opsx?.schemasCapture;
40532
+ if (capture && capture.ok === false) throw new StaticSchemasCaptureError(capture);
40533
+ }
40468
40534
  /** Return the static Schema list together with its detail and resolution projections. */
40469
40535
  async function getOpsxConfigBundle() {
40470
40536
  const snapshot = await loadSnapshot();
40537
+ assertSchemasCaptureCaptured(snapshot);
40471
40538
  return {
40472
40539
  schemas: snapshot?.opsx?.schemas ?? [],
40473
40540
  schemaDetails: snapshot?.opsx?.schemaDetails ?? {},
@@ -40477,6 +40544,7 @@ async function getOpsxConfigBundle() {
40477
40544
  /** Return exported templates for the requested Schema, or the snapshot default Schema. */
40478
40545
  async function getOpsxTemplates(schema) {
40479
40546
  const snapshot = await loadSnapshot();
40547
+ assertSchemasCaptureCaptured(snapshot);
40480
40548
  if (!snapshot?.opsx?.templates) return null;
40481
40549
  if (!schema) {
40482
40550
  const first = Object.keys(snapshot.opsx.templates)[0];
@@ -40497,6 +40565,7 @@ async function getOpsxTemplates(schema) {
40497
40565
  /** Reconstruct the exported file tree for one Schema without enabling mutations. */
40498
40566
  async function getOpsxSchemaFiles(name) {
40499
40567
  const snapshot = await loadSnapshot();
40568
+ assertSchemasCaptureCaptured(snapshot);
40500
40569
  if (!snapshot?.opsx) return null;
40501
40570
  let schemaName = name;
40502
40571
  if (!schemaName) schemaName = snapshot.opsx.schemas?.[0]?.name ?? Object.keys(snapshot.opsx.schemaDetails ?? {})[0];
@@ -40542,6 +40611,7 @@ async function getOpsxSchemaFiles(name) {
40542
40611
  /** Return all exported template documents for the requested or default Schema. */
40543
40612
  async function getOpsxTemplateContents(schema) {
40544
40613
  const snapshot = await loadSnapshot();
40614
+ assertSchemasCaptureCaptured(snapshot);
40545
40615
  if (!snapshot?.opsx) return null;
40546
40616
  const targetSchema = schema ?? snapshot.opsx.schemas?.[0]?.name ?? Object.keys(snapshot.opsx.templates ?? {})[0] ?? null;
40547
40617
  if (!targetSchema) return null;
@@ -43124,16 +43194,15 @@ function createApplyInstructionProgress(input, trackedTaskProgress) {
43124
43194
  //#endregion
43125
43195
  //#region ../core/src/opsx-types.ts
43126
43196
  /**
43127
- * Orthogonal intents (updated 2026-08-01 Asia/Shanghai):
43128
- * 1. Define reactive Change Status and Instructions projections.
43129
- * 2. Preserve live CLI path/action/Reference provenance versus explicit static absence.
43130
- * 3. Attribute Apply instruction progress without replacing tracked-task truth.
43131
- * 4. Define schema, template, skipped-dependency, and operation-input projections for OPSX surfaces.
43132
- * 5. Publish runtime schemas for final Projection Work payloads, including transformed Apply progress.
43133
- *
43134
- * Original request (2026-07-15): "Preserve CLI-provided paths, action context, References, and diagnostics end to end."
43135
- * Original request (2026-07-23): "OPSX Status 不应等待完整 Kernel warmup,且必须保留 CLI evidence。"
43136
- * Original request (2026-07-26): "展开全面的接口升级和内核升级和测试升级。"
43197
+ * Orthogonal intents (updated 2026-08-15 Asia/Shanghai):
43198
+ * 1. Publish runtime schemas for final Projection Work payloads, including transformed Apply progress.
43199
+ * 2. Keep isPlanningComplete as the authoritative planning fact over any local tracked alias.
43200
+ * 3. Carry CLI status evidence, diagnostics, and per-artifact requires as typed facts.
43201
+ * 4. Preserve root-context and store projections as browser-safe contracts.
43202
+ * 5. Keep projection notices distinct from payload data so failures never masquerade as results.
43203
+ *
43204
+ * Original request (2026-07-15): "为内核载荷建立强类型。"
43205
+ * Original request (2026-08-15): "v9的适配需要同时适配 1.8和1.9。"
43137
43206
  */
43138
43207
  /** Runtime schema for one JSON value retained from a CLI Status stdout document. */
43139
43208
  var OpsxCliJsonValueSchema = lazyType(() => unionType([
@@ -43183,7 +43252,7 @@ var ArtifactStatusSchema = objectType({
43183
43252
  var ChangeStatusSchema = objectType({
43184
43253
  changeName: stringType(),
43185
43254
  schemaName: stringType(),
43186
- isComplete: booleanType(),
43255
+ isPlanningComplete: booleanType(),
43187
43256
  applyRequires: arrayType(stringType()),
43188
43257
  artifacts: arrayType(ArtifactStatusSchema),
43189
43258
  provenance: discriminatedUnionType("kind", [objectType({
@@ -43418,6 +43487,17 @@ var PlanningCliProjectionStateSchema = createCliProjectionStateSchema(discrimina
43418
43487
  objectType({
43419
43488
  kind: literalType("opsx-change-list"),
43420
43489
  value: arrayType(stringType()),
43490
+ entries: arrayType(objectType({
43491
+ name: stringType(),
43492
+ completedTasks: numberType(),
43493
+ totalTasks: numberType(),
43494
+ lastModified: stringType(),
43495
+ status: enumType([
43496
+ "no-tasks",
43497
+ "complete",
43498
+ "in-progress"
43499
+ ])
43500
+ })),
43421
43501
  evidence: CliProjectionCommandEvidenceSchema
43422
43502
  }),
43423
43503
  objectType({
@@ -71019,7 +71099,7 @@ var browserExt = {
71019
71099
  },
71020
71100
  test: () => true,
71021
71101
  load: async () => {
71022
- await import("./browserAll-C3TgySxy.js");
71102
+ await import("./browserAll-BNHXRTWn.js");
71023
71103
  }
71024
71104
  };
71025
71105
  //#endregion
@@ -71032,7 +71112,7 @@ var webworkerExt = {
71032
71112
  },
71033
71113
  test: () => typeof self !== "undefined" && self.WorkerGlobalScope !== void 0,
71034
71114
  load: async () => {
71035
- await import("./webworkerAll-jouzdRxg.js");
71115
+ await import("./webworkerAll-6pG_bTSk.js");
71036
71116
  }
71037
71117
  };
71038
71118
  //#endregion
@@ -73626,7 +73706,7 @@ async function autoDetectRenderer(options) {
73626
73706
  for (let i = 0; i < preferredOrder.length; i++) {
73627
73707
  const rendererType = preferredOrder[i];
73628
73708
  if (rendererType === "webgpu" && await isWebGPUSupported()) {
73629
- const { WebGPURenderer } = await import("./WebGPURenderer-CzqH7K0F.js");
73709
+ const { WebGPURenderer } = await import("./WebGPURenderer--JR4o1Id.js");
73630
73710
  RendererClass = WebGPURenderer;
73631
73711
  finalOptions = {
73632
73712
  ...options,
@@ -73634,7 +73714,7 @@ async function autoDetectRenderer(options) {
73634
73714
  };
73635
73715
  break;
73636
73716
  } else if (rendererType === "webgl" && isWebGLSupported(options.failIfMajorPerformanceCaveat ?? AbstractRenderer.defaultOptions.failIfMajorPerformanceCaveat)) {
73637
- const { WebGLRenderer } = await import("./WebGLRenderer-VYeMuiRZ.js");
73717
+ const { WebGLRenderer } = await import("./WebGLRenderer-BG7MkvqA.js");
73638
73718
  RendererClass = WebGLRenderer;
73639
73719
  finalOptions = {
73640
73720
  ...options,
@@ -73642,7 +73722,7 @@ async function autoDetectRenderer(options) {
73642
73722
  };
73643
73723
  break;
73644
73724
  } else if (rendererType === "canvas") {
73645
- const { CanvasRenderer } = await import("./CanvasRenderer-2gUSLPR3.js");
73725
+ const { CanvasRenderer } = await import("./CanvasRenderer-Cud3mH2M.js");
73646
73726
  RendererClass = CanvasRenderer;
73647
73727
  finalOptions = {
73648
73728
  ...options,
@@ -97391,7 +97471,7 @@ var TerminalController = class {
97391
97471
  if (this.configPersistTimer) clearTimeout(this.configPersistTimer);
97392
97472
  this.configPersistTimer = setTimeout(() => {
97393
97473
  this.configPersistTimer = null;
97394
- import("./trpc-BZ-LKmoQ.js").then(({ trpcClient }) => {
97474
+ import("./trpc-DMtttD_4.js").then(({ trpcClient }) => {
97395
97475
  trpcClient.config.update.mutate({ terminal: { fontSize: this.config.fontSize } });
97396
97476
  }).catch(() => {});
97397
97477
  }, CONFIG_PERSIST_DEBOUNCE);
@@ -98960,6 +99040,42 @@ function ConfigFormSkeleton({ fields = 4 }) {
98960
99040
  });
98961
99041
  }
98962
99042
  //#endregion
99043
+ //#region src/components/realtime/shiny-status.tsx
99044
+ /**
99045
+ * Orthogonal intents (created 2026-08-15 Asia/Shanghai):
99046
+ * 1. Animate normal-lifecycle text (loading/resolving/refreshing) with the shiny-text luminance language.
99047
+ * 2. Compose it into one keyboard-reachable Badge whose complete meaning lives in a Tooltip.
99048
+ * 3. Keep the polite live-region semantic for assistive tech without occupying layout space.
99049
+ *
99050
+ * Original request (2026-08-15): 刷新/解析中的块级 Alert 改为 Animated Shiny Text + Tooltip,不占界面空间。
99051
+ * Boundary: terminal errors/empty/block states are NOT normal lifecycle — they keep text notices.
99052
+ */
99053
+ /** Normal-lifecycle text whose luminance sweep replaces a block-level loading notice. */
99054
+ function AnimatedShinyText({ children, className }) {
99055
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
99056
+ className: cn$1("rt-shiny-text", className),
99057
+ children
99058
+ });
99059
+ }
99060
+ /**
99061
+ * One inline lifecycle badge: shiny label + Tooltip message + hidden live region.
99062
+ * The accessible status carries the full message so `getByRole('status')` semantics survive.
99063
+ */
99064
+ function ShinyStatusBadge({ label, message, className, ...badgeProps }) {
99065
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Tooltip, {
99066
+ content: message,
99067
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, {
99068
+ role: "note",
99069
+ tabIndex: 0,
99070
+ "aria-label": message,
99071
+ tone: "muted",
99072
+ className: cn$1("focus-visible:ring-primary cursor-help px-1.5 text-[11px] font-medium outline-none focus-visible:ring-2 focus-visible:ring-offset-2", className),
99073
+ ...badgeProps,
99074
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AnimatedShinyText, { children: label })
99075
+ })
99076
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AccessibleStatus, { children: message })] });
99077
+ }
99078
+ //#endregion
98963
99079
  //#region src/lib/format-time.ts
98964
99080
  /**
98965
99081
  * Format a timestamp as relative time (e.g., "2 hours ago", "3 days ago")
@@ -107916,7 +108032,7 @@ var languages = [
107916
108032
  name: "CSS",
107917
108033
  extensions: ["css"],
107918
108034
  load() {
107919
- return import("./dist-Cr2VaH_X.js").then((m) => m.css());
108035
+ return import("./dist-CpgxMd46.js").then((m) => m.css());
107920
108036
  }
107921
108037
  }),
107922
108038
  /* @__PURE__ */ LanguageDescription.of({
@@ -107936,7 +108052,7 @@ var languages = [
107936
108052
  "hbs"
107937
108053
  ],
107938
108054
  load() {
107939
- return import("./dist-CcweeoW2.js").then((m) => m.html());
108055
+ return import("./dist-BZwNiEjE.js").then((m) => m.html());
107940
108056
  }
107941
108057
  }),
107942
108058
  /* @__PURE__ */ LanguageDescription.of({
@@ -107970,7 +108086,7 @@ var languages = [
107970
108086
  "jinja2"
107971
108087
  ],
107972
108088
  load() {
107973
- return import("./dist-DxUyXTq1.js").then((m) => m.jinja());
108089
+ return import("./dist-CSnQ9MUZ.js").then((m) => m.jinja());
107974
108090
  }
107975
108091
  }),
107976
108092
  /* @__PURE__ */ LanguageDescription.of({
@@ -107978,7 +108094,7 @@ var languages = [
107978
108094
  alias: ["json5"],
107979
108095
  extensions: ["json", "map"],
107980
108096
  load() {
107981
- return import("./dist-CuufxmlH.js").then((m) => m.json());
108097
+ return import("./dist-vPFtDCqy.js").then((m) => m.json());
107982
108098
  }
107983
108099
  }),
107984
108100
  /* @__PURE__ */ LanguageDescription.of({
@@ -107992,14 +108108,14 @@ var languages = [
107992
108108
  name: "LESS",
107993
108109
  extensions: ["less"],
107994
108110
  load() {
107995
- return import("./dist-C0UE33e7.js").then((m) => m.less());
108111
+ return import("./dist-CD_P89TI.js").then((m) => m.less());
107996
108112
  }
107997
108113
  }),
107998
108114
  /* @__PURE__ */ LanguageDescription.of({
107999
108115
  name: "Liquid",
108000
108116
  extensions: ["liquid"],
108001
108117
  load() {
108002
- return import("./dist-BQopLPgi.js").then((m) => m.liquid());
108118
+ return import("./dist-TFBLKdTC.js").then((m) => m.liquid());
108003
108119
  }
108004
108120
  }),
108005
108121
  /* @__PURE__ */ LanguageDescription.of({
@@ -108016,7 +108132,7 @@ var languages = [
108016
108132
  "mkd"
108017
108133
  ],
108018
108134
  load() {
108019
- return import("./dist-DHRASvmg.js").then((m) => m.markdown());
108135
+ return import("./dist-tvIcsOn0.js").then((m) => m.markdown());
108020
108136
  }
108021
108137
  }),
108022
108138
  /* @__PURE__ */ LanguageDescription.of({
@@ -108042,7 +108158,7 @@ var languages = [
108042
108158
  "phtml"
108043
108159
  ],
108044
108160
  load() {
108045
- return import("./dist-CqznyH3C.js").then((m) => m.php());
108161
+ return import("./dist-BTzm9CCH.js").then((m) => m.php());
108046
108162
  }
108047
108163
  }),
108048
108164
  /* @__PURE__ */ LanguageDescription.of({
@@ -108082,14 +108198,14 @@ var languages = [
108082
108198
  name: "Sass",
108083
108199
  extensions: ["sass"],
108084
108200
  load() {
108085
- return import("./dist-DukPjaq8.js").then((m) => m.sass({ indented: true }));
108201
+ return import("./dist-Bg6kJ4lE.js").then((m) => m.sass({ indented: true }));
108086
108202
  }
108087
108203
  }),
108088
108204
  /* @__PURE__ */ LanguageDescription.of({
108089
108205
  name: "SCSS",
108090
108206
  extensions: ["scss"],
108091
108207
  load() {
108092
- return import("./dist-DukPjaq8.js").then((m) => m.sass());
108208
+ return import("./dist-Bg6kJ4lE.js").then((m) => m.sass());
108093
108209
  }
108094
108210
  }),
108095
108211
  /* @__PURE__ */ LanguageDescription.of({
@@ -108156,7 +108272,7 @@ var languages = [
108156
108272
  alias: ["yml"],
108157
108273
  extensions: ["yaml", "yml"],
108158
108274
  load() {
108159
- return import("./dist-D-tZhX9W.js").then((m) => m.yaml());
108275
+ return import("./dist-gfV2B0G7.js").then((m) => m.yaml());
108160
108276
  }
108161
108277
  }),
108162
108278
  /* @__PURE__ */ LanguageDescription.of({
@@ -109043,13 +109159,13 @@ var languages = [
109043
109159
  name: "Vue",
109044
109160
  extensions: ["vue"],
109045
109161
  load() {
109046
- return import("./dist-BSYA61e0.js").then((m) => m.vue());
109162
+ return import("./dist-CzfcaAEs.js").then((m) => m.vue());
109047
109163
  }
109048
109164
  }),
109049
109165
  /* @__PURE__ */ LanguageDescription.of({
109050
109166
  name: "Angular Template",
109051
109167
  load() {
109052
- return import("./dist-BQhB00FX.js").then((m) => m.angular());
109168
+ return import("./dist-CkE7XypO.js").then((m) => m.angular());
109053
109169
  }
109054
109170
  })
109055
109171
  ];
@@ -169275,7 +169391,14 @@ function ReadonlyKanbanRow({ item, laneId, compact }) {
169275
169391
  family: archived ? "archive" : "changes",
169276
169392
  entityId: item.id
169277
169393
  };
169278
- const progress = item.trackedTaskProgress;
169394
+ const cli = item.cliTaskSummary ?? null;
169395
+ const progress = cli ? {
169396
+ completed: cli.completedTasks,
169397
+ total: cli.totalTasks
169398
+ } : {
169399
+ completed: item.trackedTaskProgress.completed,
169400
+ total: item.trackedTaskProgress.total
169401
+ };
169279
169402
  const percent = progress.total > 0 ? Math.round(progress.completed / progress.total * 100) : 0;
169280
169403
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(VTLink, {
169281
169404
  to: archived ? "/archive/$changeId" : "/changes/$changeId",
@@ -169673,13 +169796,103 @@ function Board() {
169673
169796
  });
169674
169797
  }
169675
169798
  //#endregion
169799
+ //#region src/components/change-row.tsx
169800
+ /**
169801
+ * Orthogonal intents (created 2026-08-15 Asia/Shanghai):
169802
+ * 1. Render one Change row with a grid: icon, title/subtitle, and a right rail.
169803
+ * 2. Keep the phase badge vertically centered while the time anchors the rail bottom.
169804
+ * 3. Share the exact row vocabulary between the Changes list and Dashboard.
169805
+ * 4. Preserve shared-element bindings for View Transition continuity.
169806
+ * 5. Fill the phase badge with a proportional background when a progress ratio exists —
169807
+ * an ambient progress signal that survives subtitle truncation on narrow viewports.
169808
+ *
169809
+ * Original request (2026-08-15): Owner walkthrough: grid layout, subtitle facts, badge
169810
+ * centered with time at the bottom, one atomic row component across pages.
169811
+ * Original request (2026-08-16): Owner walkthrough: use a soft primary fill behind the
169812
+ * Applying badge as a space-free progress affordance for mobile truncation.
169813
+ */
169814
+ /**
169815
+ * Ambient fill layer behind the phase badge: a soft primary wash sized to the applied-task
169816
+ * ratio. It carries no text and claims no layout — a visual progress hint that stays
169817
+ * readable when the row's subtitle facts are truncated on narrow viewports.
169818
+ */
169819
+ function PhaseBadgeProgressFill({ ratio }) {
169820
+ if (!Number.isFinite(ratio) || ratio <= 0) return null;
169821
+ const clamped = Math.min(100, Math.max(0, ratio * 100));
169822
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
169823
+ "aria-hidden": "true",
169824
+ className: "bg-primary/50 pointer-events-none absolute inset-y-0 left-0 rounded-[inherit]",
169825
+ style: { width: `${clamped}%` }
169826
+ });
169827
+ }
169828
+ /** Shared Change-row layout: icon | title+subtitle | badge(time) | chevron. */
169829
+ function ChangeRow({ changeId, name, subtitle, phase, updatedAt, formatTime, sharedFamily = "changes", className = "", progressRatio = null, containerProps, titleProps, iconProps }) {
169830
+ const sharedDescriptor = {
169831
+ family: sharedFamily,
169832
+ entityId: changeId
169833
+ };
169834
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
169835
+ ...containerProps,
169836
+ ...getSharedElementBinding(sharedDescriptor, "container"),
169837
+ className: `grid grid-cols-[auto_minmax(0,1fr)_auto] items-stretch gap-x-3 ${className}`,
169838
+ children: [
169839
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
169840
+ className: "flex items-center",
169841
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitBranch, {
169842
+ ...iconProps,
169843
+ ...getSharedElementBinding(sharedDescriptor, "icon"),
169844
+ className: "text-muted-foreground h-5 w-5 shrink-0"
169845
+ })
169846
+ }),
169847
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
169848
+ className: "flex min-w-0 flex-col justify-center gap-0.5 py-0.5",
169849
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
169850
+ ...titleProps,
169851
+ ...getSharedElementBinding(sharedDescriptor, "title"),
169852
+ className: "truncate font-medium",
169853
+ children: name
169854
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
169855
+ className: "text-muted-foreground truncate text-xs",
169856
+ children: subtitle
169857
+ })]
169858
+ }),
169859
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
169860
+ className: "flex flex-col items-end justify-between gap-1 text-right",
169861
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
169862
+ className: "flex flex-1 items-center",
169863
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge, {
169864
+ tone: "custom",
169865
+ size: "sm",
169866
+ shape: "box",
169867
+ className: `relative overflow-hidden border ${phase.toneClass}`,
169868
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PhaseBadgeProgressFill, { ratio: progressRatio ?? NaN }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
169869
+ className: "relative",
169870
+ children: phase.label
169871
+ })]
169872
+ })
169873
+ }), updatedAt > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
169874
+ className: "text-muted-foreground shrink-0 text-xs",
169875
+ children: formatTime(updatedAt)
169876
+ }) : null]
169877
+ })
169878
+ ]
169879
+ });
169880
+ }
169881
+ /** Chevron affordance kept outside the grid so row layouts stay composable. */
169882
+ function ChangeRowChevron() {
169883
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronRight, {
169884
+ className: "text-muted-foreground h-4 w-4 shrink-0",
169885
+ "aria-hidden": true
169886
+ });
169887
+ }
169888
+ //#endregion
169676
169889
  //#region src/lib/change-workflow-phase.ts
169677
169890
  function classifyChangeWorkflowPhase(params) {
169678
169891
  if (!params.hasStatus) return {
169679
169892
  label: "Unknown",
169680
169893
  toneClass: "border-border text-muted-foreground"
169681
169894
  };
169682
- if (params.isComplete && params.trackedTaskPhase === "complete") return {
169895
+ if (params.isPlanningComplete && params.trackedTaskPhase === "complete") return {
169683
169896
  label: "Workflow Complete",
169684
169897
  toneClass: "border-emerald-500/40 text-emerald-700 dark:text-emerald-300"
169685
169898
  };
@@ -169691,6 +169904,15 @@ function classifyChangeWorkflowPhase(params) {
169691
169904
  label: "No Tracked Tasks",
169692
169905
  toneClass: "border-border text-muted-foreground"
169693
169906
  };
169907
+ const applied = params.cliCompletedTasks ?? null;
169908
+ if (applied !== null && applied > 0) return {
169909
+ label: "Applying",
169910
+ toneClass: "border-primary/40 text-primary"
169911
+ };
169912
+ if (params.isPlanningComplete) return {
169913
+ label: "Planning Complete",
169914
+ toneClass: "border-sky-500/40 text-sky-700 dark:text-sky-300"
169915
+ };
169694
169916
  return {
169695
169917
  label: "In Execution",
169696
169918
  toneClass: "border-primary/40 text-primary"
@@ -169780,7 +170002,7 @@ function useChangeListContinuity(incomingChanges, containerRef) {
169780
170002
  //#endregion
169781
170003
  //#region src/routes/change-list.tsx
169782
170004
  /**
169783
- * Orthogonal intents (updated 2026-07-27 Asia/Shanghai):
170005
+ * Orthogonal intents (updated 2026-08-15 Asia/Shanghai):
169784
170006
  * 1. List only active Changes from the current writable Planning root.
169785
170007
  * 2. Derive workflow state and terminal evidence from CLI Status and formal tracked-task progress.
169786
170008
  * 3. Preserve ChangeList row continuity and stale display together with collision-safe detail navigation.
@@ -169793,6 +170015,8 @@ function useChangeListContinuity(incomingChanges, containerRef) {
169793
170015
  *
169794
170016
  * Original request (2026-07-15): "One project backend has one launch project and one CLI-selected writable planning root."
169795
170017
  * Original request (2026-07-21): "Changes页面的右上角没有 New,你要不要快速补一个"
170018
+
170019
+ * Original request (2026-08-15): "v9的适配需要同时适配 1.8和1.9。"
169796
170020
  */
169797
170021
  function buildStatusMap(statuses) {
169798
170022
  return new Map((statuses ?? []).map((status) => [status.changeName, status]));
@@ -169915,16 +170139,16 @@ function ChangeList() {
169915
170139
  const totalArtifacts = status?.artifacts.length ?? 0;
169916
170140
  const phase = classifyChangeWorkflowPhase({
169917
170141
  hasStatus: Boolean(status),
169918
- isComplete: status?.isComplete ?? false,
170142
+ isPlanningComplete: status?.isPlanningComplete ?? false,
169919
170143
  trackedTaskPhase: change.trackedTaskProgress.phase,
169920
- trackedArtifactStatus: inferTrackedArtifactStatus(status?.artifacts.map((artifact) => artifact.status) ?? [])
170144
+ trackedArtifactStatus: inferTrackedArtifactStatus(status?.artifacts.map((artifact) => artifact.status) ?? []),
170145
+ cliCompletedTasks: change.cliTaskSummary?.completedTasks ?? null
169921
170146
  });
169922
- const taskPercent = change.trackedTaskProgress.total > 0 ? Math.round(change.trackedTaskProgress.completed / change.trackedTaskProgress.total * 100) : 0;
169923
170147
  const sharedDescriptor = {
169924
170148
  family: "changes",
169925
170149
  entityId: change.id
169926
170150
  };
169927
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(VTLink, {
170151
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VTLink, {
169928
170152
  to: "/changes/$changeId",
169929
170153
  params: { changeId: change.id },
169930
170154
  state: (prev) => ({
@@ -169939,74 +170163,30 @@ function ChangeList() {
169939
170163
  vt: { sharedElements: sharedDescriptor },
169940
170164
  ...getSharedElementBinding(sharedDescriptor, "container"),
169941
170165
  className: "hover:bg-muted/50 block px-4 py-3",
169942
- children: [
169943
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
169944
- className: "mb-2 flex items-center justify-between gap-3",
169945
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
169946
- className: "flex min-w-0 items-start gap-3",
169947
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitBranch, {
169948
- ...getSharedElementBinding(sharedDescriptor, "icon"),
169949
- className: "text-muted-foreground mt-0.5 h-5 w-5 shrink-0"
169950
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
169951
- className: "min-w-0",
169952
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
169953
- ...getSharedElementBinding(sharedDescriptor, "title"),
169954
- className: "truncate font-medium",
169955
- children: change.name
169956
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
169957
- className: "text-muted-foreground truncate text-sm",
169958
- children: [change.id, change.updatedAt > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [" · ", formatRelativeTime(change.updatedAt)] })]
169959
- })]
169960
- })]
169961
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
169962
- className: "flex items-center gap-3",
169963
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
169964
- className: "flex flex-col items-end gap-1 text-right text-sm",
169965
- children: [
169966
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, {
169967
- tone: "custom",
169968
- size: "sm",
169969
- shape: "box",
169970
- className: `border ${phase.toneClass}`,
169971
- children: phase.label
169972
- }),
169973
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
169974
- className: "font-medium",
169975
- children: [
169976
- change.trackedTaskProgress.completed,
169977
- "/",
169978
- change.trackedTaskProgress.total
169979
- ]
169980
- }),
169981
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
169982
- className: "text-muted-foreground text-xs",
169983
- children: "tasks"
169984
- })
169985
- ]
169986
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronRight, { className: "text-muted-foreground h-4 w-4 shrink-0" })]
169987
- })]
169988
- }),
169989
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
169990
- className: "bg-muted h-1.5 rounded-full",
169991
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
169992
- className: "bg-primary h-full rounded-full transition-all",
169993
- style: { width: `${taskPercent}%` }
169994
- })
169995
- }),
169996
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
169997
- className: "text-muted-foreground mt-2 flex flex-wrap items-center justify-between gap-2 text-xs",
169998
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: change.trackedTaskProgress.phase === "no-tasks" ? "No tracked tasks" : `${taskPercent}% task completion` }), !statusError && status ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
169999
- className: "truncate",
170166
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
170167
+ className: "flex items-center gap-3",
170168
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeRow, {
170169
+ changeId: change.id,
170170
+ name: change.name,
170171
+ phase,
170172
+ updatedAt: change.updatedAt,
170173
+ formatTime: formatRelativeTime,
170174
+ progressRatio: change.cliTaskSummary && change.cliTaskSummary.totalTasks > 0 ? change.cliTaskSummary.completedTasks / change.cliTaskSummary.totalTasks : null,
170175
+ className: "min-w-0 flex-1",
170176
+ titleProps: { ...change.id !== change.name ? {} : null },
170177
+ subtitle: !statusError && status ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
170178
+ title: "Task counts reported by the OpenSpec CLI for this Change.",
170000
170179
  children: [
170001
170180
  doneArtifacts,
170002
170181
  "/",
170003
170182
  totalArtifacts,
170004
170183
  " artifacts · ",
170005
- status.schemaName
170184
+ status.schemaName,
170185
+ change.cliTaskSummary ? ` · Tasks ${change.cliTaskSummary.completedTasks}/${change.cliTaskSummary.totalTasks}` : ""
170006
170186
  ]
170007
- }) : !statusError && statuses === void 0 && isStatusLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RealtimeSkeletonLine, { className: "w-28" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Workflow status unavailable" })]
170008
- })
170009
- ]
170187
+ }) : !statusError && statuses === void 0 && isStatusLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RealtimeSkeletonLine, { className: "w-28" }) : "Workflow status unavailable"
170188
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeRowChevron, {})]
170189
+ })
170010
170190
  }, change.id);
170011
170191
  }), hasCurrentEmptyChanges && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
170012
170192
  className: "text-muted-foreground p-4 text-center",
@@ -171034,15 +171214,41 @@ function EvidenceDisclosure({ title, children, summary, defaultOpen = false, cla
171034
171214
  //#endregion
171035
171215
  //#region src/components/apply-progress-notice.tsx
171036
171216
  /**
171037
- * Orthogonal intents (updated 2026-07-28 Asia/Shanghai):
171217
+ * Orthogonal intents (updated 2026-08-15 Asia/Shanghai):
171038
171218
  * 1. Attribute Apply instruction counts to the upstream Apply command.
171039
- * 2. Preserve tracked artifact counts beside divergent Apply evidence.
171040
- * 3. Keep divergence direct while compressing its two objective source counts.
171219
+ * 2. Compress agreement to one subtitle badge; keep divergence a direct blocker.
171220
+ * 3. Keep divergence's two objective source counts side by side with their causes.
171221
+ * 4. Keep tooltips as the keyboard-reachable explanation for every compact count.
171041
171222
  *
171042
171223
  * Original request (2026-07-15): "与 tracked glob 进度分歧时各自归因展示。"
171043
171224
  * Original request (2026-07-28): supporting 6.x evidence should use Badge + Tooltip or Accordion.
171225
+ * Original request (2026-08-15): Owner walkthrough: agreement is one badge in the subtitle row,
171226
+ * not a two-line block; only divergence owns a notice.
171227
+ */
171228
+ /**
171229
+ * One compact, source-attributed Apply progress badge for the Change subtitle row.
171230
+ * The Apply instruction result is the only visible implementation progress authority, so
171231
+ * this stays rendered whenever instructions exist — agreement is not a reason to hide the
171232
+ * CLI's own count, but it needs no separate block.
171233
+ */
171234
+ function ApplyProgressBadge({ applyInstructionProgress }) {
171235
+ const { complete, total, remaining } = applyInstructionProgress;
171236
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(InformationBadge, {
171237
+ ariaLabel: `Apply instructions progress ${complete} of ${total}`,
171238
+ tooltip: `Progress reported by openspec instructions apply — ${complete} of ${total} tasks applied, ${remaining} remaining.`,
171239
+ children: [
171240
+ "Apply ",
171241
+ complete,
171242
+ "/",
171243
+ total
171244
+ ]
171245
+ });
171246
+ }
171247
+ /**
171248
+ * Render the Apply/tracked divergence as one direct, source-attributed blocker. Returns
171249
+ * null when the sources agree — the agreement case lives in the subtitle badge row via
171250
+ * {@link ApplyProgressBadge}.
171044
171251
  */
171045
- /** Render source-attributed Apply progress and any tracked-progress divergence. */
171046
171252
  function ApplyProgressNotice({ applyInstructionProgress }) {
171047
171253
  const divergence = applyInstructionProgress.divergence;
171048
171254
  if (!divergence) return null;
@@ -171064,13 +171270,13 @@ function ApplyProgressNotice({ applyInstructionProgress }) {
171064
171270
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171065
171271
  className: "flex flex-wrap gap-1.5",
171066
171272
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(InformationBadge, {
171067
- ariaLabel: `Apply instructions progress ${divergence.apply.complete} of ${divergence.apply.total}`,
171273
+ ariaLabel: `Apply instructions progress ${applyInstructionProgress.complete} of ${applyInstructionProgress.total}`,
171068
171274
  tooltip: "Progress reported by openspec instructions apply.",
171069
171275
  children: [
171070
171276
  "Apply ",
171071
- divergence.apply.complete,
171277
+ applyInstructionProgress.complete,
171072
171278
  "/",
171073
- divergence.apply.total
171279
+ applyInstructionProgress.total
171074
171280
  ]
171075
171281
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(InformationBadge, {
171076
171282
  ariaLabel: `Tracked artifact glob progress ${divergence.tracked.completed} of ${divergence.tracked.total}`,
@@ -171087,16 +171293,284 @@ function ApplyProgressNotice({ applyInstructionProgress }) {
171087
171293
  })]
171088
171294
  });
171089
171295
  }
171296
+ var OPENSPEC_CLI_SUPPORTED_SERIES = ["1.8", "1.9"];
171297
+ /**
171298
+ * Derive command capabilities from one parsed CLI version.
171299
+ *
171300
+ * Only an admitted version — stable inside the accepted range — can select version-specific
171301
+ * capabilities. Unsupported forms (prereleases, >=1.10, below-range) and unparseable output
171302
+ * keep their mismatch evidence and expose no capability, so a page-level version bypass can
171303
+ * never manufacture a 1.9 command surface for a CLI the release line does not admit.
171304
+ */
171305
+ function deriveOpenSpecCliCapabilities(version) {
171306
+ if (!isAdmittedVersion(version)) return {
171307
+ schemasRootSelector: false,
171308
+ archivedValidation: false
171309
+ };
171310
+ const onTargetSeries = isSeries(version, "1.9");
171311
+ return {
171312
+ schemasRootSelector: onTargetSeries,
171313
+ archivedValidation: onTargetSeries
171314
+ };
171315
+ }
171316
+ function parseOpenSpecCliVersion(raw) {
171317
+ if (!raw) return null;
171318
+ const match = raw.match(/(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?/);
171319
+ if (!match) return null;
171320
+ return {
171321
+ major: Number(match[1]),
171322
+ minor: Number(match[2]),
171323
+ patch: Number(match[3]),
171324
+ prerelease: match[4] ?? null
171325
+ };
171326
+ }
171327
+ function isSeries(version, series) {
171328
+ const [major, minor] = series.split(".").map((part) => Number(part));
171329
+ return version.major === major && version.minor === minor;
171330
+ }
171331
+ function isStable(version) {
171332
+ return version.prerelease === null;
171333
+ }
171334
+ /** True only for stable versions inside the accepted range (current or supported non-current). */
171335
+ function isAdmittedVersion(version) {
171336
+ if (!version || !isStable(version)) return false;
171337
+ return isSeries(version, "1.9") || isSupportedNonCurrentSeries(version);
171338
+ }
171339
+ function isSupportedNonCurrentSeries(version) {
171340
+ return OPENSPEC_CLI_SUPPORTED_SERIES.filter((series) => series !== "1.9").some((series) => isSeries(version, series));
171341
+ }
171342
+ //#endregion
171343
+ //#region src/components/archived-validation-evidence.tsx
171344
+ /**
171345
+ * Orthogonal intents (created 2026-08-15 Asia/Shanghai):
171346
+ * 1. Present OpenSpec 1.9 `validate --archived --json` as typed CLI evidence.
171347
+ * 2. Preserve item issues, totals, root, and exit/failure evidence without repair actions.
171348
+ * 3. Identify the evidence as unavailable in static snapshots instead of fabricating it.
171349
+ * 4. Derive the capability from the detected admitted CLI and hide the action on 1.8.
171350
+ * 5. Validate report payloads with the Core contract schema, never shallow shape guards.
171351
+ *
171352
+ * Original request (2026-08-15): "v9的适配需要同时适配 1.8和1.9。"
171353
+ */
171354
+ function parseValidationReport(value) {
171355
+ const parsed = CliValidateReportSchema.safeParse(value);
171356
+ if (parsed.success) return {
171357
+ report: parsed.data,
171358
+ schemaIssues: []
171359
+ };
171360
+ return {
171361
+ report: null,
171362
+ schemaIssues: parsed.error.issues.map((issue) => `${issue.path.length > 0 ? issue.path.join(".") : "<root>"}: ${issue.message}`)
171363
+ };
171364
+ }
171365
+ function IssueList({ issues }) {
171366
+ if (issues.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
171367
+ className: "text-muted-foreground",
171368
+ children: "No CLI issue reported."
171369
+ });
171370
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", {
171371
+ className: "text-muted-foreground space-y-0.5",
171372
+ children: issues.map((issue, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", {
171373
+ className: "break-words",
171374
+ children: [
171375
+ issue.level,
171376
+ " · ",
171377
+ issue.path,
171378
+ " · ",
171379
+ issue.message
171380
+ ]
171381
+ }, index))
171382
+ });
171383
+ }
171384
+ function RunButton({ pending, label, onRun }) {
171385
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
171386
+ type: "button",
171387
+ onClick: onRun,
171388
+ disabled: pending,
171389
+ "aria-busy": pending || void 0,
171390
+ 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",
171391
+ children: [pending ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, {
171392
+ className: "h-3.5 w-3.5 animate-spin",
171393
+ "aria-hidden": true
171394
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCw, {
171395
+ className: "h-3.5 w-3.5",
171396
+ "aria-hidden": true
171397
+ }), label]
171398
+ });
171399
+ }
171400
+ /** On-demand, read-only archived-task validation evidence for the Change Evidence tab. */
171401
+ function ArchivedValidationEvidence() {
171402
+ const [report, setReport] = (0, import_react.useState)(null);
171403
+ const [error, setError] = (0, import_react.useState)(null);
171404
+ const [pending, setPending] = (0, import_react.useState)(false);
171405
+ const cli = useRootActionState().context?.cli;
171406
+ const capabilities = deriveOpenSpecCliCapabilities(cli?.available ? parseOpenSpecCliVersion(cli.version) : null);
171407
+ if (isStaticMode()) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EvidenceDisclosure, {
171408
+ title: "Archived validation",
171409
+ summary: "Unavailable in static snapshot",
171410
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
171411
+ className: "text-muted-foreground",
171412
+ children: "Archived-task validation is live CLI evidence and is not captured in this static snapshot."
171413
+ })
171414
+ });
171415
+ if (cli?.available === true && !capabilities.archivedValidation) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EvidenceDisclosure, {
171416
+ title: "Archived validation",
171417
+ summary: "Unavailable on this CLI line",
171418
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
171419
+ className: "text-muted-foreground",
171420
+ children: [
171421
+ "Archived-task validation requires the OpenSpec 1.9 line",
171422
+ cli.version ? ` (detected ${cli.version.trim()})` : "",
171423
+ ". This session's CLI does not declare the capability, so no command is offered."
171424
+ ]
171425
+ })
171426
+ });
171427
+ const run = async () => {
171428
+ setPending(true);
171429
+ setError(null);
171430
+ setReport(null);
171431
+ try {
171432
+ const result = await trpcClient.cli.validate.mutate({ kind: "archived" });
171433
+ const transport = CliCommandTransportSchema.safeParse(result);
171434
+ if (transport.success) setReport({
171435
+ ...transport.data,
171436
+ data: transport.data.data ?? null,
171437
+ payload: transport.data.payload ?? null
171438
+ });
171439
+ else setError("The archived validation transport returned an unrecognized result shape.");
171440
+ } catch (cause) {
171441
+ setError(cause instanceof Error ? cause.message : String(cause));
171442
+ } finally {
171443
+ setPending(false);
171444
+ }
171445
+ };
171446
+ if (!report && !error) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EvidenceDisclosure, {
171447
+ title: "Archived validation",
171448
+ summary: "OpenSpec 1.9 archived-task validation",
171449
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171450
+ className: "space-y-2",
171451
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
171452
+ className: "text-muted-foreground",
171453
+ children: "Run the official CLI's archived-task validation and keep its typed report as evidence. OpenSpecUI never repairs or archives from here."
171454
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunButton, {
171455
+ pending,
171456
+ label: "Validate archived tasks",
171457
+ onRun: () => void run()
171458
+ })]
171459
+ })
171460
+ });
171461
+ const parsed = report ? parseValidationReport(report.data) : {
171462
+ report: null,
171463
+ schemaIssues: []
171464
+ };
171465
+ const validationReport = parsed.report;
171466
+ if (error || !validationReport) {
171467
+ const schemaDiagnostic = parsed.schemaIssues.length > 0 ? parsed.schemaIssues.join("; ") : null;
171468
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EvidenceDisclosure, {
171469
+ title: "Archived validation",
171470
+ summary: "CLI failure evidence",
171471
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171472
+ className: "space-y-2",
171473
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171474
+ className: "text-destructive flex items-start gap-2 break-words",
171475
+ role: "alert",
171476
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, {
171477
+ className: "mt-0.5 h-3.5 w-3.5 shrink-0",
171478
+ "aria-hidden": true
171479
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
171480
+ className: "min-w-0 break-all",
171481
+ children: error ?? report?.contractError ?? schemaDiagnostic ?? report?.stderr.trim() ?? "The archived validation command failed."
171482
+ })]
171483
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunButton, {
171484
+ pending,
171485
+ label: "Rerun",
171486
+ onRun: () => void run()
171487
+ })]
171488
+ })
171489
+ });
171490
+ }
171491
+ const validation = validationReport;
171492
+ const failed = validation.summary.totals.failed;
171493
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EvidenceDisclosure, {
171494
+ title: "Archived validation",
171495
+ summary: `${validation.summary.totals.passed} passed · ${failed} failed`,
171496
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171497
+ className: "space-y-3",
171498
+ children: [
171499
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("dl", {
171500
+ className: "@[32rem]:grid-cols-[auto_minmax(0,1fr)] grid min-w-0 gap-x-3 gap-y-1",
171501
+ children: [
171502
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
171503
+ className: "text-muted-foreground",
171504
+ children: "Root"
171505
+ }),
171506
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", {
171507
+ className: "min-w-0 break-all font-mono",
171508
+ children: validation.root.path
171509
+ }),
171510
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
171511
+ className: "text-muted-foreground",
171512
+ children: "Exit"
171513
+ }),
171514
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", { children: report?.exitCode ?? "unknown" }),
171515
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
171516
+ className: "text-muted-foreground",
171517
+ children: "Totals"
171518
+ }),
171519
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("dd", { children: [
171520
+ validation.summary.totals.passed,
171521
+ " passed · ",
171522
+ failed,
171523
+ " failed ·",
171524
+ " ",
171525
+ validation.summary.totals.items,
171526
+ " archived changes"
171527
+ ] })
171528
+ ]
171529
+ }),
171530
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
171531
+ className: "space-y-2",
171532
+ children: validation.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171533
+ className: "border-border/60 rounded border p-2",
171534
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171535
+ className: "flex min-w-0 items-center gap-2",
171536
+ children: [item.valid ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CircleCheck, {
171537
+ className: "h-3.5 w-3.5 shrink-0 text-emerald-600",
171538
+ "aria-hidden": true
171539
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TriangleAlert, {
171540
+ className: "h-3.5 w-3.5 shrink-0 text-amber-600",
171541
+ "aria-hidden": true
171542
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
171543
+ className: "min-w-0 break-all font-mono text-[11px]",
171544
+ children: item.id
171545
+ })]
171546
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
171547
+ className: "mt-1",
171548
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IssueList, { issues: item.issues })
171549
+ })]
171550
+ }, item.id))
171551
+ }),
171552
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunButton, {
171553
+ pending,
171554
+ label: "Rerun",
171555
+ onRun: () => void run()
171556
+ })
171557
+ ]
171558
+ })
171559
+ });
171560
+ }
171090
171561
  //#endregion
171091
171562
  //#region src/components/change-context-summary.tsx
171092
171563
  /**
171093
- * Orthogonal intents (created 2026-08-03 Asia/Shanghai):
171564
+ * Orthogonal intents (updated 2026-08-15 Asia/Shanghai):
171094
171565
  * 1. Project compact Schema, artifact progress, Root, Store, and Reference subtitle badges.
171095
- * 2. Preserve current, retained, unavailable, and static authority distinctions.
171096
- * 3. Keep Reference failures directly visible without owning subscriptions or mutations.
171566
+ * 2. Carry the Apply instruction count as one subtitle badge — the progress authority.
171567
+ * 3. Preserve current, retained, unavailable, and static authority distinctions.
171568
+ * 4. Keep Reference failures directly visible without owning subscriptions or mutations.
171097
171569
  *
171098
171570
  * Original request (2026-08-03): keep only necessary Change evidence in the default decision plane.
171099
171571
  * Owner correction (2026-08-03): unify Change scan Tooltips in the subtitle and keep failures below the Header.
171572
+ * Original request (2026-08-15): Owner walkthrough: merge Apply progress into the subtitle badge row.
171573
+ * Original request (2026-08-15): 刷新/解析中的 lifecycle 锁收敛为副标题行内的 shiny 徽章 + Tooltip。
171100
171574
  */
171101
171575
  function summarizeReferences(references) {
171102
171576
  return references.reduce((counts, reference) => {
@@ -171117,7 +171591,7 @@ function referenceErrorLabels(references) {
171117
171591
  });
171118
171592
  }
171119
171593
  /** Compact source-attributed facts that share the Change Header subtitle. */
171120
- function ChangeContextSummary({ status, referenceEvidence }) {
171594
+ function ChangeContextSummary({ status, referenceEvidence, applyInstructionProgress, statusRefreshing = null, rootChecking = null }) {
171121
171595
  const provenance = status.provenance;
171122
171596
  const references = referenceEvidence.state === "unavailable" ? null : referenceEvidence.references;
171123
171597
  const referenceCounts = references ? summarizeReferences(references) : null;
@@ -171143,6 +171617,7 @@ function ChangeContextSummary({ status, referenceEvidence }) {
171143
171617
  " artifacts"
171144
171618
  ]
171145
171619
  }),
171620
+ applyInstructionProgress ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ApplyProgressBadge, { applyInstructionProgress }) : null,
171146
171621
  provenance.kind === "static" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InformationBadge, {
171147
171622
  ariaLabel: "Static Change context has no live backend provenance",
171148
171623
  tooltip: "CLI Change context is unavailable in this static snapshot.",
@@ -171175,7 +171650,15 @@ function ChangeContextSummary({ status, referenceEvidence }) {
171175
171650
  ariaLabel: "Reference evidence unavailable",
171176
171651
  tooltip: referenceEvidence.state === "unavailable" && referenceEvidence.reason === "static" ? "Reference evidence is not published in this static snapshot." : "Reference evidence is unavailable until Root Context is observed.",
171177
171652
  children: "References unavailable"
171178
- })
171653
+ }),
171654
+ rootChecking ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ShinyStatusBadge, {
171655
+ label: rootChecking.label,
171656
+ message: rootChecking.message
171657
+ }) : null,
171658
+ statusRefreshing ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ShinyStatusBadge, {
171659
+ label: statusRefreshing.label,
171660
+ message: statusRefreshing.message
171661
+ }) : null
171179
171662
  ]
171180
171663
  });
171181
171664
  }
@@ -171656,29 +172139,39 @@ function OperationInputsDialogAction({ title, context, operationGuidance }) {
171656
172139
  //#endregion
171657
172140
  //#region src/components/root-action-notice.tsx
171658
172141
  /**
171659
- * Orthogonal intents (updated 2026-07-28 Asia/Shanghai):
171660
- * 1. Render root-action loading and blocked states with CLI-owned evidence.
171661
- * 2. Keep blocker meaning direct while placing verbose CLI evidence in shared indirect space.
171662
- * 3. Keep the notice reusable across OPSX compose and direct-action surfaces.
172142
+ * Orthogonal intents (updated 2026-08-15 Asia/Shanghai):
172143
+ * 1. Render root-action blocked states with CLI-owned evidence as direct alerts.
172144
+ * 2. Render root-action checking states as one inline shiny badge for header/status rows.
172145
+ * 3. Keep blocker meaning direct while placing verbose CLI evidence in shared indirect space.
172146
+ * 4. Keep the notice reusable across OPSX compose and direct-action surfaces.
171663
172147
  *
171664
172148
  * Original request (2026-07-15): "Show CLI-owned failure evidence when root selection fails."
171665
172149
  * Original request (2026-07-28): supporting 6.x evidence should use Badge + Tooltip or Accordion.
172150
+ * Original request (2026-08-15): 刷新/解析中的块级 Alert 改为 Animated Shiny Text + Tooltip。
171666
172151
  */
171667
- /** Render objective loading or failure evidence that locks root-dependent actions. */
172152
+ /**
172153
+ * Normal lifecycle (resolving/refreshing) as visual language — one inline shiny badge
172154
+ * with no layout block. The complete lock reason stays available on hover/keyboard
172155
+ * focus via the Tooltip and the hidden polite live region.
172156
+ */
172157
+ function RootCheckingBadge({ state }) {
172158
+ if (state.status !== "checking") return null;
172159
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ShinyStatusBadge, {
172160
+ label: state.title,
172161
+ message: state.message
172162
+ });
172163
+ }
172164
+ /** Render objective failure evidence that locks root-dependent actions; null otherwise. */
171668
172165
  function RootActionNotice({ state }) {
171669
- if (state.status === "ready") return null;
171670
- const checking = state.status === "checking";
172166
+ if (state.status !== "blocked") return null;
171671
172167
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171672
- role: checking ? "status" : "alert",
171673
- "aria-live": checking ? "polite" : "assertive",
171674
- className: checking ? "border-border bg-muted/30 rounded-md border p-3 text-sm" : "border-destructive/40 bg-destructive/10 text-destructive rounded-md border p-3 text-sm",
172168
+ role: "alert",
172169
+ "aria-live": "assertive",
172170
+ className: "border-destructive/40 bg-destructive/10 text-destructive rounded-md border p-3 text-sm",
171675
172171
  children: [
171676
172172
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171677
172173
  className: "flex items-center gap-2 font-medium",
171678
- children: [checking ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, {
171679
- className: "h-4 w-4 animate-spin",
171680
- "aria-hidden": true
171681
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CircleAlert, {
172174
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CircleAlert, {
171682
172175
  className: "h-4 w-4",
171683
172176
  "aria-hidden": true
171684
172177
  }), state.title]
@@ -171718,6 +172211,7 @@ function RootActionNotice({ state }) {
171718
172211
  * Original request (2026-08-01): preserve OpenSpec 1.7 Apply operation inputs end to end.
171719
172212
  * Original request (2026-08-03): move complete Change evidence into a dedicated tab page.
171720
172213
  * Owner correction (2026-08-03): move Actions inline with the title, unify subtitle badges, and localize unavailable Tooltips.
172214
+ * Original request (2026-08-15): 刷新/解析中状态收敛为副标题行内的 shiny 徽章,不再占据 statusRegion 块。
171721
172215
  */
171722
172216
  function ChangeView() {
171723
172217
  const { changeId } = useParams({ from: "/changes/$changeId" });
@@ -171791,13 +172285,16 @@ function ChangeView() {
171791
172285
  id: "evidence",
171792
172286
  label: "Evidence",
171793
172287
  icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileSearch, { className: "h-4 w-4" }),
171794
- content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeEvidencePanel, {
171795
- status,
171796
- referenceEvidence
172288
+ content: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
172289
+ className: "flex min-h-0 min-w-0 flex-1 flex-col",
172290
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeEvidencePanel, {
172291
+ status,
172292
+ referenceEvidence
172293
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArchivedValidationEvidence, {})]
171797
172294
  })
171798
172295
  }] : [], [referenceEvidence, status]);
171799
172296
  const hasReferenceFailures = referenceEvidence.state !== "unavailable" && referenceEvidence.references.some((reference) => reference.status.some((diagnostic) => diagnostic.severity === "error"));
171800
- const hasDirectStatus = !statusCurrent || Boolean(error) || rootAction.status !== "ready" || hasReferenceFailures || Boolean(applyInstructions?.applyInstructionProgress);
172297
+ const hasDirectStatus = Boolean(error) || rootAction.status === "blocked" || hasReferenceFailures || Boolean(applyInstructions?.applyInstructionProgress.divergence);
171801
172298
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OpsxEntityDetailView, {
171802
172299
  entityId: changeId,
171803
172300
  sharedFamily: "changes",
@@ -171807,7 +172304,16 @@ function ChangeView() {
171807
172304
  title: status?.changeName,
171808
172305
  subtitle: status ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeContextSummary, {
171809
172306
  status,
171810
- referenceEvidence
172307
+ referenceEvidence,
172308
+ applyInstructionProgress: applyInstructions?.applyInstructionProgress ?? null,
172309
+ statusRefreshing: statusCurrent ? null : {
172310
+ label: "Status refreshing",
172311
+ message: statusAuthorityMessage ?? ""
172312
+ },
172313
+ rootChecking: rootAction.status === "checking" ? {
172314
+ label: rootAction.title,
172315
+ message: rootAction.message
172316
+ } : null
171811
172317
  }) : void 0,
171812
172318
  headerActions: status ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeCommandBar, {
171813
172319
  status,
@@ -171845,15 +172351,6 @@ function ChangeView() {
171845
172351
  statusRegion: status && hasDirectStatus ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171846
172352
  className: "flex min-w-0 flex-col gap-2",
171847
172353
  children: [
171848
- !statusCurrent && !error ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171849
- role: "status",
171850
- "aria-live": "polite",
171851
- className: "border-border bg-muted/30 text-muted-foreground flex items-center gap-2 rounded-md border px-3 py-2 text-xs",
171852
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCw, {
171853
- className: "h-3.5 w-3.5 shrink-0",
171854
- "aria-hidden": true
171855
- }), statusAuthorityMessage]
171856
- }) : null,
171857
172354
  error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
171858
172355
  role: "alert",
171859
172356
  "aria-live": "assertive",
@@ -171912,7 +172409,7 @@ var CONFIG_GUIDE_STAGE_META = {
171912
172409
  //#region src/components/config/config-guide.tsx
171913
172410
  var ConfigGuideContext = (0, import_react.createContext)(null);
171914
172411
  (0, import_react.lazy)(async () => {
171915
- return { default: (await import("./config-guide-presentation-DluN0NgQ.js")).ConfigGuidePresentationLayer };
172412
+ return { default: (await import("./config-guide-presentation-CmUNOJoP.js")).ConfigGuidePresentationLayer };
171916
172413
  });
171917
172414
  /** Access the root-owned adaptive Guide runtime. */
171918
172415
  function useConfigGuide() {
@@ -173677,6 +174174,7 @@ function ActiveRootConfigSection({ isStatic }) {
173677
174174
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
173678
174175
  className: "flex flex-wrap items-center justify-end gap-2",
173679
174176
  children: [
174177
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RootCheckingBadge, { state: rootAction }),
173680
174178
  (config.exists || isEditing) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
173681
174179
  role: "tablist",
173682
174180
  "aria-label": "Active Root editor mode",
@@ -174670,19 +175168,23 @@ function ConfigSchemaWorkspace({ onNavigate, schemaId }) {
174670
175168
  ]
174671
175169
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
174672
175170
  className: "flex items-center gap-2",
174673
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
174674
- type: "button",
174675
- onClick: handleAddSchema,
174676
- disabled: !schemaCanEdit || createSchemaMutation.isPending,
174677
- className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs font-medium disabled:cursor-not-allowed disabled:opacity-50",
174678
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Plus, { className: "h-3.5 w-3.5" }), "Add"]
174679
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
174680
- type: "button",
174681
- onClick: handleDeleteSchema,
174682
- disabled: !schemaCanEdit || deleteSchemaMutation.isPending,
174683
- className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs font-medium disabled:cursor-not-allowed disabled:opacity-50",
174684
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Trash2, { className: "h-3.5 w-3.5" }), "Delete"]
174685
- })]
175171
+ children: [
175172
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RootCheckingBadge, { state: rootAction }),
175173
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
175174
+ type: "button",
175175
+ onClick: handleAddSchema,
175176
+ disabled: !schemaCanEdit || createSchemaMutation.isPending,
175177
+ className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs font-medium disabled:cursor-not-allowed disabled:opacity-50",
175178
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Plus, { className: "h-3.5 w-3.5" }), "Add"]
175179
+ }),
175180
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
175181
+ type: "button",
175182
+ onClick: handleDeleteSchema,
175183
+ disabled: !schemaCanEdit || deleteSchemaMutation.isPending,
175184
+ className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs font-medium disabled:cursor-not-allowed disabled:opacity-50",
175185
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Trash2, { className: "h-3.5 w-3.5" }), "Delete"]
175186
+ })
175187
+ ]
174686
175188
  })]
174687
175189
  }),
174688
175190
  !isStatic && rootAction.disabled ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RootActionNotice, { state: rootAction }) : null,
@@ -176928,14 +177430,15 @@ async function refreshDashboardGitSnapshot(reason, expectedBindingToken) {
176928
177430
  //#endregion
176929
177431
  //#region src/routes/dashboard.tsx
176930
177432
  /**
176931
- * Orthogonal intents (updated 2026-07-31 Asia/Shanghai):
177433
+ * Orthogonal intents (updated 2026-08-15 Asia/Shanghai):
176932
177434
  * 1. Render independent Dashboard projections inside stable region-owned Pending geometry.
176933
177435
  * 2. Keep Dashboard-owned readonly Code Git refresh bound to rendered provenance and separate from Planning-root mutation authority.
176934
177436
  * 3. Curate Code Git activity while preserving binding-token detail handoff provenance.
176935
- * 4. Retain stable regional snapshots beside their own loading, updating, and error evidence.
176936
- * 5. Pause auto-refresh while hidden while preserving one absolute next-refresh deadline.
177437
+ * 4. Show only objective planning and artifact facts, never tracked task completion.
177438
+ * 5. Retain stable regional snapshots beside their own loading, updating, and error evidence.
176937
177439
  *
176938
177440
  * Original request (2026-07-16): "接下来,你来接手后续工作"
177441
+ * Original request (2026-08-15): "v9的适配需要同时适配 1.8和1.9。"
176939
177442
  * Derived requirement (2026-07-19): Checkpoint 6.11 preserves Git handoff and action provenance.
176940
177443
  * Original request (2026-07-23): "现在页面数据的加载数据非常慢(比如dashboard页面、changes页面都要等待非常久,页面刷新后,似乎后台没有缓存一样,也要加载很久。"
176941
177444
  * Original request (2026-07-27): "统一修复所有类似的问题(我们也没不多,各个页面都检查一下,特别是app 那边新增的页面)"
@@ -176949,6 +177452,7 @@ async function refreshDashboardGitSnapshot(reason, expectedBindingToken) {
176949
177452
  * Original request (2026-07-31): "Code Git Snapshot 的 Other Worktrees 默认隐藏 (detached)。然后commitList这里默认显示5个就好"
176950
177453
  * Original request (2026-07-31): "检查目前的这个 Code Git Snapshot,它非常慢,有时候甚至要十几秒"
176951
177454
  * Owner correction (2026-07-31): Hidden documents pause the timer; visibility resumes the remaining delay or refreshes once when the absolute deadline elapsed.
177455
+
176952
177456
  */
176953
177457
  var GIT_AUTO_REFRESH_OPTIONS = [
176954
177458
  {
@@ -177405,8 +177909,6 @@ function Dashboard() {
177405
177909
  children: [
177406
177910
  summaryPending ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeListSkeleton, { count: 3 }) : null,
177407
177911
  !summaryPending && activeChanges.map((change) => {
177408
- const progress = change.trackedTaskProgress;
177409
- const taskPercent = progress.total > 0 ? Math.round(progress.completed / progress.total * 100) : 0;
177410
177912
  const status = activeStatuses.find((item) => item.changeName === change.id);
177411
177913
  const doneArtifacts = status?.artifacts.filter((artifact) => artifact.status === "done").length ?? 0;
177412
177914
  const totalArtifacts = status?.artifacts.length ?? 0;
@@ -177414,11 +177916,12 @@ function Dashboard() {
177414
177916
  const trackedArtifactStatus = trackedArtifactId && status ? status.artifacts.find((artifact) => artifact.id === trackedArtifactId)?.status ?? inferTrackedArtifactStatus(status.artifacts.map((artifact) => artifact.status)) : inferTrackedArtifactStatus(status?.artifacts.map((artifact) => artifact.status) ?? []);
177415
177917
  const phase = classifyChangeWorkflowPhase({
177416
177918
  hasStatus: Boolean(status),
177417
- isComplete: status?.isComplete ?? false,
177418
- trackedTaskPhase: progress.phase,
177419
- trackedArtifactStatus
177919
+ isPlanningComplete: status?.isPlanningComplete ?? false,
177920
+ trackedTaskPhase: change.trackedTaskProgress.phase,
177921
+ trackedArtifactStatus,
177922
+ cliCompletedTasks: change.cliTaskSummary?.completedTasks ?? null
177420
177923
  });
177421
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(VTLink, {
177924
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VTLink, {
177422
177925
  to: "/changes/$changeId",
177423
177926
  params: { changeId: change.id },
177424
177927
  state: (prev) => ({
@@ -177439,71 +177942,29 @@ function Dashboard() {
177439
177942
  entityId: change.id
177440
177943
  }, "container"),
177441
177944
  className: "hover:bg-muted/50 block min-w-0 px-4 py-3",
177442
- children: [
177443
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
177444
- className: "mb-2 flex min-w-0 flex-wrap items-start justify-between gap-3 sm:flex-nowrap sm:items-center",
177445
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
177446
- className: "min-w-0 flex-1",
177447
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
177448
- ...getSharedElementBinding({
177449
- family: "changes",
177450
- entityId: change.id
177451
- }, "title"),
177452
- className: "truncate font-medium",
177453
- children: change.name
177454
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
177455
- className: "text-muted-foreground truncate text-xs",
177456
- children: [change.updatedAt > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [formatRelativeTime(change.updatedAt), " · "] }), change.id]
177457
- })]
177458
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
177459
- className: "shrink-0 text-right text-sm",
177460
- children: [
177461
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, {
177462
- tone: "custom",
177463
- size: "sm",
177464
- shape: "box",
177465
- className: `border ${phase.toneClass}`,
177466
- children: phase.label
177467
- }),
177468
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
177469
- className: "font-medium",
177470
- children: [
177471
- progress.completed,
177472
- "/",
177473
- progress.total
177474
- ]
177475
- }),
177476
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
177477
- className: "text-muted-foreground text-xs",
177478
- children: "tasks"
177479
- })
177480
- ]
177481
- })]
177482
- }),
177483
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
177484
- className: "bg-muted h-1.5 rounded-full",
177485
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
177486
- className: "bg-primary h-full rounded-full transition-all",
177487
- style: { width: `${taskPercent}%` }
177488
- })
177489
- }),
177490
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
177491
- className: "text-muted-foreground mt-2 flex min-w-0 flex-wrap items-center justify-between gap-2 text-xs",
177492
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
177493
- className: "shrink-0",
177494
- children: [taskPercent, "% task completion"]
177495
- }), status ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
177496
- className: "min-w-0 truncate text-right",
177945
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
177946
+ className: "flex min-w-0 items-center gap-3",
177947
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeRow, {
177948
+ changeId: change.id,
177949
+ name: change.name,
177950
+ phase,
177951
+ updatedAt: change.updatedAt,
177952
+ formatTime: formatRelativeTime,
177953
+ progressRatio: change.cliTaskSummary && change.cliTaskSummary.totalTasks > 0 ? change.cliTaskSummary.completedTasks / change.cliTaskSummary.totalTasks : null,
177954
+ className: "min-w-0 flex-1",
177955
+ subtitle: status ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
177956
+ title: "Task counts reported by the OpenSpec CLI for this Change.",
177497
177957
  children: [
177498
177958
  doneArtifacts,
177499
177959
  "/",
177500
177960
  totalArtifacts,
177501
177961
  " artifacts · ",
177502
- status.schemaName
177962
+ status.schemaName,
177963
+ change.cliTaskSummary ? ` · Tasks ${change.cliTaskSummary.completedTasks}/${change.cliTaskSummary.totalTasks}` : ""
177503
177964
  ]
177504
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Artifacts status unavailable" })]
177505
- })
177506
- ]
177965
+ }) : "Artifacts status unavailable"
177966
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeRowChevron, {})]
177967
+ })
177507
177968
  }, change.id);
177508
177969
  }),
177509
177970
  !summaryPending && !hasChanges && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {