@ran-sh/dsh-crew 1.2.0-rc.4 → 1.2.0-rc.6

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ran-sh/dsh-crew",
3
- "version": "1.2.0-rc.4",
3
+ "version": "1.2.0-rc.6",
4
4
  "type": "module",
5
5
  "main": "./src/hub/entry.mjs",
6
6
  "bin": {
@@ -163,8 +163,8 @@ const COPY = {
163
163
  save: '保存', saved: '已保存', jobs: 'Worker 任务', empty: '当前没有 Worker / Reviewer 任务。',
164
164
  adaptiveTitle: '自适应模型路由(实验)', adaptiveHint: '默认关闭;只重排系统自动候选,手动模型优先级始终保持原序。健康信号仅来自本进程已观察到的成功、失败、超时与粗粒度延迟,重启后清空。',
165
165
  adaptiveEnabled: '启用自适应路由', adaptiveWindow: '健康窗口', adaptiveSamples: '最少样本', adaptiveBoundary: '下一个工作流生效',
166
- modelActivity: '模型调用概览', modelActivityHint: '聚合本 Hub 内存中最近 500 个任务的真实调用证据,最多显示 50 个模型;不保存提示词、结果或凭据。', noModelActivity: '还没有真实模型调用。',
167
- calls: '调用次数', invocationSource: '任务来源', routingSource: '路由来源', lastCalled: '最近调用', role: '角色', model: '模型', never: '—',
166
+ modelActivity: '模型活动概览', modelActivityHint: '聚合本 Hub 内存中最近 500 个含真实调用证据的任务;每个模型按任务计数(不是推测底层轮次),最多显示 50 个模型。不保存提示词、结果或凭据。', noModelActivity: '还没有真实模型活动。',
167
+ calls: '任务数', invocationSource: '任务来源', routingSource: '路由来源', lastCalled: '最近调用', role: '角色', model: '模型', never: '—',
168
168
  col: { id: '任务', role: '角色', source: '来源', model: '模型', tier: '档位', status: '状态', progress: '进度', tokens: 'tokens ⇅', task: '内容' },
169
169
  working: '处理中…',
170
170
  tips: {
@@ -305,8 +305,8 @@ const COPY = {
305
305
  save: 'Save', saved: 'Saved', jobs: 'Worker jobs', empty: 'No Worker / Reviewer jobs yet.',
306
306
  adaptiveTitle: 'Adaptive model routing (experimental)', adaptiveHint: 'Off by default. Only system-derived candidates may be reordered; explicit model priorities always keep their order. Health uses only process-local success, failure, timeout, and coarse latency observations and resets on restart.',
307
307
  adaptiveEnabled: 'Enable adaptive routing', adaptiveWindow: 'Health window', adaptiveSamples: 'Minimum samples', adaptiveBoundary: 'Effective for the next workflow',
308
- modelActivity: 'Model invocation overview', modelActivityHint: 'Aggregates real invocation evidence from the latest 500 in-memory Hub jobs and shows at most 50 models; prompts, results, and credentials are never stored here.', noModelActivity: 'No real model invocations yet.',
309
- calls: 'Calls', invocationSource: 'Task source', routingSource: 'Routing source', lastCalled: 'Last called', role: 'Role', model: 'Model', never: '—',
308
+ modelActivity: 'Model activity overview', modelActivityHint: 'Aggregates the latest 500 in-memory Hub jobs with real model-activity evidence; each model is counted once per qualifying job (not an inferred turn count). Shows at most 50 models; prompts, results, and credentials are never stored here.', noModelActivity: 'No real model activity yet.',
309
+ calls: 'Jobs', invocationSource: 'Task source', routingSource: 'Routing source', lastCalled: 'Last called', role: 'Role', model: 'Model', never: '—',
310
310
  col: { id: 'job', role: 'role', source: 'source', model: 'model', tier: 'tier', status: 'status', progress: 'progress', tokens: 'tokens ⇅', task: 'task' },
311
311
  working: 'Working…',
312
312
  tips: {
@@ -1838,7 +1838,7 @@ function WorkersPanel({ ctx }: { ctx: any }) {
1838
1838
  <div role="row" key={`${entry.provider}/${entry.model}`} style={{ display: 'grid', gridTemplateColumns: 'minmax(190px, 1.35fr) 72px minmax(170px, 1fr) 125px', gap: 10, alignItems: 'center', padding: '7px 6px', borderTop: '1px solid rgba(128,128,128,0.16)' }}>
1839
1839
  <span role="cell" style={{ minWidth: 0 }}><strong style={{ display: 'block', fontSize: 12 }}>{entry.model}</strong><span style={{ ...S.mono, opacity: 0.55 }}>{entry.provider}</span></span>
1840
1840
  <span role="cell" style={{ ...S.mono, fontSize: 15, fontWeight: 650 }}>{entry.count}</span>
1841
- <span role="cell" style={{ minWidth: 0, fontSize: 11.5 }}><span style={{ display: 'block' }}>{entry.task_sources.map(sourceLabel).join(' · ')}</span><span style={{ display: 'block', opacity: 0.55 }}>{entry.selection_sources.join(' · ')} · {entry.roles.join(' / ')}</span></span>
1841
+ <span role="cell" style={{ minWidth: 0, fontSize: 11.5 }}><span style={{ display: 'block' }}>{entry.task_sources.map(sourceLabel).join(' · ')}</span><span style={{ display: 'block', opacity: 0.55 }}>{entry.selection_sources.join(' · ')} · {entry.roles.length > 0 ? entry.roles.join(' / ') : copy.never}</span></span>
1842
1842
  <span role="cell" style={{ ...S.mono, fontSize: 10.5 }}>{formatTimestamp(entry.last_called_at, locale)}</span>
1843
1843
  </div>
1844
1844
  ))}
@@ -21,9 +21,11 @@ function hasInvocationEvidence(job) {
21
21
  }
22
22
 
23
23
  /**
24
- * Build a bounded, presentation-only model activity summary from the jobs the
25
- * Hub already exposes. No prompts, results, credentials, or new persistence
26
- * are introduced here.
24
+ * Build a bounded, presentation-only, job-level model activity summary from
25
+ * the jobs the Hub already exposes. Each qualifying job contributes one row
26
+ * count for its selected provider/model; the count is not an inferred number
27
+ * of underlying model turns. No prompts, results, credentials, or new
28
+ * persistence are introduced here.
27
29
  */
28
30
  export function aggregateModelInvocations(jobs = []) {
29
31
  const groups = new Map();
@@ -45,7 +47,12 @@ export function aggregateModelInvocations(jobs = []) {
45
47
  current.count += 1;
46
48
  current.taskSources.add(clean(job?.source, 'api'));
47
49
  current.selectionSources.add(clean(job?.selection_source, 'unknown'));
48
- current.roles.add(job?.role === 'reviewer' ? 'reviewer' : 'worker');
50
+ // Do not infer a role from malformed, missing, or future role values. The
51
+ // summary is presentation evidence and must never assert a role the job
52
+ // did not provide.
53
+ if (job?.role === 'worker' || job?.role === 'reviewer') {
54
+ current.roles.add(job.role);
55
+ }
49
56
  const calledAt = validTimestamp(job?.startedAt);
50
57
  if (calledAt && (!current.lastCalledAt || Date.parse(calledAt) > Date.parse(current.lastCalledAt))) {
51
58
  current.lastCalledAt = calledAt;
@@ -36,7 +36,7 @@ export {
36
36
  // included in the identity contract.
37
37
  const RUNTIME_ID = randomUUID();
38
38
 
39
- export const RUNTIME_VERSION = '1.2.0-rc.4';
39
+ export const RUNTIME_VERSION = '1.2.0-rc.6';
40
40
  export const HUB_PROTOCOL_VERSION = 1;
41
41
 
42
42
  export const HUB_CAPABILITIES = Object.freeze([
@@ -82,15 +82,28 @@ function Test-OfficialWebReady {
82
82
  }
83
83
  }
84
84
 
85
- function Get-OfficialFrontendOverlay {
86
- $frontendRoot = Join-Path $env:USERPROFILE '.config\dsh-crew\frontend'
87
- $path = Join-Path $frontendRoot 'official-web.patch.json'
88
- if (-not (Test-Path -LiteralPath $path -PathType Leaf)) { throw 'Crew frontend overlay is missing. Run dsh-crew update with the current GitHub candidate.' }
89
- $patch = @(Get-Content -LiteralPath $path -Raw | ConvertFrom-Json)
90
- if ($patch.Count -ne 1 -or @($patch[0].insert).Count -ne 1 -or $patch[0].insert[0].id -ne 'dsh-crew-official-web-bridge') {
91
- throw 'Crew frontend overlay has an unexpected structure.'
92
- }
93
- $uri = [Uri] ([string] $patch[0].insert[0].name)
85
+ function Get-OfficialFrontendOverlay {
86
+ $frontendRoot = Join-Path $env:USERPROFILE '.config\dsh-crew\frontend'
87
+ $path = Join-Path $frontendRoot 'official-web.patch.json'
88
+ if (-not (Test-Path -LiteralPath $path -PathType Leaf)) { throw 'Crew frontend overlay is missing. Run dsh-crew update with the current GitHub candidate.' }
89
+ # Windows PowerShell 5.1 keeps a JSON root array as one pipeline object;
90
+ # direct `$patch[0].insert[0]` therefore resolves `insert` as IList.Insert
91
+ # instead of indexing the JSON property. Flatten both PowerShell generations
92
+ # explicitly and read properties through PSObject so StrictMode reports a
93
+ # useful validation error instead of "property id cannot be found".
94
+ $parsed = Get-Content -LiteralPath $path -Raw | ConvertFrom-Json
95
+ $patch = @($parsed | ForEach-Object { $_ })
96
+ $root = if ($patch.Count -eq 1) { $patch[0] } else { $null }
97
+ $insertProperty = if ($null -ne $root) { $root.PSObject.Properties['insert'] } else { $null }
98
+ $insertValue = if ($null -ne $insertProperty) { $insertProperty.Value } else { $null }
99
+ $inserts = @($insertValue | ForEach-Object { $_ })
100
+ $bridge = if ($inserts.Count -eq 1) { $inserts[0] } else { $null }
101
+ $idProperty = if ($null -ne $bridge) { $bridge.PSObject.Properties['id'] } else { $null }
102
+ $nameProperty = if ($null -ne $bridge) { $bridge.PSObject.Properties['name'] } else { $null }
103
+ if ($patch.Count -ne 1 -or $inserts.Count -ne 1 -or $null -eq $idProperty -or [string] $idProperty.Value -ne 'dsh-crew-official-web-bridge' -or $null -eq $nameProperty) {
104
+ throw 'Crew frontend overlay has an unexpected structure.'
105
+ }
106
+ $uri = [Uri] ([string] $nameProperty.Value)
94
107
  if (-not $uri.IsFile) { throw 'Crew frontend must load from its local snapshot.' }
95
108
  $entry = [IO.Path]::GetFullPath($uri.LocalPath)
96
109
  $prefix = [IO.Path]::GetFullPath((Join-Path $frontendRoot 'revisions')) + [IO.Path]::DirectorySeparatorChar