@ran-sh/dsh-crew 1.1.1 → 1.2.0-rc.5

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 (84) hide show
  1. package/.claude-plugin/marketplace.json +16 -17
  2. package/.claude-plugin/plugin.json +7 -1
  3. package/README.md +44 -15
  4. package/README.zh.md +37 -12
  5. package/agents/ds-flash.md +16 -18
  6. package/agents/ds-pro.md +16 -24
  7. package/agents/ds-reviewer.md +15 -15
  8. package/agents/ds-worker.md +16 -16
  9. package/bin/dsh-crew.mjs +16 -12
  10. package/codex/AGENTS.md +37 -85
  11. package/codex/agents/ds-flash.toml +18 -14
  12. package/codex/agents/ds-pro.toml +18 -15
  13. package/codex/agents/ds-reviewer.toml +17 -13
  14. package/codex/agents/ds-worker.toml +17 -13
  15. package/codex/prompts/dsh-config.md +17 -1
  16. package/codex/prompts/dsh-status.md +5 -1
  17. package/commands/config.md +16 -4
  18. package/commands/status.md +6 -2
  19. package/docs/installation.md +54 -9
  20. package/docs/readiness-matrix.md +14 -6
  21. package/docs/ui-surfaces.md +32 -17
  22. package/lib/client.js +769 -177
  23. package/official-web-bridge/lib/client.js +297 -209
  24. package/official-web-bridge/overlay-entry.mjs +59 -0
  25. package/package.json +6 -3
  26. package/scripts/build-client.mjs +2 -0
  27. package/scripts/setup.mjs +8 -7
  28. package/scripts/verify-crew-ui-polish.mjs +145 -0
  29. package/scripts/verify-history-ui.mjs +97 -0
  30. package/scripts/verify-npm-install.mjs +1 -1
  31. package/src/client/history-panel.tsx +108 -0
  32. package/src/client/host-readiness.mjs +15 -6
  33. package/src/client/index.tsx +91 -69
  34. package/src/client/model-callability-view.mjs +17 -0
  35. package/src/client/panel-chrome.tsx +40 -0
  36. package/src/client/quick-panel.tsx +88 -73
  37. package/src/client/readiness-envelope.mjs +34 -0
  38. package/src/client/task-telemetry.mjs +11 -4
  39. package/src/config-readiness.mjs +181 -115
  40. package/src/extension-contract.mjs +44 -26
  41. package/src/history/admission-gate.mjs +51 -0
  42. package/src/history/archive-store.mjs +261 -0
  43. package/src/history/cleanup-plan.mjs +64 -0
  44. package/src/history/http.mjs +32 -0
  45. package/src/history/operation.mjs +86 -0
  46. package/src/history/runner.mjs +51 -0
  47. package/src/history/runtime.mjs +28 -0
  48. package/src/history/service.mjs +137 -0
  49. package/src/history/state.mjs +27 -0
  50. package/src/hub/index.mjs +141 -24
  51. package/src/hub-client.mjs +17 -15
  52. package/src/image-output.mjs +71 -0
  53. package/src/install/install-legacy.mjs +126 -23
  54. package/src/install/npx-lifecycle.mjs +373 -64
  55. package/src/install/official-frontend-assets.mjs +78 -0
  56. package/src/install/payload-content.mjs +88 -0
  57. package/src/install/windows-startup.mjs +107 -19
  58. package/src/install/windows-supervisor-adapter.mjs +443 -0
  59. package/src/install/windows-supervisor-lifecycle.mjs +782 -0
  60. package/src/install/zcode.mjs +53 -14
  61. package/src/job-contracts.mjs +37 -31
  62. package/src/jobs.mjs +2 -2
  63. package/src/mcp-runtime.mjs +74 -9
  64. package/src/model-callability-contract.mjs +79 -0
  65. package/src/multimodal.mjs +0 -0
  66. package/src/official-web-bridge.mjs +0 -2
  67. package/src/provider-health.mjs +130 -124
  68. package/src/readiness-matrix.mjs +20 -15
  69. package/src/runtime-identity-contract.mjs +34 -0
  70. package/src/runtime-identity.mjs +14 -4
  71. package/src/runtime-readiness-snapshot.mjs +285 -87
  72. package/src/server.mjs +86 -76
  73. package/src/standalone-sdk.mjs +23 -0
  74. package/src/supervisor/restart-request.mjs +64 -10
  75. package/src/workflow-runtime.mjs +28 -13
  76. package/windows/start-dsh-crew.cmd +57 -57
  77. package/windows/start-dsh-crew.ps1 +327 -51
  78. package/windows/supervisor-control.ps1 +467 -0
  79. package/zcode/AGENTS.md +4 -1
  80. package/zcode/agents/ds-reviewer.md +31 -36
  81. package/zcode/agents/ds-worker.md +31 -39
  82. package/zcode/commands/dsh-config.md +17 -6
  83. package/zcode/commands/dsh-status.md +5 -4
  84. package/.mcp.json +0 -8
