@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.
- package/.claude-plugin/marketplace.json +16 -17
- package/.claude-plugin/plugin.json +7 -1
- package/README.md +44 -15
- package/README.zh.md +37 -12
- package/agents/ds-flash.md +16 -18
- package/agents/ds-pro.md +16 -24
- package/agents/ds-reviewer.md +15 -15
- package/agents/ds-worker.md +16 -16
- package/bin/dsh-crew.mjs +16 -12
- package/codex/AGENTS.md +37 -85
- package/codex/agents/ds-flash.toml +18 -14
- package/codex/agents/ds-pro.toml +18 -15
- package/codex/agents/ds-reviewer.toml +17 -13
- package/codex/agents/ds-worker.toml +17 -13
- package/codex/prompts/dsh-config.md +17 -1
- package/codex/prompts/dsh-status.md +5 -1
- package/commands/config.md +16 -4
- package/commands/status.md +6 -2
- package/docs/installation.md +54 -9
- package/docs/readiness-matrix.md +14 -6
- package/docs/ui-surfaces.md +32 -17
- package/lib/client.js +769 -177
- package/official-web-bridge/lib/client.js +297 -209
- package/official-web-bridge/overlay-entry.mjs +59 -0
- package/package.json +6 -3
- package/scripts/build-client.mjs +2 -0
- package/scripts/setup.mjs +8 -7
- package/scripts/verify-crew-ui-polish.mjs +145 -0
- package/scripts/verify-history-ui.mjs +97 -0
- package/scripts/verify-npm-install.mjs +1 -1
- package/src/client/history-panel.tsx +108 -0
- package/src/client/host-readiness.mjs +15 -6
- package/src/client/index.tsx +91 -69
- package/src/client/model-callability-view.mjs +17 -0
- package/src/client/panel-chrome.tsx +40 -0
- package/src/client/quick-panel.tsx +88 -73
- package/src/client/readiness-envelope.mjs +34 -0
- package/src/client/task-telemetry.mjs +11 -4
- package/src/config-readiness.mjs +181 -115
- package/src/extension-contract.mjs +44 -26
- package/src/history/admission-gate.mjs +51 -0
- package/src/history/archive-store.mjs +261 -0
- package/src/history/cleanup-plan.mjs +64 -0
- package/src/history/http.mjs +32 -0
- package/src/history/operation.mjs +86 -0
- package/src/history/runner.mjs +51 -0
- package/src/history/runtime.mjs +28 -0
- package/src/history/service.mjs +137 -0
- package/src/history/state.mjs +27 -0
- package/src/hub/index.mjs +141 -24
- package/src/hub-client.mjs +17 -15
- package/src/image-output.mjs +71 -0
- package/src/install/install-legacy.mjs +126 -23
- package/src/install/npx-lifecycle.mjs +373 -64
- package/src/install/official-frontend-assets.mjs +78 -0
- package/src/install/payload-content.mjs +88 -0
- package/src/install/windows-startup.mjs +107 -19
- package/src/install/windows-supervisor-adapter.mjs +443 -0
- package/src/install/windows-supervisor-lifecycle.mjs +782 -0
- package/src/install/zcode.mjs +53 -14
- package/src/job-contracts.mjs +37 -31
- package/src/jobs.mjs +2 -2
- package/src/mcp-runtime.mjs +74 -9
- package/src/model-callability-contract.mjs +79 -0
- package/src/multimodal.mjs +0 -0
- package/src/official-web-bridge.mjs +0 -2
- package/src/provider-health.mjs +130 -124
- package/src/readiness-matrix.mjs +20 -15
- package/src/runtime-identity-contract.mjs +34 -0
- package/src/runtime-identity.mjs +14 -4
- package/src/runtime-readiness-snapshot.mjs +285 -87
- package/src/server.mjs +86 -76
- package/src/standalone-sdk.mjs +23 -0
- package/src/supervisor/restart-request.mjs +64 -10
- package/src/workflow-runtime.mjs +28 -13
- package/windows/start-dsh-crew.cmd +57 -57
- package/windows/start-dsh-crew.ps1 +327 -51
- package/windows/supervisor-control.ps1 +467 -0
- package/zcode/AGENTS.md +4 -1
- package/zcode/agents/ds-reviewer.md +31 -36
- package/zcode/agents/ds-worker.md +31 -39
- package/zcode/commands/dsh-config.md +17 -6
- package/zcode/commands/dsh-status.md +5 -4
- package/.mcp.json +0 -8
package/src/config-readiness.mjs
CHANGED
|
@@ -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
|
|
25
|
-
if (!body
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
&&
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
|
|
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
|
-
|
|
38
|
-
const
|
|
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
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
?
|
|
62
|
-
|
|
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.
|
|
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
|
+
}
|