@zq-silk/yui 2.1.0 → 2.3.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 (135) hide show
  1. package/README.md +8 -2
  2. package/dist/cli/commandCatalog.js +32 -6
  3. package/dist/cli/commandDiscovery.js +4 -1
  4. package/dist/cli/interactionPolicy.js +4 -0
  5. package/dist/cli.js +23 -3078
  6. package/dist/commands/taskCommands.js +84 -28
  7. package/dist/commands/taskIntegrationCommands.js +8 -17
  8. package/dist/commands/taskUpstreamCommands.js +3 -1
  9. package/dist/context/runContextPack.js +132 -5
  10. package/dist/context/sourceRunContext.js +4 -2
  11. package/dist/context/taskContext.js +6 -1
  12. package/dist/controlPlaneCli.js +3099 -0
  13. package/dist/controller/clientRuntime.js +3 -2
  14. package/dist/controller/fileSchedulerStoreAdapter.js +19 -6
  15. package/dist/controller/jobControl.js +21 -0
  16. package/dist/executor/agentExecutor.js +1 -1
  17. package/dist/executor/effectiveLaunch.js +18 -5
  18. package/dist/executor/fileRoleLaunchPlanner.js +15 -19
  19. package/dist/integration/gitIntegrationService.js +58 -82
  20. package/dist/job/jobCleanupInspection.js +67 -0
  21. package/dist/message/messageContinuation.js +7 -2
  22. package/dist/nativeAgent/agent.js +176 -74
  23. package/dist/nativeAgent/cliDemo.js +37 -0
  24. package/dist/nativeAgent/codingTools.js +11 -0
  25. package/dist/nativeAgent/commandTool.js +215 -0
  26. package/dist/nativeAgent/compactionDemo.js +158 -0
  27. package/dist/nativeAgent/composition.js +71 -0
  28. package/dist/nativeAgent/context/budget.js +44 -0
  29. package/dist/nativeAgent/context/index.js +339 -0
  30. package/dist/nativeAgent/context/providerCompressor.js +103 -0
  31. package/dist/nativeAgent/demo.js +12 -1
  32. package/dist/nativeAgent/evaluation/cases.js +38 -0
  33. package/dist/nativeAgent/evaluation/checks.js +91 -0
  34. package/dist/nativeAgent/evaluation/demo.js +19 -0
  35. package/dist/nativeAgent/evaluation/files.js +54 -0
  36. package/dist/nativeAgent/evaluation/fixture.js +36 -0
  37. package/dist/nativeAgent/evaluation/index.js +239 -0
  38. package/dist/nativeAgent/executionOwner.js +209 -0
  39. package/dist/nativeAgent/filePatterns.js +170 -0
  40. package/dist/nativeAgent/fileToolsSupport.js +202 -0
  41. package/dist/nativeAgent/index.js +13 -0
  42. package/dist/nativeAgent/interaction/cli.js +358 -0
  43. package/dist/nativeAgent/interaction/contracts.js +1 -0
  44. package/dist/nativeAgent/interaction/index.js +3 -0
  45. package/dist/nativeAgent/interaction/memoryDemo.js +115 -0
  46. package/dist/nativeAgent/interaction/renderer.js +34 -0
  47. package/dist/nativeAgent/localSafety.js +258 -0
  48. package/dist/nativeAgent/model/anthropicMessages.js +204 -0
  49. package/dist/nativeAgent/model/chatCompletions.js +210 -0
  50. package/dist/nativeAgent/model/errors.js +47 -0
  51. package/dist/nativeAgent/model/gateway.js +423 -0
  52. package/dist/nativeAgent/model/index.js +7 -0
  53. package/dist/nativeAgent/model/observationAdapter.js +21 -0
  54. package/dist/nativeAgent/model/protocols.js +19 -0
  55. package/dist/nativeAgent/model/responses.js +263 -0
  56. package/dist/nativeAgent/model/types.js +1 -0
  57. package/dist/nativeAgent/model/wire.js +73 -0
  58. package/dist/nativeAgent/observability/index.js +220 -0
  59. package/dist/nativeAgent/product/catalog.js +82 -0
  60. package/dist/nativeAgent/product/config.js +295 -0
  61. package/dist/nativeAgent/product/facts.js +30 -0
  62. package/dist/nativeAgent/product/index.js +62 -0
  63. package/dist/nativeAgent/product/location.js +44 -0
  64. package/dist/nativeAgent/product/runtime.js +276 -0
  65. package/dist/nativeAgent/product/storage.js +49 -0
  66. package/dist/nativeAgent/product/tools.js +47 -0
  67. package/dist/nativeAgent/product/transport.js +54 -0
  68. package/dist/nativeAgent/projectGuidance/index.js +425 -0
  69. package/dist/nativeAgent/searchTools.js +305 -0
  70. package/dist/nativeAgent/session/backends.js +293 -0
  71. package/dist/nativeAgent/session/catalog.js +97 -0
  72. package/dist/nativeAgent/session/catalogDemo.js +87 -0
  73. package/dist/nativeAgent/session/contracts.js +1 -0
  74. package/dist/nativeAgent/session/format.js +269 -0
  75. package/dist/nativeAgent/session/index.js +5 -0
  76. package/dist/nativeAgent/session/location.js +36 -0
  77. package/dist/nativeAgent/session/sqliteFormat.js +134 -0
  78. package/dist/nativeAgent/session/store.js +248 -0
  79. package/dist/nativeAgent/textTools.js +270 -133
  80. package/dist/nativeAgent/toolManager/executor.js +290 -0
  81. package/dist/nativeAgent/toolManager/index.js +4 -0
  82. package/dist/nativeAgent/validation.js +2 -2
  83. package/dist/repository/gitWorkspace.js +41 -12
  84. package/dist/repository/taskWorkspaceCoordinator.js +72 -145
  85. package/dist/repository/taskWorkspacePreparer.js +39 -43
  86. package/dist/repository/workspaceCleanupInspection.js +88 -7
  87. package/dist/resources/resourceRegistrar.js +16 -10
  88. package/dist/runtime/integrationRuntimeIsolation.js +21 -0
  89. package/dist/runtime/taskRuntimeIsolation.js +91 -21
  90. package/dist/task/archiveDiagnostics.js +26 -8
  91. package/dist/task/archivePreflight.js +26 -9
  92. package/dist/task/leaderArchive.js +9 -15
  93. package/dist/task/taskAuthority.js +56 -0
  94. package/dist/web/assets/client/api.js +8 -0
  95. package/dist/web/assets/client/app.js +74 -9
  96. package/dist/web/assets/client/components.js +95 -36
  97. package/dist/web/assets/client/detail.js +110 -64
  98. package/dist/web/assets/client/dock.js +95 -11
  99. package/dist/web/assets/client/evidence.js +286 -94
  100. package/dist/web/assets/client/i18n.js +182 -62
  101. package/dist/web/assets/client/overview.js +9 -10
  102. package/dist/web/assets/client/records.js +142 -7
  103. package/dist/web/assets/client/sections.js +234 -198
  104. package/dist/web/assets/client/sidebar.js +31 -2
  105. package/dist/web/assets/icons.js +4 -0
  106. package/dist/web/assets/shell.js +2 -1
  107. package/dist/web/assets/styles/components.js +64 -15
  108. package/dist/web/assets/styles/layout.js +11 -4
  109. package/dist/web/assets/styles/responsive.js +16 -6
  110. package/dist/web/assets/styles/tokens.js +1 -1
  111. package/dist/web/assets/styles/views.js +62 -42
  112. package/dist/web/webServer.js +12 -1
  113. package/dist/web/webTaskSurface.js +8 -1
  114. package/docs/agent-result-consumption.md +16 -0
  115. package/docs/agent-result-consumption.zh-CN.md +13 -0
  116. package/docs/examples/agent-offline.mjs +194 -0
  117. package/docs/native-agent.md +283 -0
  118. package/docs/observability/README.md +13 -3
  119. package/docs/observability/README.zh-CN.md +10 -3
  120. package/docs/release-workflow.md +72 -9
  121. package/docs/release-workflow.zh-CN.md +55 -6
  122. package/docs/roles-and-configuration.md +32 -0
  123. package/docs/roles-and-configuration.zh-CN.md +26 -0
  124. package/docs/task-delivery.md +36 -8
  125. package/docs/task-delivery.zh-CN.md +24 -7
  126. package/i18n/README.zh-CN.md +3 -2
  127. package/package.json +1 -1
  128. package/skills/yui-leader/SKILL.md +9 -0
  129. package/skills/yui-leader/references/execution.md +2 -1
  130. package/skills/yui-leader/references/integration.md +20 -0
  131. package/skills/yui-operator/SKILL.md +4 -0
  132. package/skills/yui-reviewer/SKILL.md +8 -0
  133. package/skills/yui-runtime/SKILL.md +11 -0
  134. package/skills/yui-runtime/references/publication.md +20 -4
  135. package/skills/yui-worker/SKILL.md +3 -0