@@ -1,145 +1,211 @@
1
- import { buildReadinessMatrix, READINESS_REASON_CODES } from './readiness-matrix.mjs';
2
- import { PRODUCTION_EXECUTION_PLANE, PRODUCTION_PROFILE, PRODUCTION_LISTEN_PORT } from './runtime-identity.mjs';
1
+ import { buildReadinessMatrix, READINESS_REASON_CODES } from './readiness-matrix.mjs';
2
+ import { PRODUCTION_EXECUTION_PLANE, PRODUCTION_PROFILE, PRODUCTION_LISTEN_PORT } from './runtime-identity.mjs';
3
3
 
4
- function warningCodes(catalogBody) {
4
+ function warningCodes(catalogBody) {
5
5
  const hints = Array.isArray(catalogBody?.health?.hints) ? catalogBody.health.hints : [];
6
6
  return [...new Set(hints
7
7
  .filter((hint) => hint?.level === 'warning' && typeof hint?.code === 'string' && hint.code.trim())
8
8
  .map((hint) => hint.code.trim()))];
9
- }
10
-
11
- function verifiedHubJob(job) {
12
- const context = job?.execution_context;
13
- return job?.status === 'done'
14
- && job?.task_status === 'success'
15
- && job?.delivery_complete === true
16
- && job?.workspace_evidence_ok === true
17
- && context?.execution_plane === PRODUCTION_EXECUTION_PLANE
18
- && context?.profile === PRODUCTION_PROFILE
19
- && Number(context?.listen_port) === PRODUCTION_LISTEN_PORT
20
- && typeof context?.runtime_id === 'string'
21
- && context.runtime_id.trim().length > 0;
22
- }
23
-
24
- function structurallyConsistentProviderInventory(body) {
25
- if (!body || typeof body !== 'object' || body.ok === false || !Array.isArray(body.records)) return false;
26
- return body.records.every((record) => {
27
- if (!record || typeof record.id !== 'string' || record.id.trim() === '') return false;
28
- if (!['present', 'absent'].includes(record.desired_state)) return false;
29
- if (!record.lifecycle || typeof record.lifecycle !== 'object' || Array.isArray(record.lifecycle)) return false;
30
- for (const field of ['installed', 'configured', 'enabled', 'catalogued']) {
31
- if (typeof record.lifecycle[field] !== 'boolean') return false;
32
- }
33
- if (record.desired_state === 'absent' && record.lifecycle.enabled === true) return false;
34
- return true;
35
- });
36
- }
37
-
38
- export function buildHubExecutionRows(hubJobs = []) {
39
- const jobs = Array.isArray(hubJobs) ? hubJobs : [];
40
- const workerPassed = jobs.some((job) => job?.role === 'worker' && verifiedHubJob(job));
41
- const workerPrimaryPassed = jobs.some((job) => job?.role === 'worker'
42
- && verifiedHubJob(job)
43
- && Number(job?.attempt ?? job?.selection_trace?.logical_attempt ?? 0) === 0);
44
- const workerEscalationPassed = jobs.some((job) => job?.role === 'worker'
45
- && verifiedHubJob(job)
46
- && (Number(job?.attempt ?? job?.selection_trace?.logical_attempt ?? 0) > 0));
47
- const reviewerPassed = jobs.some((job) => job?.role === 'reviewer'
48
- && verifiedHubJob(job)
49
- && job?.review_verdict === 'approve');
50
- return [
51
- workerPassed
52
- ? { id: 'model_execution', status: 'PASS', reason_code: 'REAL_EXECUTION_PASSED', evidence_source: 'hub-jobs' }
53
- : { id: 'model_execution', status: 'NOT_RUN', reason_code: 'NO_EXECUTION_EVIDENCE', evidence_source: 'none' },
54
- workerPrimaryPassed
55
- ? { id: 'worker_primary_callable', status: 'PASS', reason_code: 'WORKER_PRIMARY_CALLABLE', evidence_source: 'hub-jobs' }
56
- : { id: 'worker_primary_callable', status: 'NOT_RUN', reason_code: 'NO_EXECUTION_EVIDENCE', evidence_source: 'none' },
57
- workerEscalationPassed
58
- ? { id: 'worker_escalation_callable', status: 'PASS', reason_code: 'WORKER_ESCALATION_CALLABLE', evidence_source: 'hub-jobs' }
59
- : { id: 'worker_escalation_callable', status: 'NOT_RUN', reason_code: 'NO_EXECUTION_EVIDENCE', evidence_source: 'none' },
60
- reviewerPassed
61
- ? { id: 'reviewer_primary_callable', status: 'PASS', reason_code: 'REVIEWER_PRIMARY_CALLABLE', evidence_source: 'hub-jobs' }
62
- : { id: 'reviewer_primary_callable', status: 'NOT_RUN', reason_code: 'NO_EXECUTION_EVIDENCE', evidence_source: 'none' },
63
- { id: 'provider_lifecycle_consistent', status: 'NOT_RUN', reason_code: 'NO_EXECUTION_EVIDENCE', evidence_source: 'none' },
64
- reviewerPassed
65
- ? { id: 'reviewer_pipeline', status: 'PASS', reason_code: 'REAL_REVIEW_PASSED', evidence_source: 'hub-jobs' }
66
- : { id: 'reviewer_pipeline', status: 'NOT_RUN', reason_code: 'NO_EXECUTION_EVIDENCE', evidence_source: 'none' },
67
- ];
68
- }
9
+ }
10
+
11
+ function verifiedHubJob(job) {
12
+ const context = job?.execution_context;
13
+ return job?.status === 'done'
14
+ && job?.task_status === 'success'
15
+ && job?.delivery_complete === true
16
+ && job?.workspace_evidence_ok === true
17
+ && context?.execution_plane === PRODUCTION_EXECUTION_PLANE
18
+ && context?.profile === PRODUCTION_PROFILE
19
+ && Number(context?.listen_port) === PRODUCTION_LISTEN_PORT
20
+ && typeof context?.runtime_id === 'string'
21
+ && context.runtime_id.trim().length > 0;
22
+ }
23
+
24
+ function hasBlockingProviderRecovery(body, currentSelections) {
25
+ if (!Object.hasOwn(body, 'recovery_transactions')) return false;
26
+ if (!Array.isArray(body.recovery_transactions)) return true;
27
+ const selectedProviders = new Set(Object.values(currentSelections ?? {})
28
+ .filter((selection) => selection?.ok === true && typeof selection.provider === 'string')
29
+ .map((selection) => selection.provider));
30
+ return body.recovery_transactions.some((transaction) => transaction?.unresolved === true
31
+ || typeof transaction?.provider_id !== 'string'
32
+ || selectedProviders.has(transaction.provider_id));
33
+ }
34
+
35
+ function structurallyConsistentProviderInventory(body, currentSelections) {
36
+ if (!body || typeof body !== 'object' || body.ok === false || !Array.isArray(body.records)) return false;
37
+ if ('lifecycle_evidence' in body && body.lifecycle_evidence?.ok !== true) return false;
38
+ if ('declaration_evidence' in body && body.declaration_evidence?.ok !== true) return false;
39
+ if ('default_evidence' in body && body.default_evidence?.ok !== true) return false;
40
+ if (hasBlockingProviderRecovery(body, currentSelections)) return false;
41
+ return body.records.every((record) => {
42
+ if (!record || typeof record.id !== 'string' || record.id.trim() === '') return false;
43
+ if (!['present', 'absent'].includes(record.desired_state)) return false;
44
+ if (!record.lifecycle || typeof record.lifecycle !== 'object' || Array.isArray(record.lifecycle)) return false;
45
+ for (const field of ['installed', 'configured', 'enabled', 'catalogued']) {
46
+ if (typeof record.lifecycle[field] !== 'boolean') return false;
47
+ }
48
+ if (record.desired_state === 'absent' && record.lifecycle.enabled === true) return false;
49
+ return true;
50
+ });
51
+ }
52
+
53
+ function matchesCurrentRoute(job, currentSelections, role) {
54
+ if (!currentSelections) return true;
55
+ const selectionKey = role === 'worker'
56
+ && Number(job?.attempt ?? job?.selection_trace?.logical_attempt ?? 0) > 0
57
+ && Object.hasOwn(currentSelections, 'worker_escalation')
58
+ ? 'worker_escalation'
59
+ : role;
60
+ if (!Object.hasOwn(currentSelections, selectionKey)) return true;
61
+ const selected = currentSelections[selectionKey];
62
+ return selected?.ok === true
63
+ && job?.provider === selected.provider
64
+ && job?.model === selected.model;
65
+ }
66
+
67
+ function safeDetailCode(value, fallback) {
68
+ return typeof value === 'string' && /^[A-Z][A-Z0-9_]{0,127}$/u.test(value) ? value : fallback;
69
+ }
70
+
71
+ function currentRouteHealthEvidence({ role, currentSelections, providerHealthChecked, providerHealthBody } = {}) {
72
+ if (!currentSelections || !Object.hasOwn(currentSelections, role)) return null;
73
+ const selected = currentSelections[role];
74
+ if (selected?.ok === false) {
75
+ return {
76
+ status: 'FAIL',
77
+ reason_code: 'PROVIDER_ROUTE_UNCALLABLE',
78
+ evidence_source: 'model-routing',
79
+ detail_code: safeDetailCode(selected.code, 'MODEL_ROUTE_UNAVAILABLE'),
80
+ };
81
+ }
82
+ if (!selected?.provider || !selected?.model || providerHealthChecked !== true) return null;
83
+ if (providerHealthBody?.ok === false) {
84
+ return { status: 'FAIL', reason_code: 'PROVIDER_HEALTH_UNAVAILABLE', evidence_source: 'provider-health' };
85
+ }
86
+ const health = Array.isArray(providerHealthBody?.health) ? providerHealthBody.health : [];
87
+ const observation = health.find((entry) => entry?.provider === selected.provider
88
+ && entry?.model === selected.model
89
+ && entry?.fresh === true);
90
+ if (!observation || observation.state === 'unprobed') return null;
91
+ if (observation.state === 'callable') {
92
+ return { status: 'PASS', reason_code: 'PROVIDER_ROUTE_CALLABLE', evidence_source: 'provider-health' };
93
+ }
94
+ const stateCode = String(observation.state ?? '').toUpperCase().replaceAll('-', '_');
95
+ return {
96
+ status: 'FAIL',
97
+ reason_code: 'PROVIDER_ROUTE_UNCALLABLE',
98
+ evidence_source: 'provider-health',
99
+ detail_code: safeDetailCode(observation.reason_code, safeDetailCode(stateCode, 'PROVIDER_UNCALLABLE')),
100
+ };
101
+ }
102
+
103
+ export function buildHubExecutionRows(hubJobs = [], { currentSelections = null } = {}) {
104
+ const jobs = Array.isArray(hubJobs) ? hubJobs : [];
105
+ const workerPassed = jobs.some((job) => job?.role === 'worker' && matchesCurrentRoute(job, currentSelections, 'worker') && verifiedHubJob(job));
106
+ const workerPrimaryPassed = jobs.some((job) => job?.role === 'worker'
107
+ && matchesCurrentRoute(job, currentSelections, 'worker')
108
+ && verifiedHubJob(job)
109
+ && Number(job?.attempt ?? job?.selection_trace?.logical_attempt ?? 0) === 0);
110
+ const workerEscalationPassed = jobs.some((job) => job?.role === 'worker'
111
+ && matchesCurrentRoute(job, currentSelections, 'worker')
112
+ && verifiedHubJob(job)
113
+ && (Number(job?.attempt ?? job?.selection_trace?.logical_attempt ?? 0) > 0));
114
+ const reviewerPassed = jobs.some((job) => job?.role === 'reviewer'
115
+ && matchesCurrentRoute(job, currentSelections, 'reviewer')
116
+ && verifiedHubJob(job)
117
+ && job?.review_verdict === 'approve');
118
+ return [
119
+ workerPassed
120
+ ? { id: 'model_execution', status: 'PASS', reason_code: 'REAL_EXECUTION_PASSED', evidence_source: 'hub-jobs' }
121
+ : { id: 'model_execution', status: 'NOT_RUN', reason_code: 'NO_EXECUTION_EVIDENCE', evidence_source: 'none' },
122
+ workerPrimaryPassed
123
+ ? { id: 'worker_primary_callable', status: 'PASS', reason_code: 'WORKER_PRIMARY_CALLABLE', evidence_source: 'hub-jobs' }
124
+ : { id: 'worker_primary_callable', status: 'NOT_RUN', reason_code: 'NO_EXECUTION_EVIDENCE', evidence_source: 'none' },
125
+ workerEscalationPassed
126
+ ? { id: 'worker_escalation_callable', status: 'PASS', reason_code: 'WORKER_ESCALATION_CALLABLE', evidence_source: 'hub-jobs' }
127
+ : { id: 'worker_escalation_callable', status: 'NOT_RUN', reason_code: 'NO_EXECUTION_EVIDENCE', evidence_source: 'none' },
128
+ reviewerPassed
129
+ ? { id: 'reviewer_primary_callable', status: 'PASS', reason_code: 'REVIEWER_PRIMARY_CALLABLE', evidence_source: 'hub-jobs' }
130
+ : { id: 'reviewer_primary_callable', status: 'NOT_RUN', reason_code: 'NO_EXECUTION_EVIDENCE', evidence_source: 'none' },
131
+ { id: 'provider_lifecycle_consistent', status: 'NOT_RUN', reason_code: 'NO_EXECUTION_EVIDENCE', evidence_source: 'none' },
132
+ reviewerPassed
133
+ ? { id: 'reviewer_pipeline', status: 'PASS', reason_code: 'REAL_REVIEW_PASSED', evidence_source: 'hub-jobs' }
134
+ : { id: 'reviewer_pipeline', status: 'NOT_RUN', reason_code: 'NO_EXECUTION_EVIDENCE', evidence_source: 'none' },
135
+ ];
136
+ }
69
137
 
70
138
  /**
71
139
  * Enrich the conservative runtime matrix with evidence the config report has
72
140
  * already collected. This function performs no I/O and never reads provider
73
141
  * configuration, credentials, quotas, pricing, or hidden catalog expectations.
74
142
  */
75
- export function buildConfigReadinessMatrix({
76
- platform = process.platform,
77
- hubCompatibility = null,
78
- workerProviderMode = null,
79
- providerCatalogChecked = false,
80
- providerCatalogBody = null,
81
- providerInventoryChecked = false,
82
- providerInventoryBody = null,
83
- providerHealthChecked = false,
84
- providerHealthBody = null,
85
- hubJobsChecked = false,
86
- hubJobsBody = null,
87
- } = {}) {
143
+ export function buildConfigReadinessMatrix({
144
+ platform = process.platform,
145
+ hubCompatibility = null,
146
+ workerProviderMode = null,
147
+ providerCatalogChecked = false,
148
+ providerCatalogBody = null,
149
+ providerInventoryChecked = false,
150
+ providerInventoryBody = null,
151
+ providerHealthChecked = false,
152
+ providerHealthBody = null,
153
+ hubJobsChecked = false,
154
+ hubJobsBody = null,
155
+ currentSelections = null,
156
+ } = {}) {
88
157
  const warnings = warningCodes(providerCatalogBody);
89
158
  const catalogResponseOk = !!providerCatalogBody
90
159
  && typeof providerCatalogBody === 'object'
91
160
  && providerCatalogBody.ok !== false;
92
161
  const catalogOk = providerCatalogChecked && catalogResponseOk && warnings.length === 0;
93
162
 
94
- const evidence = {};
95
- const hubJobs = hubCompatibility?.compatible === true
96
- && hubJobsChecked
97
- && hubJobsBody?.ok !== false
98
- && Array.isArray(hubJobsBody?.jobs)
99
- ? hubJobsBody.jobs
100
- : [];
101
- for (const row of buildHubExecutionRows(hubJobs)) {
102
- if (row.status === 'PASS') {
103
- evidence[row.id] = {
104
- status: row.status,
105
- reason_code: row.reason_code,
106
- evidence_source: row.evidence_source,
107
- };
108
- }
109
- }
110
- if (
163
+ const evidence = {};
164
+ const hubJobs = hubCompatibility?.compatible === true
165
+ && hubJobsChecked
166
+ && hubJobsBody?.ok !== false
167
+ && Array.isArray(hubJobsBody?.jobs)
168
+ ? hubJobsBody.jobs
169
+ : [];
170
+ for (const row of buildHubExecutionRows(hubJobs, { currentSelections })) {
171
+ if (row.status === 'PASS') {
172
+ evidence[row.id] = {
173
+ status: row.status,
174
+ reason_code: row.reason_code,
175
+ evidence_source: row.evidence_source,
176
+ };
177
+ }
178
+ }
179
+ if (
111
180
  workerProviderMode !== 'deepseek-official'
112
181
  && hubCompatibility?.compatible === true
113
182
  && providerCatalogChecked
114
183
  && catalogResponseOk
115
184
  && warnings.length > 0
116
- ) {
185
+ ) {
117
186
  evidence.provider_catalog = {
118
187
  status: 'FAIL',
119
188
  reason_code: READINESS_REASON_CODES.PROVIDER_CATALOG_HEALTH_WARNING,
120
189
  evidence_source: 'harness-catalog',
121
190
  };
122
- }
123
-
124
- if (providerInventoryChecked) {
125
- evidence.provider_lifecycle_consistent = structurallyConsistentProviderInventory(providerInventoryBody)
126
- ? { status: 'PASS', reason_code: READINESS_REASON_CODES.PROVIDER_LIFECYCLE_CONSISTENT, evidence_source: 'provider-inventory' }
127
- : {
128
- status: 'FAIL',
129
- reason_code: providerInventoryBody?.ok === false
130
- ? READINESS_REASON_CODES.PROVIDER_INVENTORY_UNAVAILABLE
131
- : READINESS_REASON_CODES.PROVIDER_LIFECYCLE_INCONSISTENT,
132
- evidence_source: 'provider-inventory',
133
- };
134
- }
135
-
136
- if (providerHealthChecked && providerHealthBody?.ok === false) {
137
- evidence.provider_health = {
138
- status: 'FAIL',
139
- reason_code: 'PROVIDER_HEALTH_UNAVAILABLE',
140
- evidence_source: 'provider-health',
141
- };
142
- }
191
+ }
192
+
193
+ if (providerInventoryChecked) {
194
+ evidence.provider_lifecycle_consistent = structurallyConsistentProviderInventory(providerInventoryBody, currentSelections)
195
+ ? { status: 'PASS', reason_code: READINESS_REASON_CODES.PROVIDER_LIFECYCLE_CONSISTENT, evidence_source: 'provider-inventory' }
196
+ : {
197
+ status: 'FAIL',
198
+ reason_code: providerInventoryBody?.ok === false
199
+ ? READINESS_REASON_CODES.PROVIDER_INVENTORY_UNAVAILABLE
200
+ : READINESS_REASON_CODES.PROVIDER_LIFECYCLE_INCONSISTENT,
201
+ evidence_source: 'provider-inventory',
202
+ };
203
+ }
204
+
205
+ for (const [role, rowId] of [['worker', 'provider_health'], ['reviewer', 'reviewer_health']]) {
206
+ const healthEvidence = currentRouteHealthEvidence({ role, currentSelections, providerHealthChecked, providerHealthBody });
207
+ if (healthEvidence) evidence[rowId] = healthEvidence;
208
+ }
143
209
 
144
210
  const matrix = buildReadinessMatrix({
145
211
  platform,
@@ -2,7 +2,9 @@
2
2
  // describes only DSH Crew and deliberately never advertises itself as a top-
3
3
  // level Executor or control plane.
4
4
 
5
- export const EXTENSION_CONTRACT_SCHEMA_VERSION = 1;
5
+ import { validateModelCallabilityV2 } from './model-callability-contract.mjs';
6
+
7
+ export const EXTENSION_CONTRACT_SCHEMA_VERSION = 1;
6
8
 
7
9
  function row(matrix, id) {
8
10
  return Array.isArray(matrix?.rows) ? matrix.rows.find((entry) => entry?.id === id) : undefined;
@@ -34,40 +36,56 @@ function readinessFromRow(entry, { pass = 'READY', notRun = 'DEGRADED' } = {}) {
34
36
  return component('UNAVAILABLE', entry.reason_code ?? 'CHECK_FAILED');
35
37
  }
36
38
 
37
- export function buildExtensionContract({ config = {}, readinessMatrix = {}, readinessSnapshot = null, workspace = null, profiles = null, runtime = null } = {}) {
38
- const matrix = readinessSnapshot?.readiness_matrix ?? readinessMatrix;
39
+ function modelReadinessFromSnapshot(readinessSnapshot, matrix, runtime, expectedEnabledRoles, now = Date.now()) {
40
+ const callability = readinessSnapshot?.model_callability;
41
+ const providerHealthEvidence = row(matrix, 'provider_health');
42
+ const catalogEvidence = row(matrix, 'provider_catalog');
43
+ if (callability && typeof callability === 'object') {
44
+ const validation = validateModelCallabilityV2({
45
+ projection: callability,
46
+ runtime,
47
+ expectedEnabledRoles,
48
+ expectedSelections: { worker: readinessSnapshot?.worker?.selected ?? null, reviewer: readinessSnapshot?.reviewer?.selected ?? null },
49
+ now,
50
+ });
51
+ if (validation.ok && validation.state === 'CALLABLE') return component('READY', 'CURRENT_MODEL_CALLABLE', { captured_at: callability.captured_at, expires_at: callability.expires_at, runtime_id: callability.current_runtime_id });
52
+ if (validation.ok && validation.state === 'NOT_CALLABLE') return component('UNAVAILABLE', callability.roles.worker?.state === 'NOT_CALLABLE' ? callability.roles.worker.reason_code : callability.roles.reviewer.reason_code ?? 'CURRENT_MODEL_NOT_CALLABLE');
53
+ if (validation.ok && validation.state === 'STALE') return component('DEGRADED', 'MODEL_EVIDENCE_STALE');
54
+ return component('DEGRADED', validation.reason_code ?? 'MODEL_CALLABILITY_UNKNOWN');
55
+ }
56
+ if (providerHealthEvidence?.status === 'FAIL') return readinessFromRow(providerHealthEvidence);
57
+ if (catalogEvidence?.status === 'FAIL') return readinessFromRow(catalogEvidence);
58
+ if (providerHealthEvidence || catalogEvidence) return component('DEGRADED', 'MODEL_CALLABILITY_NOT_PROJECTED');
59
+ return component('UNAVAILABLE', 'MODEL_CALLABILITY_NOT_PROJECTED');
60
+ }
61
+
62
+ export function buildExtensionContract({ config = {}, readinessMatrix = {}, readinessSnapshot = null, workspace = null, profiles = null, runtime = null } = {}) {
63
+ const matrix = readinessSnapshot?.readiness_matrix ?? readinessMatrix;
39
64
  const workerEnabled = config.subagents_enabled !== false && config.worker_state !== 'disabled';
40
65
  const reviewerEnabled = config.subagents_enabled !== false && config.review_state !== 'disabled';
41
- const realModelEvidence = ['worker_primary_callable', 'model_execution', 'worker_escalation_callable', 'deepseek_flash', 'deepseek_pro']
42
- .map((id) => row(matrix, id))
43
- .find((entry) => entry?.status === 'PASS');
44
- const catalogEvidence = row(matrix, 'provider_catalog');
45
- const lifecycleEvidence = row(matrix, 'provider_lifecycle_consistent');
46
- const modelReadiness = catalogEvidence?.status === 'FAIL'
47
- ? readinessFromRow(catalogEvidence)
48
- : realModelEvidence
49
- ? component('READY', realModelEvidence.reason_code ?? 'MODEL_EXECUTION_PASSED')
50
- : catalogEvidence?.status === 'PASS' || catalogEvidence?.status === 'SKIP'
51
- ? component('DEGRADED', 'MODEL_CATALOG_ONLY')
52
- : component('UNAVAILABLE', catalogEvidence?.reason_code ?? 'NO_EVIDENCE');
53
- const components = {
54
- harness: readinessFromRow(row(matrix, 'hub_compatibility')),
55
- provider_lifecycle: lifecycleEvidence
56
- ? readinessFromRow(lifecycleEvidence, { notRun: 'DEGRADED' })
57
- : component('DEGRADED', 'PROVIDER_LIFECYCLE_NOT_CHECKED'),
58
- model: modelReadiness,
66
+ const reviewerHealthEvidence = row(matrix, 'reviewer_health');
67
+ const lifecycleEvidence = row(matrix, 'provider_lifecycle_consistent');
68
+ const modelReadiness = modelReadinessFromSnapshot(readinessSnapshot, matrix, runtime, { worker: workerEnabled, reviewer: reviewerEnabled });
69
+ const components = {
70
+ harness: readinessFromRow(row(matrix, 'hub_compatibility')),
71
+ provider_lifecycle: lifecycleEvidence
72
+ ? readinessFromRow(lifecycleEvidence, { notRun: 'DEGRADED' })
73
+ : component('DEGRADED', 'PROVIDER_LIFECYCLE_NOT_CHECKED'),
74
+ model: modelReadiness,
59
75
  workspace: workspaceComponent(workspace),
60
76
  reviewer: reviewerEnabled
61
- ? readinessFromRow(row(matrix, 'reviewer_pipeline'))
62
- : component('DEGRADED', 'REVIEWER_DISABLED'),
77
+ ? reviewerHealthEvidence?.status === 'FAIL'
78
+ ? readinessFromRow(reviewerHealthEvidence)
79
+ : readinessFromRow(row(matrix, 'reviewer_pipeline'))
80
+ : component('NOT_APPLICABLE', 'REVIEWER_DISABLED'),
63
81
  };
64
- const states = Object.values(components).map((entry) => entry.status);
82
+ const states = Object.entries(components).filter(([key]) => key !== 'reviewer' || reviewerEnabled).map(([, entry]) => entry.status);
65
83
  const readiness = states.includes('UNAVAILABLE') ? 'UNAVAILABLE' : states.includes('DEGRADED') ? 'DEGRADED' : 'READY';
66
84
  return {
67
85
  schema_version: EXTENSION_CONTRACT_SCHEMA_VERSION,
68
86
  kind: 'dsh-crew-extension',
69
- runtime: runtime ?? null,
70
- ...(readinessSnapshot ? { readiness_snapshot: readinessSnapshot } : {}),
87
+ runtime: runtime ?? null,
88
+ ...(readinessSnapshot ? { readiness_snapshot: readinessSnapshot } : {}),
71
89
  capabilities: {
72
90
  'deepseek.worker': workerEnabled,
73
91
  'deepseek.reviewer': reviewerEnabled,
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Crew-profile-only runtime adapter. Fence the public agent creation entry,
3
+ * including creations still awaiting publication in the official agent list.
4
+ * Callers must persist their maintenance marker BEFORE asking idle().
5
+ * No original agent is cancelled or disposed by this adapter.
6
+ */
7
+ const installed = new WeakSet();
8
+ const guarded = Symbol.for('dsh-crew.history.admission');
9
+ function method(object, name) {
10
+ for (let current = object; current; current = Object.getPrototypeOf(current)) {
11
+ const descriptor = Object.getOwnPropertyDescriptor(current, name);
12
+ if (descriptor) return descriptor.value;
13
+ }
14
+ }
15
+
16
+ export function installHistoryAdmissionGate(agents, isMaintenancePending) {
17
+ if (typeof agents?.create !== 'function' || typeof agents?.list !== 'function'
18
+ || typeof isMaintenancePending !== 'function') throw new Error('HISTORY_ADMISSION_UNAVAILABLE');
19
+ if (installed.has(agents)) throw new Error('HISTORY_ADMISSION_ALREADY_INSTALLED');
20
+ const entries = ['create', 'resume'].filter(name => typeof method(agents, name) === 'function')
21
+ .map(name => ({ name, original: method(agents, name), wrapper: null }));
22
+ if (!entries.some(entry => entry.name === 'create')) throw new Error('HISTORY_ADMISSION_UNAVAILABLE');
23
+ if (entries.some(entry => entry.original[guarded])) throw new Error('HISTORY_ADMISSION_ALREADY_INSTALLED');
24
+ let creating = 0;
25
+ for (const entry of entries) {
26
+ entry.wrapper = async function(...args) {
27
+ if (isMaintenancePending()) throw new Error('HISTORY_MAINTENANCE_PENDING');
28
+ creating += 1;
29
+ try { return await entry.original.apply(this, args); }
30
+ finally { creating -= 1; }
31
+ };
32
+ entry.wrapper[guarded] = true;
33
+ agents[entry.name] = entry.wrapper;
34
+ }
35
+ installed.add(agents);
36
+ return {
37
+ idle() {
38
+ // Cordis returns fresh traceable callable proxies; compare descriptors,
39
+ // not the per-access wrapper returned by agents.create/resume.
40
+ if (entries.some(entry => method(agents, entry.name) !== entry.wrapper)) return false;
41
+ try {
42
+ const live = agents.list();
43
+ return Array.isArray(live) && creating === 0 && live.length === 0;
44
+ } catch { return false; }
45
+ },
46
+ dispose() {
47
+ for (const entry of entries) if (method(agents, entry.name) === entry.wrapper) agents[entry.name] = entry.original;
48
+ installed.delete(agents);
49
+ },
50
+ };
51
+ }