@@ -2,6 +2,10 @@
2
2
  * COMPONENTS — reusable controls and primitives: buttons, segmented
3
3
  * controls, badges, dots, chips, cards, disclosures, key/value lists, empty
4
4
  * states, metrics, dialogs and the toast. Colour comes only from tokens.
5
+ *
6
+ * Task and overview surfaces are one reading column of flat panels: a card
7
+ * head (icon tile, title, count, hint, actions) above a hairline, then the
8
+ * body. List cards divide their rows with hairlines instead of nesting boxes.
5
9
  */
6
10
  export const COMPONENT_STYLES = `
7
11
  /* Tones: one semantic colour per tone, used by dots, badges and signals */
@@ -57,24 +61,66 @@ code.id{padding:1px 6px;border-radius:var(--r-xs);background:var(--surface-3);co
57
61
  .mono-line{font-family:var(--font-mono);font-size:var(--fs-2xs);overflow-wrap:anywhere}
58
62
 
59
63
  /* Chip tabs (local filters) */
60
- .chip-tabs{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:12px}
64
+ .chip-tabs{display:flex;flex-wrap:wrap;gap:6px}
61
65
  .chip-tab{display:inline-flex;align-items:center;gap:6px;height:28px;padding:0 10px;border:1px solid var(--line-2);border-radius:var(--r-pill);background:transparent;color:var(--ink-3);font-size:var(--fs-xs);font-weight:500}
62
66
  .chip-tab:hover{color:var(--ink);border-color:var(--line-3)}
63
67
  .chip-tab[aria-pressed="true"]{background:var(--ink);border-color:var(--ink);color:var(--canvas)}
64
68
  .chip-tab[aria-pressed="true"] .count{background:rgba(127,127,127,.25);color:inherit}
65
69
 
66
- /* Cards */
67
- .card{display:flex;flex-direction:column;min-width:0;border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface);box-shadow:var(--shadow-1)}
68
- .card-head{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:4px 10px;padding:14px 16px 0}
69
- .card-title{display:flex;align-items:center;gap:8px;flex:1;min-width:0;font-size:var(--fs-md);font-weight:600;color:var(--ink)}
70
- .card-title .icon{color:var(--ink-3)}
71
- .card-actions{grid-row:1;grid-column:2;display:flex;gap:6px;margin:-4px -6px -4px 0}
72
- .card-hint{grid-column:1/-1;color:var(--ink-3);font-size:var(--fs-xs);line-height:1.45}
73
- .card-body{display:grid;gap:12px;padding:14px 16px 16px;min-width:0}
74
- .card-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;align-items:start}
75
- .card-grid-1{grid-template-columns:minmax(0,1fr)}
70
+ /* Cards: flat panels. Actions sit beside the heading and wrap below it when
71
+ the column is too narrow for both. */
72
+ .card{display:flex;flex-direction:column;min-width:0;border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface)}
73
+ .card-head{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px 16px;padding:12px 16px}
74
+ .card-heading{display:grid;gap:3px;flex:1 1 260px;min-width:0}
75
+ .card-title{display:flex;align-items:center;gap:10px;min-width:0;font-size:var(--fs-md);font-weight:600;color:var(--ink)}
76
+ .card-title>span:not(.card-icon):not(.count){min-width:0;overflow-wrap:anywhere}
77
+ .card-icon{display:grid;place-items:center;width:24px;height:24px;flex:none;border-radius:var(--r-sm);background:var(--surface-3);color:var(--ink-3)}
78
+ .card-icon .icon{width:14px;height:14px}
79
+ .card-hint{color:var(--ink-3);font-size:var(--fs-xs);line-height:1.45}
80
+ .card-heading:has(.card-icon) .card-hint{padding-left:34px}
81
+ .card-actions{display:flex;flex-wrap:wrap;align-items:center;gap:6px;min-width:0}
82
+ .card-actions>.btn-ghost:last-child{margin-right:-8px}
83
+ .card-body{display:grid;grid-template-columns:minmax(0,1fr);gap:12px;padding:14px 16px 16px;min-width:0}
84
+ .card-head+.card-body{border-top:1px solid var(--line)}
85
+ .card-body:empty,.card-body:has(> :only-child:empty){display:none}
86
+ .card-body>.btn-link{justify-self:start}
87
+ .card-stack{display:flex;flex-direction:column;gap:16px;min-width:0}
76
88
  .stack{display:grid;gap:10px;min-width:0}
77
89
 
90
+ /* List cards: one row per record, divided by hairlines */
91
+ .list-card{overflow:hidden}
92
+ .list-card>.card-body{padding:0;gap:0}
93
+ .row-stack{display:grid;grid-template-columns:minmax(0,1fr);min-width:0}
94
+ .row-stack>:is(.work-card,.run-card,.review-card,.record,.role-card,.lazy-row){border:0;border-top:1px solid var(--line);border-radius:0;background:transparent;box-shadow:none}
95
+ .row-stack>:is(.work-card,.run-card,.review-card,.record,.role-card,.lazy-row):first-child,
96
+ .row-stack>.row-label+:is(.work-card,.run-card,.review-card,.record,.lazy-row){border-top:0}
97
+ .row-stack>:is(.run-card,.review-card,.record){padding:12px 16px}
98
+ .row-stack>.run-card[data-status="failed"]{box-shadow:inset 3px 0 0 var(--bad)}
99
+ .row-stack>.empty{margin:14px 16px}
100
+ .row-stack>.note{margin:12px 16px}
101
+ .row-stack>.show-more{margin:6px 16px 14px}
102
+ .row-stack>.row-stack{border-top:1px solid var(--line)}
103
+ .row-stack>.row-label{padding:12px 16px 2px;color:var(--ink-4);font-size:var(--fs-2xs);font-weight:600;letter-spacing:.04em}
104
+ .row-stack>.row-label:only-child{padding-bottom:12px}
105
+ .row-stack.boxed{border:1px solid var(--line);border-radius:var(--r-md);background:var(--surface);overflow:hidden}
106
+ .row-stack.boxed>:is(.record){padding:10px 14px}
107
+ .list-foot{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;min-width:0}
108
+ .list-foot:empty{display:none}
109
+ .row-stack>.list-foot{padding:8px 16px;border-top:1px solid var(--line)}
110
+ .card-body>.list-foot{padding-top:4px;border-top:1px solid var(--line)}
111
+ .list-foot>.faint{margin-right:auto}
112
+
113
+ /* Lazy rows: a list summary that reads its exact record when opened */
114
+ .lazy-row{min-width:0}
115
+ .lazy-head{display:flex;align-items:center;gap:10px;min-width:0;padding:11px 16px;list-style:none;cursor:pointer;font-size:var(--fs-sm)}
116
+ .lazy-head::-webkit-details-marker{display:none}
117
+ .lazy-head:hover .lazy-title{color:var(--ink)}
118
+ .lazy-head:focus-visible{box-shadow:inset 0 0 0 2px var(--accent-line)}
119
+ .lazy-title{flex:1;min-width:0;color:var(--ink-2);font-weight:500;overflow-wrap:anywhere}
120
+ .lazy-body{display:grid;grid-template-columns:minmax(0,1fr);gap:10px;min-width:0;padding:0 16px 14px 40px}
121
+ .lazy-content{display:grid;grid-template-columns:minmax(0,1fr);gap:12px;min-width:0}
122
+ [data-reading="true"]>.record-actions,.record[data-reading="true"]{opacity:.7}
123
+
78
124
  /* Disclosure */
79
125
  .disclosure{min-width:0;border-top:1px solid var(--line)}
80
126
  .disclosure>summary{display:flex;align-items:center;gap:8px;padding:10px 0;list-style:none;cursor:pointer;color:var(--ink-2);font-size:var(--fs-sm);font-weight:500;user-select:none}
@@ -83,15 +129,18 @@ code.id{padding:1px 6px;border-radius:var(--r-xs);background:var(--surface-3);co
83
129
  .disclosure-chevron{width:14px;height:14px;color:var(--ink-4);transition:transform var(--t-med) var(--ease)}
84
130
  details[open]>summary .disclosure-chevron{transform:rotate(90deg)}
85
131
  .disclosure-meta{margin-left:auto;color:var(--ink-4);font-size:var(--fs-xs);font-weight:400}
86
- .disclosure-body{display:grid;gap:10px;padding:0 0 12px 22px;min-width:0}
87
- .card-disclosure{border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface);box-shadow:var(--shadow-1)}
88
- .card-disclosure>summary{padding:14px 16px;color:var(--ink);font-weight:600;font-size:var(--fs-md)}
89
- .card-disclosure>.disclosure-body{padding:0 16px 16px}
132
+ .disclosure-body{display:grid;grid-template-columns:minmax(0,1fr);gap:10px;padding:0 0 12px 22px;min-width:0}
133
+ .card-disclosure{border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface)}
134
+ .card-disclosure>summary{gap:10px;padding:12px 16px;border-radius:var(--r-lg);color:var(--ink);font-weight:600;font-size:var(--fs-md)}
135
+ .card-disclosure>summary .disclosure-chevron{box-sizing:content-box;padding:5px;border-radius:var(--r-sm);background:var(--surface-3);color:var(--ink-3)}
136
+ .card-disclosure[open]>summary{border-bottom:1px solid var(--line);border-radius:var(--r-lg) var(--r-lg) 0 0}
137
+ .card-disclosure>.disclosure-body{padding:14px 16px 16px}
90
138
 
91
139
  /* Key/value */
92
140
  .kv{display:grid;grid-template-columns:minmax(96px,max-content) minmax(0,1fr);gap:7px 16px;margin:0;font-size:var(--fs-sm)}
93
141
  .kv dt{color:var(--ink-3)}
94
142
  .kv dd{margin:0;min-width:0;color:var(--ink);overflow-wrap:anywhere}
143
+ .kv dd code.id{white-space:normal;overflow-wrap:anywhere;-webkit-box-decoration-break:clone;box-decoration-break:clone}
95
144
  .kv-compact{gap:3px 12px;font-size:var(--fs-xs)}
96
145
 
97
146
  /* Prose */
@@ -2,7 +2,9 @@
2
2
  * LAYOUT — the three-region workspace.
3
3
  * sidebar | center (task details) | divider | dock (session)
4
4
  * body.dock-open shows the dock; body.dock-center swaps the dock into the
5
- * middle so the order becomes sidebar | dock | divider | center.
5
+ * middle so the order becomes sidebar | dock | divider | center. The sidebar's
6
+ * own divider overlays its right edge, so it adds no grid column; --sidebar-w
7
+ * is the default width and a stored preference overrides it inline.
6
8
  */
7
9
  export const LAYOUT_STYLES = `
8
10
  .app{display:grid;height:100vh;height:100dvh;grid-template-rows:minmax(0,1fr);
@@ -12,16 +14,21 @@ body.dock-open .app{grid-template-columns:var(--sidebar-w) minmax(0,1fr) var(--d
12
14
  body.dock-open.dock-center .app{grid-template-areas:"sidebar dock divider center";grid-template-columns:var(--sidebar-w) var(--dock-w) var(--divider-w) minmax(0,1fr)}
13
15
 
14
16
  /* Sidebar */
15
- .sidebar{grid-area:sidebar;display:flex;flex-direction:column;min-width:0;min-height:0;background:var(--surface);border-right:1px solid var(--line)}
17
+ .sidebar{grid-area:sidebar;display:flex;flex-direction:column;min-width:0;min-height:0;background:var(--surface);border-right:1px solid var(--line);container:sidebar/inline-size}
18
+ .sidebar-divider{grid-area:sidebar;justify-self:end;position:relative;z-index:20;width:9px;margin-right:-5px;cursor:col-resize;touch-action:none}
19
+ .sidebar-divider span{position:absolute;top:0;bottom:0;left:3px;width:1px;background:transparent;transition:background var(--t-fast),box-shadow var(--t-fast)}
20
+ .sidebar-divider:hover span,.sidebar-divider:focus-visible span,body.sidebar-resizing .sidebar-divider span{background:var(--accent);box-shadow:0 0 0 1px var(--accent)}
21
+ .sidebar-divider:focus-visible{box-shadow:none}
22
+ body.sidebar-resizing{cursor:col-resize;user-select:none}
16
23
  .side-head{flex:none;display:flex;align-items:center;gap:10px;height:var(--header-h);padding:0 12px 0 16px;border-bottom:1px solid var(--line)}
17
24
  .brand{display:flex;align-items:center;gap:10px;flex:1;min-width:0}
18
25
  .search-field{flex:none;margin:12px 12px 0}
19
26
  .attention-bar{flex:none;margin:10px 12px 0}
20
27
  .status-tabs{flex:none;margin:10px 0 0;padding:0 12px}
21
- .task-list{flex:1;min-height:0;overflow-y:auto;padding:6px 8px 12px;scrollbar-gutter:stable}
28
+ .task-list{flex:1;min-height:0;overflow-y:auto;padding:4px 8px 12px;scrollbar-gutter:stable}
22
29
  .pager{flex:none;display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:6px;padding:8px 12px;border-top:1px solid var(--line)}
23
30
  .pager .pager-clear{grid-column:1/-1}
24
- .side-foot{flex:none;display:flex;align-items:center;gap:6px;padding:10px 12px;border-top:1px solid var(--line)}
31
+ .side-foot{flex:none;display:flex;align-items:center;gap:4px;padding:10px;border-top:1px solid var(--line)}
25
32
 
26
33
  /* Center */
27
34
  .center{grid-area:center;min-width:0;min-height:0;overflow-y:auto;scrollbar-gutter:stable;background:var(--canvas)}
@@ -3,16 +3,22 @@
3
3
  * ≤1200px narrower sidebar and dock defaults
4
4
  * ≤900px master–detail: task list OR task page; the dock becomes a
5
5
  * full-screen sheet over the task page
6
+ * Sidebar container queries adapt its footer to the width the user chose.
6
7
  */
7
8
  export const RESPONSIVE_STYLES = `
9
+ @container sidebar (max-width:299px){
10
+ .foot-btn kbd{display:none}
11
+ .lazy-meta{display:none}
12
+ .lazy-body{padding-left:16px}
13
+ }
14
+ @container sidebar (max-width:259px){
15
+ .foot-btn{gap:0;padding:0 9px}
16
+ .foot-btn span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
17
+ }
8
18
  @media(max-width:1200px){
9
19
  :root{--sidebar-w:264px}
10
- .card-grid{grid-template-columns:minmax(0,1fr)}
11
20
  .metric-strip{grid-template-columns:repeat(3,minmax(0,1fr))}
12
21
  }
13
- @media(max-width:1040px){
14
- body.dock-open .overview-grid{grid-template-columns:minmax(0,1fr)}
15
- }
16
22
  @media(max-width:900px){
17
23
  .app,body.dock-open .app,body.dock-open.dock-center .app{grid-template-areas:"main";grid-template-columns:minmax(0,1fr)}
18
24
  .sidebar{grid-area:main;border-right:0}
@@ -21,10 +27,9 @@ export const RESPONSIVE_STYLES = `
21
27
  body.task-open .center{display:block}
22
28
  .back-btn{display:inline-grid}
23
29
  .crumbs .crumb,.crumbs .crumb-sep{display:none}
24
- .dock-divider{display:none}
30
+ .dock-divider,.sidebar-divider{display:none}
25
31
  .dock{position:fixed;inset:0;z-index:60;padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px)}
26
32
  #dock-swap{display:none}
27
- .overview-grid{grid-template-columns:minmax(0,1fr)}
28
33
  .dock-toggle span{display:none}
29
34
  .dock-toggle{width:32px;padding:0}
30
35
  }
@@ -36,8 +41,13 @@ export const RESPONSIVE_STYLES = `
36
41
  .tab{padding:0 12px}
37
42
  .field-row{grid-template-columns:minmax(0,1fr)}
38
43
  .work-body{padding-left:16px}
44
+ .card-heading:has(.card-icon) .card-hint{padding-left:0}
45
+ .role-card>:not(.role-head):not(.role-actions){margin-left:0}
46
+ .now-card>.card-body{padding:14px 14px 14px 17px}
39
47
  .kv{grid-template-columns:minmax(0,1fr)}
40
48
  .kv dt{margin-top:4px}
41
49
  .foot-btn kbd{display:none}
50
+ .lazy-meta{display:none}
51
+ .lazy-body{padding-left:16px}
42
52
  }
43
53
  `;
@@ -23,7 +23,7 @@ export const TOKEN_STYLES = `
23
23
  --sp-1:4px;--sp-2:8px;--sp-3:12px;--sp-4:16px;--sp-5:20px;--sp-6:24px;--sp-8:32px;
24
24
  --r-xs:5px;--r-sm:7px;--r-md:10px;--r-lg:14px;--r-pill:999px;
25
25
  --sidebar-w:clamp(260px,21vw,312px);--dock-w:440px;--dock-min:320px;--divider-w:9px;
26
- --center-max:980px;--header-h:56px;
26
+ --center-max:880px;--header-h:56px;
27
27
  --t-fast:120ms;--t-med:220ms;--ease:cubic-bezier(.2,.8,.2,1);
28
28
  }
29
29
  :root,[data-theme="sumi"]{
@@ -1,6 +1,8 @@
1
1
  /*
2
2
  * VIEWS — styling for the concrete surfaces: sidebar index, overview, task
3
- * page (header, tabs, sections, records) and the session dock.
3
+ * page (header, tabs, panels, records) and the session dock. The overview
4
+ * and every task tab are a single reading column; nothing pairs cards side by
5
+ * side.
4
6
  */
5
7
  export const VIEW_STYLES = `
6
8
  /* ---------- Sidebar ---------- */
@@ -25,29 +27,32 @@ export const VIEW_STYLES = `
25
27
  .attention-pill[aria-pressed="true"]{background:var(--tone);color:var(--canvas)}
26
28
  .attention-clear{display:flex;align-items:center;gap:6px;color:var(--ink-4);font-size:var(--fs-xs)}
27
29
  .attention-clear .icon{color:var(--ok)}
28
- .tabs-row{display:flex;gap:2px;overflow-x:auto;scrollbar-width:none;padding-bottom:2px;border-bottom:1px solid var(--line)}
30
+ .tabs-row{position:relative;display:flex;gap:2px;overflow-x:auto;scrollbar-width:none;padding-bottom:2px;border-bottom:1px solid var(--line)}
31
+ .tabs-row[data-fade="end"]{-webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 28px),transparent);mask-image:linear-gradient(90deg,#000 calc(100% - 28px),transparent)}
32
+ .tabs-row[data-fade="start"]{-webkit-mask-image:linear-gradient(90deg,transparent,#000 28px);mask-image:linear-gradient(90deg,transparent,#000 28px)}
33
+ .tabs-row[data-fade="both"]{-webkit-mask-image:linear-gradient(90deg,transparent,#000 28px,#000 calc(100% - 28px),transparent);mask-image:linear-gradient(90deg,transparent,#000 28px,#000 calc(100% - 28px),transparent)}
29
34
  .tabs-row::-webkit-scrollbar{display:none}
30
35
  .status-tab{position:relative;display:inline-flex;align-items:center;gap:5px;flex:none;height:32px;padding:0 8px;border:0;background:transparent;color:var(--ink-3);font-size:var(--fs-xs);font-weight:500;white-space:nowrap}
31
36
  .status-tab:hover{color:var(--ink)}
32
37
  .status-tab[aria-pressed="true"]{color:var(--ink)}
33
38
  .status-tab[aria-pressed="true"]::after{content:"";position:absolute;left:6px;right:6px;bottom:-3px;height:2px;border-radius:2px;background:var(--accent)}
34
39
  .status-tab-count{color:var(--ink-4);font-size:var(--fs-2xs);font-variant-numeric:tabular-nums}
35
- .task-group{margin-top:10px}
36
- .task-group-head{display:flex;align-items:center;gap:6px;padding:4px 8px 6px;color:var(--ink-4);font-size:var(--fs-2xs);font-weight:600;text-transform:uppercase;letter-spacing:.07em}
40
+ .task-group{margin-top:8px}
41
+ .task-group-head{display:flex;align-items:center;gap:6px;padding:4px 8px 4px;color:var(--ink-4);font-size:var(--fs-2xs);font-weight:600;text-transform:uppercase;letter-spacing:.07em}
37
42
  .task-group-head .count{background:transparent;padding:0;min-width:0}
38
- .task-row{position:relative;display:flex;align-items:flex-start;gap:10px;width:100%;padding:9px 10px;border:0;border-radius:var(--r-md);background:transparent;text-align:left;transition:background var(--t-fast)}
39
- .task-row>.dot{margin-top:6px}
43
+ .task-row{position:relative;display:flex;align-items:flex-start;gap:9px;width:100%;padding:7px 10px;border:0;border-radius:var(--r-md);background:transparent;text-align:left;transition:background var(--t-fast)}
44
+ .task-row>.dot{margin-top:5px}
40
45
  .task-row:hover{background:var(--surface-3)}
41
46
  .task-row[aria-current="true"]{background:var(--surface-3);box-shadow:inset 0 0 0 1px var(--line-2)}
42
- .task-row[aria-current="true"]::before{content:"";position:absolute;left:-8px;top:10px;bottom:10px;width:3px;border-radius:0 3px 3px 0;background:var(--accent)}
43
- .task-body{display:grid;gap:3px;flex:1;min-width:0}
47
+ .task-row[aria-current="true"]::before{content:"";position:absolute;left:0;top:9px;bottom:9px;width:3px;border-radius:0 3px 3px 0;background:var(--accent)}
48
+ .task-body{display:grid;gap:1px;flex:1;min-width:0}
44
49
  .task-line{display:flex;align-items:center;gap:8px;min-width:0}
45
- .task-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ink);font-size:var(--fs-md);font-weight:500}
50
+ .task-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ink);font-size:var(--fs-md);font-weight:500;line-height:1.35}
46
51
  .task-time{flex:none;color:var(--ink-4);font-size:var(--fs-2xs);font-variant-numeric:tabular-nums}
47
52
  .task-sub{gap:8px;height:18px;color:var(--ink-4);font-size:var(--fs-2xs)}
48
53
  .task-id{font-size:var(--fs-2xs);line-height:1;color:var(--ink-3)}
49
- .task-meta{display:inline-flex;align-items:center;gap:3px;line-height:1;white-space:nowrap}
50
- .task-meta .icon{width:11px;height:11px}
54
+ .task-count{display:inline-flex;align-items:center;gap:3px;line-height:1;white-space:nowrap}
55
+ .task-count .icon{width:11px;height:11px}
51
56
  .task-signals{display:inline-flex;gap:4px;margin-left:auto}
52
57
  .signal{display:inline-flex;align-items:center;gap:3px;height:18px;padding:0 6px;border-radius:var(--r-pill);background:var(--tone-soft);color:var(--tone);font-size:10.5px;font-weight:600;font-variant-numeric:tabular-nums}
53
58
  .signal .icon{width:11px;height:11px;stroke-width:2}
@@ -59,12 +64,11 @@ export const VIEW_STYLES = `
59
64
  .pager-count{grid-column:2;text-align:center;color:var(--ink-4);font-size:var(--fs-2xs);font-variant-numeric:tabular-nums}
60
65
  .pager-clear{height:28px;border:1px dashed var(--line-3);border-radius:var(--r-sm);background:transparent;color:var(--ink-3);font-size:var(--fs-xs)}
61
66
  .pager-clear:hover{color:var(--accent);border-color:var(--accent-line)}
62
- .foot-btn{display:inline-flex;align-items:center;gap:7px;height:32px;padding:0 10px;border:1px solid var(--line-2);border-radius:var(--r-sm);background:transparent;color:var(--ink-2);font-size:var(--fs-xs);font-weight:500;min-width:0}
67
+ .foot-btn{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 8px;border:1px solid var(--line-2);border-radius:var(--r-sm);background:transparent;color:var(--ink-2);font-size:var(--fs-xs);font-weight:500;min-width:0}
63
68
  .foot-btn span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
64
69
  .foot-btn:hover{color:var(--ink);border-color:var(--line-3);background:var(--surface-3)}
65
70
  .foot-btn[aria-pressed="true"]{color:var(--accent);border-color:var(--accent-line);background:var(--accent-soft)}
66
71
  .foot-btn kbd{margin-left:2px}
67
- .side-foot .foot-btn:first-child{flex:1}
68
72
  .side-foot .icon-btn{margin-left:auto}
69
73
 
70
74
  /* ---------- Page scaffolding ---------- */
@@ -73,18 +77,12 @@ export const VIEW_STYLES = `
73
77
  .page-title{margin-top:6px;font-size:var(--fs-2xl);font-weight:650;letter-spacing:-.025em}
74
78
  .page-sub{margin-top:4px;color:var(--ink-3)}
75
79
  .page-foot{margin-top:20px;color:var(--ink-4);font-size:var(--fs-xs);text-align:center}
76
- .section{margin-top:28px;min-width:0}
77
- .section-title{display:flex;align-items:center;gap:10px;margin-bottom:12px}
78
- .section-title h2{display:flex;align-items:center;gap:8px;font-size:var(--fs-lg);font-weight:600}
79
- .section-actions{margin-left:auto}
80
80
  .sub-head{display:flex;align-items:center;gap:8px;margin-top:6px;font-size:var(--fs-sm);font-weight:600}
81
81
 
82
82
  /* ---------- Overview ---------- */
83
- .metric-strip{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:10px;margin-bottom:14px}
83
+ .metric-strip{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:10px;margin-bottom:16px}
84
84
  .metric-strip .metric{padding:14px 16px;border-radius:var(--r-lg)}
85
85
  .metric-strip .metric-value{font-size:var(--fs-2xl)}
86
- .overview-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;margin-bottom:14px;align-items:start}
87
- .overview>.card{margin-bottom:14px}
88
86
  .row-list{display:grid;gap:2px;margin:-4px -8px}
89
87
  .list-row{display:flex;align-items:center;gap:10px;width:100%;min-height:38px;padding:7px 8px;border:0;border-radius:var(--r-sm);background:transparent;color:var(--ink);text-align:left;font-size:var(--fs-sm)}
90
88
  .list-row:hover:not(:disabled){background:var(--surface-3)}
@@ -122,29 +120,30 @@ export const VIEW_STYLES = `
122
120
  .tab .icon{color:var(--ink-4)}
123
121
  .tab[aria-selected="true"] .icon{color:var(--accent)}
124
122
  .tab:focus-visible{box-shadow:inset var(--focus)}
125
- .tab-panel{padding-top:20px;min-width:0}
126
- .tab-panel>.card{margin-bottom:14px}
127
- .tab-panel>.section:first-child{margin-top:4px}
123
+ .tab .count.tone-warn{background:var(--warn-soft);color:var(--warn)}
124
+ .tab-panel{display:flex;flex-direction:column;gap:16px;padding-top:20px;min-width:0}
125
+ .tab-panel [id^="detail-"]{scroll-margin-top:calc(var(--header-h) + 60px)}
128
126
 
129
- /* Now card */
130
- .now-card{border-color:var(--line-2);background:linear-gradient(180deg,var(--surface-2),var(--surface))}
127
+ /* Now banner: the execution status tone as a left stripe and a soft wash */
128
+ .now-card{border-color:var(--line-2);background:linear-gradient(100deg,var(--tone-soft,transparent),transparent 62%),var(--surface);box-shadow:inset 3px 0 0 var(--tone,var(--line-3))}
129
+ .now-card>.card-body{gap:0;padding:16px 18px 16px 20px}
131
130
  .now-head{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
132
131
  .now-owner{color:var(--ink-2);font-size:var(--fs-sm);font-weight:500}
133
- .now-summary{margin-top:10px;font-size:var(--fs-lg);line-height:1.45;color:var(--ink)}
132
+ .now-summary{margin-top:10px;font-size:var(--fs-lg);font-weight:500;line-height:1.45;color:var(--ink)}
134
133
  .now-reason{margin-top:4px;color:var(--ink-3);font-size:var(--fs-sm)}
135
134
  .now-note{margin-top:8px;color:var(--ink-3);font-size:var(--fs-sm)}
136
135
  .signal-list{list-style:none;display:grid;gap:6px;margin:12px 0 0;padding:0}
137
136
  .signal-row{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 8px;padding:8px 10px;border-radius:var(--r-sm);background:var(--tone-soft);font-size:var(--fs-sm)}
138
137
  .signal-row>.icon{align-self:center;color:var(--tone)}
139
138
  .signal-kind{color:var(--tone);font-weight:600}
140
- .next-line{display:flex;flex-wrap:wrap;align-items:center;gap:4px;color:var(--ink-3);font-size:var(--fs-xs)}
139
+ .next-line{display:flex;flex-wrap:wrap;align-items:center;gap:4px;margin-top:12px;padding-top:10px;border-top:1px solid var(--line);color:var(--ink-3);font-size:var(--fs-xs)}
141
140
  .next-line:empty{display:none}
142
141
  .next-line .icon{color:var(--accent)}
143
142
  .next-line strong{color:var(--ink)}
144
143
 
145
144
  /* Needs you / input requests */
146
145
  .needs-card{border-color:var(--warn);box-shadow:0 0 0 3px var(--warn-soft)}
147
- .needs-card .card-title .icon{color:var(--warn)}
146
+ .needs-card .card-icon{background:var(--warn-soft);color:var(--warn)}
148
147
  .input-card{display:grid;gap:10px;padding:14px;border:1px solid var(--line-2);border-radius:var(--r-md);background:var(--surface-2)}
149
148
  .input-head{display:flex;flex-wrap:wrap;align-items:center;gap:8px;color:var(--ink-3);font-size:var(--fs-xs)}
150
149
  .input-kicker{display:inline-flex;align-items:center;gap:5px;color:var(--warn);font-weight:600;text-transform:uppercase;letter-spacing:.06em;font-size:var(--fs-2xs)}
@@ -160,22 +159,20 @@ export const VIEW_STYLES = `
160
159
  .input-form{display:flex;gap:8px}
161
160
  .input-form input{flex:1}
162
161
 
163
- /* Decisions, sessions, planning */
162
+ /* Decisions, planning */
164
163
  .decision{display:grid;gap:4px;padding-top:10px;border-top:1px solid var(--line)}
165
164
  .decision:first-child{padding-top:0;border-top:0}
166
165
  .decision-head{display:flex;align-items:center;gap:8px;font-size:var(--fs-sm)}
167
166
  .decision-head strong{flex:1;min-width:0;font-weight:600}
168
- .session-list{list-style:none;display:grid;gap:8px;margin:0;padding:0}
169
- .session-row{display:grid;gap:3px;padding:9px 11px;border-radius:var(--r-sm);background:var(--surface-2);border:1px solid var(--line)}
170
- .session-row-head{display:flex;align-items:center;gap:8px;font-size:var(--fs-sm)}
171
- .session-row p{color:var(--ink-2)}
172
167
  .planning-card .kv{font-size:var(--fs-xs)}
173
168
 
174
- /* Work items */
175
- .work-card{border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface);box-shadow:var(--shadow-1);min-width:0}
169
+ /* Work items (rows of the Work list card) */
170
+ .work-card{min-width:0}
176
171
  .work-head{display:flex;align-items:center;gap:10px;padding:13px 16px;list-style:none}
177
172
  summary.work-head{cursor:pointer}
178
173
  summary.work-head::-webkit-details-marker{display:none}
174
+ summary.work-head:hover .work-title{color:var(--ink)}
175
+ summary.work-head:focus-visible{box-shadow:inset 0 0 0 2px var(--accent-line)}
179
176
  .work-title{flex:1;min-width:0;font-weight:600;font-size:var(--fs-md);overflow-wrap:anywhere}
180
177
  .work-body{display:grid;gap:12px;padding:0 16px 16px 34px}
181
178
  .work-card.is-settled .work-title{color:var(--ink-2);font-weight:500}
@@ -187,21 +184,33 @@ summary.work-head::-webkit-details-marker{display:none}
187
184
  .candidate-seq{font-family:var(--font-mono);color:var(--accent)}
188
185
 
189
186
  /* Records, runs, roles */
190
- .record,.run-card,.review-card{display:grid;gap:8px;min-width:0;padding:12px 14px;border:1px solid var(--line);border-radius:var(--r-md);background:var(--surface)}
187
+ .record,.run-card,.review-card{display:grid;grid-template-columns:minmax(0,1fr);gap:8px;min-width:0;overflow-wrap:anywhere;padding:12px 14px;border:1px solid var(--line);border-radius:var(--r-md);background:var(--surface)}
191
188
  .record.is-compact{padding:9px 12px;background:var(--surface-2)}
192
189
  .record-head,.run-head{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0;font-size:var(--fs-sm)}
193
190
  .record-store{color:var(--ink-3);font-size:var(--fs-2xs);font-weight:600;text-transform:uppercase;letter-spacing:.06em}
194
191
  .record-actions{display:flex;gap:8px}
195
- .run-card[data-status="failed"]{border-color:color-mix(in srgb,var(--bad) 35%,var(--line))}
192
+ .record-lead{font-weight:500;overflow-wrap:anywhere}
193
+ .delivery-stack>.sub-head:not(:first-child){margin-top:10px}
194
+ .delivery-project .record-head strong{overflow-wrap:anywhere}
195
+ .check-list{list-style:none;margin:0;padding:0;display:grid;gap:4px;font-size:var(--fs-xs)}
196
+ .check-list li{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:2px 8px;min-width:0}
197
+ .check-details{grid-column:2/-1;white-space:pre-wrap;overflow-wrap:anywhere}
196
198
  .run-role{font-weight:600}
197
- .role-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px}
198
- .role-card{display:grid;gap:10px;align-content:start;min-width:0;padding:14px;border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface);box-shadow:var(--shadow-1)}
199
+ .role-card{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px 12px;align-content:start;min-width:0;padding:14px 16px}
200
+ .role-card>*{grid-column:1/-1;min-width:0}
201
+ .role-card>.role-head{grid-column:1;grid-row:1}
202
+ .role-card>.role-actions{grid-column:2;grid-row:1;align-self:center}
203
+ .role-card>:not(.role-head):not(.role-actions){margin-left:42px}
199
204
  .role-head{display:flex;align-items:center;gap:10px}
200
205
  .role-title{display:grid;flex:1;min-width:0;line-height:1.3}
201
206
  .role-title .faint{font-size:var(--fs-xs)}
202
207
  .avatar{display:grid;place-items:center;width:32px;height:32px;flex:none;border-radius:9px;background:var(--surface-3);color:var(--ink-2);font-weight:650;font-size:var(--fs-sm)}
203
208
  .role-card .kv{font-size:var(--fs-xs)}
204
- .role-actions{display:flex;justify-content:flex-end;margin:-4px -6px -6px}
209
+ .role-actions{display:flex;justify-content:flex-end;margin-right:-8px}
210
+ .role-session{display:grid;gap:3px;min-width:0;font-size:var(--fs-sm)}
211
+ .role-session-head{display:flex;flex-wrap:wrap;align-items:center;gap:4px 8px}
212
+ .role-session>p{color:var(--ink-2)}
213
+ .card-actions>[data-slot="session-counts"]:empty{display:none}
205
214
 
206
215
  /* History timeline */
207
216
  .timeline{list-style:none;margin:0;padding:0;position:relative;display:grid;gap:0}
@@ -210,13 +219,23 @@ summary.work-head::-webkit-details-marker{display:none}
210
219
  .timeline-mark{position:relative;z-index:1;display:grid;place-items:center;width:28px;height:28px;border-radius:50%;background:var(--surface-2);border:1px solid var(--line-2);color:var(--ink-3)}
211
220
  .kind-decision .timeline-mark{color:var(--ok);border-color:var(--ok-soft);background:var(--ok-soft)}
212
221
  .kind-milestone .timeline-mark{color:var(--accent);border-color:var(--accent-soft);background:var(--accent-soft)}
213
- .timeline-body{display:grid;gap:6px;min-width:0;padding-top:3px}
222
+ .kind-run .timeline-mark{color:var(--info);border-color:var(--info-soft);background:var(--info-soft)}
223
+ .kind-question .timeline-mark{color:var(--warn);border-color:var(--warn-soft);background:var(--warn-soft)}
224
+ .timeline-body{display:grid;grid-template-columns:minmax(0,1fr);gap:6px;min-width:0;padding-top:3px;overflow-wrap:anywhere}
214
225
  .timeline-head{display:flex;flex-wrap:wrap;align-items:center;gap:8px;font-size:var(--fs-sm)}
226
+ .timeline-item>.record{align-self:start;padding:4px 0 0;border:0;background:transparent}
227
+ .timeline .lazy-head{align-items:flex-start;padding:2px 0 0;gap:8px}
228
+ .timeline .lazy-head .disclosure-chevron{order:2;margin-top:4px}
229
+ .timeline .lazy-body{padding:10px 0 2px}
230
+ .timeline-summary{flex:1;display:grid;gap:4px;min-width:0}
231
+ .timeline-title,.timeline-preview{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
232
+ .timeline-preview{margin:0}
233
+ .lazy-row[open] .timeline-preview{display:none}
215
234
  .timeline-empty{list-style:none}
216
235
  .timeline .show-more{margin-left:40px}
217
236
 
218
237
  /* Evidence */
219
- .file-list{display:grid;gap:2px}
238
+ .file-list{display:grid;grid-template-columns:minmax(0,1fr);gap:2px}
220
239
  .file-list:empty{display:none}
221
240
  .file-row{display:flex;align-items:center;gap:8px;min-height:32px;padding:5px 8px;border:0;border-radius:var(--r-sm);background:transparent;text-align:left;font-size:var(--fs-sm);color:var(--ink-2)}
222
241
  .file-row:hover{background:var(--surface-3);color:var(--ink)}
@@ -236,6 +255,7 @@ summary.work-head::-webkit-details-marker{display:none}
236
255
  .feed:focus-visible{box-shadow:inset var(--focus)}
237
256
  .feed>.empty{margin:auto 0}
238
257
  .feed-note{color:var(--ink-4);font-size:var(--fs-2xs);text-align:center}
258
+ .feed-older{align-self:center}
239
259
  .feed-day{display:flex;align-items:center;gap:10px;color:var(--ink-4);font-size:var(--fs-2xs);font-weight:500}
240
260
  .feed-day::before,.feed-day::after{content:"";flex:1;height:1px;background:var(--line)}
241
261
  .msg{display:flex;gap:10px;max-width:100%;min-width:0}
@@ -194,7 +194,7 @@ async function handleHttpRequest(request, response, store, dependencies, token,
194
194
  }
195
195
  return;
196
196
  }
197
- const surfaceTarget = /^\/api\/tasks\/([^/]+)\/(context|delta|inspect|metadata|messages|control)$/.exec(pathname);
197
+ const surfaceTarget = /^\/api\/tasks\/([^/]+)\/(context|delta|inspect|list|metadata|messages|control)$/.exec(pathname);
198
198
  if (surfaceTarget && dependencies.surface) {
199
199
  try {
200
200
  let taskId;
@@ -223,6 +223,17 @@ async function handleHttpRequest(request, response, store, dependencies, token,
223
223
  ...(query.has("cursor") ? { cursor: query.get("cursor") } : {})
224
224
  });
225
225
  }
226
+ else if (method === "GET" && action === "list") {
227
+ const limit = query.get("limit");
228
+ if (limit !== null && !/^\d{1,3}$/u.test(limit))
229
+ throw new WebRequestRejected("Invalid list limit.");
230
+ value = dependencies.surface.list(taskId, {
231
+ store: query.get("store") ?? "",
232
+ ...(query.has("status") ? { status: query.get("status") } : {}),
233
+ ...(query.has("cursor") ? { cursor: query.get("cursor") } : {}),
234
+ ...(limit === null ? {} : { limit: Number(limit) })
235
+ });
236
+ }
226
237
  else if (method === "POST" && action === "messages") {
227
238
  const body = await readMutationBody(request);
228
239
  if (typeof body !== "object" || body === null || Array.isArray(body)
@@ -3,7 +3,7 @@ import { openTaskArtifactRepository } from "../artifacts/taskArtifactRepository.
3
3
  import { applyGlobalInputControl } from "../commands/globalRoleCommands.js";
4
4
  import { applyTaskInputControl, sendTaskMessageCommand, updateTaskMetadataCommand } from "../commands/taskCommands.js";
5
5
  import { runTaskInputCommand } from "../commands/taskInputCommands.js";
6
- import { inspectTaskContext, readTaskContext, readTaskContextDelta, withContextObservations } from "../context/taskContext.js";
6
+ import { inspectTaskContext, listTaskContext, readTaskContext, readTaskContextDelta, withContextObservations } from "../context/taskContext.js";
7
7
  import { BUILTIN_CAPABILITIES } from "../kernel/builtinCapabilities.js";
8
8
  import { capabilitySchemaError } from "../kernel/capabilitySchema.js";
9
9
  import { recordGlobalInterruptResult, recordGlobalSteerResult } from "../message/globalInterrupt.js";
@@ -248,6 +248,13 @@ export function createWebTaskSurface(store, options = {}, observations = [], hos
248
248
  read: async (taskId) => withContextObservations(readTaskContext(store, taskId, environment), observations),
249
249
  delta: (taskId, input) => readTaskContextDelta(store, taskId, input, environment),
250
250
  inspect: (taskId, input) => inspectTaskContext(store, taskId, input, environment),
251
+ // The same paged family discovery as `task context list`: summaries and
252
+ // exact references, never bodies; continuations keep their filters.
253
+ list: (taskId, input) => listTaskContext(store, taskId, input.store, {
254
+ ...(input.status === undefined ? {} : { status: input.status }),
255
+ ...(input.cursor === undefined ? {} : { cursor: input.cursor }),
256
+ ...(input.limit === undefined ? {} : { limit: input.limit })
257
+ }, environment),
251
258
  update: (taskId, input) => {
252
259
  const descriptor = BUILTIN_CAPABILITIES.find((entry) => entry.name === "task.update");
253
260
  const error = capabilitySchemaError(descriptor.inputSchema, { taskId, patch: input });
@@ -65,6 +65,22 @@ silently rerun successful Producers.
65
65
 
66
66
  ## Review
67
67
 
68
+ Capturing a Run-backed WorkItem Candidate freezes its exact source report and
69
+ Candidate identity in the existing immutable Context Snapshot store. Review
70
+ receives a `source-run` pointer with `evidenceOf=<work-item>/<candidate>` and
71
+ expands the original report through `task run context expand`, including all
72
+ content pages. Source, Candidate or report drift refuses a new dispatch; already
73
+ frozen Run Context remains readable. Task-final producer evidence requires an
74
+ exact Candidate head or a committed Integration at the fixed head and Task-main
75
+ target. Earlier attempts sharing a target are not ancestry proof. A later direct
76
+ Task-main repair remains reviewable without a matching producer report: the
77
+ ReviewRound pointer identifies the evidence gap. Attached reports describe their
78
+ named Candidate, not validation of the entire Task head; a Reviewer assesses
79
+ the fixed code and reports missing validation rather than borrowing old success.
80
+ Historical Candidates without this frozen proof remain inspectable, but need
81
+ newly captured delivery evidence before a new Candidate Review; old Snapshots
82
+ are never backfilled.
83
+
68
84
  ReviewRound owns frozen Candidate or Task-head identity, workspace provenance,
69
85
  execution topology, exact main Reviewer Run, lifecycle and Core diagnostics.
70
86
  Its completed state is structural execution evidence, not a “pass” extracted
@@ -52,6 +52,19 @@ Review 结果。Producer 从不直接进入 Integration 或验收。重试针对
52
52
 
53
53
  ## Review
54
54
 
55
+ 捕获 Run 来源的 WorkItem Candidate 时,会在现有不可变 Context Snapshot 存储中
56
+ 冻结其精确原始报告与 Candidate 身份。Review 获得带
57
+ `evidenceOf=<work-item>/<candidate>` 的 `source-run` 指针,通过
58
+ `task run context expand` 读取原文与所有内容分页。来源、Candidate 或报告漂移会
59
+ 拒绝新的派发,但已经冻结的 Run Context 仍可读取。Task-final 来源证据需要精确
60
+ 匹配 Candidate 提交,或匹配固定 head 与 Task-main 目标的已提交 Integration。
61
+ 仅共享目标的历史 attempts 不是血缘证明。Task-main 后续直接修复没有匹配报告时,
62
+ 仍可审查,ReviewRound 指针明确提示证据缺口。附带报告只描述其命名的 Candidate,
63
+ 不是整个 Task head 已通过验证的证明;Reviewer 应审查固定代码、报告验证缺口,
64
+ 不能借用旧成功结论。
65
+ 缺少冻结证据的历史 Candidate 仍可诊断;新的 Candidate Review 需要新捕获的交付
66
+ 证据,不回填旧 Snapshot。
67
+
55
68
  ReviewRound 拥有冻结的 Candidate 或 Task-head 身份、工作区来源、执行拓扑、精确
56
69
  的 main Reviewer Run、生命周期和 Core 诊断。它的 completed 状态是结构性执行证据,
57
70
  而不是从报告里提取出来的“通过”。