@ran-sh/dsh-crew 1.1.0 → 1.2.0-rc.4
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 +5434 -4844
- package/official-web-bridge/lib/client.js +567 -479
- 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 +86 -64
- 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/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/provider-profile-store.mjs +12 -0
- package/src/provider-settings-store.mjs +347 -5
- 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 -55
- 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
|
@@ -124,6 +124,31 @@ export function maintenanceResultsDir(appRoot) {
|
|
|
124
124
|
return join(supervisorStateRoot(appRoot), 'maintenance-results');
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
export function maintenanceSessionFile(appRoot) {
|
|
128
|
+
return join(supervisorStateRoot(appRoot), 'maintenance-session.json');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function readMaintenanceSession(appRoot) {
|
|
132
|
+
const file = maintenanceSessionFile(appRoot);
|
|
133
|
+
if (!existsSync(file)) return { ok: true, state: 'absent', session: null };
|
|
134
|
+
try {
|
|
135
|
+
const session = JSON.parse(readFileSync(file, 'utf8'));
|
|
136
|
+
const valid = session?.schema_version === 1
|
|
137
|
+
&& session.state === 'STOPPED'
|
|
138
|
+
&& typeof session.lease === 'string'
|
|
139
|
+
&& session.lease.length > 0
|
|
140
|
+
&& typeof session.runtime_id === 'string'
|
|
141
|
+
&& session.runtime_id.length > 0
|
|
142
|
+
&& typeof session.request_id === 'string'
|
|
143
|
+
&& session.request_id.length > 0;
|
|
144
|
+
return valid
|
|
145
|
+
? { ok: true, state: 'present', session }
|
|
146
|
+
: { ok: false, state: 'malformed', code: 'MAINTENANCE_SESSION_MALFORMED', session: null };
|
|
147
|
+
} catch (error) {
|
|
148
|
+
return { ok: false, state: 'malformed', code: 'MAINTENANCE_SESSION_MALFORMED', error: error?.message, session: null };
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
127
152
|
export function readRestartRequest(appRoot, requestId) {
|
|
128
153
|
try {
|
|
129
154
|
const parsed = JSON.parse(readFileSync(join(restartRequestsDir(appRoot), `${requestId}.json`), 'utf8'));
|
|
@@ -170,24 +195,47 @@ export function readRestartResult(appRoot, requestId) {
|
|
|
170
195
|
return null;
|
|
171
196
|
}
|
|
172
197
|
|
|
173
|
-
/**
|
|
174
|
-
|
|
175
|
-
* actively heartbeating (absent, stale beyond tolerance, or malformed).
|
|
176
|
-
*/
|
|
177
|
-
export function readSupervisorHeartbeat(appRoot, { now = Date.now(), staleAfterMs = 15_000 } = {}) {
|
|
198
|
+
/** Observe a fresh heartbeat without granting it restart authority. */
|
|
199
|
+
export function readSupervisorHeartbeatRecord(appRoot, { now = Date.now(), staleAfterMs = 15_000 } = {}) {
|
|
178
200
|
try {
|
|
179
201
|
const parsed = JSON.parse(readFileSync(heartbeatFile(appRoot), 'utf8'));
|
|
180
202
|
if (parsed?.schema_version !== 1 || !Number.isInteger(parsed.pid) || parsed.pid < 1) return null;
|
|
181
|
-
if (typeof parsed.last_seen !== 'number' || now - parsed.last_seen > staleAfterMs) return null;
|
|
182
|
-
|
|
203
|
+
if (typeof parsed.last_seen !== 'number' || now - parsed.last_seen > staleAfterMs || parsed.last_seen - now > 5_000) return null;
|
|
204
|
+
const hasOwnershipField = Object.hasOwn(parsed, 'ownership_ready');
|
|
205
|
+
const identityReady = typeof parsed.process_started_at_utc_ticks === 'string'
|
|
206
|
+
&& /^\d+$/u.test(parsed.process_started_at_utc_ticks)
|
|
207
|
+
&& parsed.process_started_at_utc_ticks !== '0'
|
|
208
|
+
&& typeof parsed.helper_hash === 'string'
|
|
209
|
+
&& /^[a-f0-9]{64}$/u.test(parsed.helper_hash)
|
|
210
|
+
&& typeof parsed.supervisor_instance_id === 'string'
|
|
211
|
+
&& parsed.supervisor_instance_id.trim().length > 0;
|
|
212
|
+
const state = !hasOwnershipField ? 'legacy-v1' : parsed.ownership_ready === true && identityReady ? 'ready' : 'starting';
|
|
213
|
+
return { state, record: { ...parsed, ownership_source: state } };
|
|
183
214
|
} catch { return null; }
|
|
184
215
|
}
|
|
185
216
|
|
|
186
|
-
|
|
217
|
+
/** Return only an ownership-proven supervisor heartbeat. */
|
|
218
|
+
export function readSupervisorHeartbeat(appRoot, options = {}) {
|
|
219
|
+
const observed = readSupervisorHeartbeatRecord(appRoot, options);
|
|
220
|
+
return observed?.state === 'ready' ? observed.record : null;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function writeSupervisorHeartbeat({
|
|
224
|
+
appRoot,
|
|
225
|
+
pid,
|
|
226
|
+
now = Date.now(),
|
|
227
|
+
ownershipReady = true,
|
|
228
|
+
processStartedAtUtcTicks = null,
|
|
229
|
+
helperHash = null,
|
|
230
|
+
supervisorInstanceId = randomUUID(),
|
|
231
|
+
}) {
|
|
187
232
|
const record = {
|
|
188
233
|
schema_version: 1,
|
|
189
|
-
supervisor_instance_id:
|
|
234
|
+
supervisor_instance_id: supervisorInstanceId,
|
|
190
235
|
pid,
|
|
236
|
+
process_started_at_utc_ticks: typeof processStartedAtUtcTicks === 'string' ? processStartedAtUtcTicks : null,
|
|
237
|
+
helper_hash: helperHash,
|
|
238
|
+
ownership_ready: ownershipReady === true,
|
|
191
239
|
last_seen: now,
|
|
192
240
|
protocol_version: 1,
|
|
193
241
|
};
|
|
@@ -195,7 +243,13 @@ export function writeSupervisorHeartbeat({ appRoot, pid, now = Date.now() }) {
|
|
|
195
243
|
// run (the watcher rewrites this file every few seconds).
|
|
196
244
|
try {
|
|
197
245
|
const prev = JSON.parse(readFileSync(heartbeatFile(appRoot), 'utf8'));
|
|
198
|
-
|
|
246
|
+
const sameWatcher = prev?.schema_version === 1
|
|
247
|
+
&& prev.pid === record.pid
|
|
248
|
+
&& prev.process_started_at_utc_ticks === record.process_started_at_utc_ticks
|
|
249
|
+
&& prev.helper_hash === record.helper_hash
|
|
250
|
+
&& typeof prev.supervisor_instance_id === 'string'
|
|
251
|
+
&& prev.supervisor_instance_id.length > 0;
|
|
252
|
+
if (sameWatcher) record.supervisor_instance_id = prev.supervisor_instance_id;
|
|
199
253
|
} catch { /* first beat */ }
|
|
200
254
|
writeFileAtomic(heartbeatFile(appRoot), JSON.stringify(record, null, 2) + '\n');
|
|
201
255
|
return record;
|
package/src/workflow-runtime.mjs
CHANGED
|
@@ -299,8 +299,8 @@ export function createWorkflowRuntime(adapters, {
|
|
|
299
299
|
let config = {};
|
|
300
300
|
|
|
301
301
|
try {
|
|
302
|
-
config = adapters.getConfig?.() ?? {};
|
|
303
|
-
job.review_gate = ['required', 'optional', 'off'].includes(config?.review?.gate) ? config.review.gate : 'required';
|
|
302
|
+
config = adapters.getConfig?.() ?? {};
|
|
303
|
+
job.review_gate = ['required', 'optional', 'off'].includes(config?.review?.gate) ? config.review.gate : 'required';
|
|
304
304
|
const alloc = await adapters.allocateWorkspace?.(job);
|
|
305
305
|
if (alloc && alloc.ok === false) {
|
|
306
306
|
failJob(job, Object.assign(new Error(alloc.error ?? alloc.reason), { code: alloc.reason }));
|
|
@@ -322,7 +322,11 @@ export function createWorkflowRuntime(adapters, {
|
|
|
322
322
|
if (isReviewJob) {
|
|
323
323
|
transition(job, JOB_PHASES.REVIEWING, 'explicit reviewer');
|
|
324
324
|
const before = alloc?.ok && alloc.isolation === 'worktree' ? await safeCapture(adapters, job.execution_cwd, job.base_revision) : null;
|
|
325
|
-
|
|
325
|
+
// Explicit reviewers inspect the caller's stated task/workspace
|
|
326
|
+
// directly. The bounded worker-candidate capsule belongs only to the
|
|
327
|
+
// automatic post-worker review path; constructing it with no worker
|
|
328
|
+
// view falsely tells an explicit reviewer that nothing was delivered.
|
|
329
|
+
const reviewTask = job.original_task;
|
|
326
330
|
const review = await runReviewerAttempt(job, reviewTask, config, before);
|
|
327
331
|
if (job.cancelling) { await cancelWorkflow(job); return; }
|
|
328
332
|
job.review = review;
|
|
@@ -476,7 +480,7 @@ export function createWorkflowRuntime(adapters, {
|
|
|
476
480
|
const reviewApproved = review.status === 'done'
|
|
477
481
|
&& review.delivery_complete === true
|
|
478
482
|
&& review.verdict === 'approve';
|
|
479
|
-
if (!reviewApproved && job.review_gate === 'required') {
|
|
483
|
+
if (!reviewApproved && job.review_gate === 'required') {
|
|
480
484
|
const code = review.verdict === 'request_changes'
|
|
481
485
|
? 'REVIEW_CHANGES_REQUESTED'
|
|
482
486
|
: 'REVIEW_INCONCLUSIVE';
|
|
@@ -512,6 +516,16 @@ export function createWorkflowRuntime(adapters, {
|
|
|
512
516
|
}
|
|
513
517
|
|
|
514
518
|
async function runReviewerAttempt(job, task, config, beforeCandidate, cwd = job.execution_cwd, baseRevision = job.base_revision) {
|
|
519
|
+
const requireFingerprint = (candidate) => {
|
|
520
|
+
if (job.isolation !== 'worktree') return;
|
|
521
|
+
if (candidate?.ok === true && typeof candidate.fingerprint === 'string' && candidate.fingerprint.trim()) return;
|
|
522
|
+
job.candidate_capture_failed = true;
|
|
523
|
+
job.retain_workspace = true;
|
|
524
|
+
throw Object.assign(new Error('review workspace evidence unavailable; worktree retained'), {
|
|
525
|
+
code: 'REVIEW_EVIDENCE_UNAVAILABLE',
|
|
526
|
+
});
|
|
527
|
+
};
|
|
528
|
+
requireFingerprint(beforeCandidate);
|
|
515
529
|
const policy = resolveModelPolicy(config, 'reviewer', { attempt: 0 });
|
|
516
530
|
const attemptId = attemptIdFor(adapters, job.id, 'review');
|
|
517
531
|
job.current_attempt_id = attemptId;
|
|
@@ -544,6 +558,7 @@ export function createWorkflowRuntime(adapters, {
|
|
|
544
558
|
}, 0);
|
|
545
559
|
if (ar.status === 'failed' && attemptView.error_code) job.error_code = attemptView.error_code;
|
|
546
560
|
const afterCandidate = job.isolation === 'worktree' ? await safeCapture(adapters, cwd, baseRevision) : null;
|
|
561
|
+
requireFingerprint(afterCandidate);
|
|
547
562
|
const review = normalizeReview({ attemptResult: ar, beforeCandidate, afterCandidate });
|
|
548
563
|
recordCanonical(job, 'review.completed', {
|
|
549
564
|
attempt_id: attemptView.id,
|
|
@@ -568,9 +583,9 @@ export function createWorkflowRuntime(adapters, {
|
|
|
568
583
|
id: ar.id,
|
|
569
584
|
role: ar.role ?? 'worker',
|
|
570
585
|
attempt,
|
|
571
|
-
provider: ar.provider ?? null,
|
|
572
|
-
model: ar.model ?? null,
|
|
573
|
-
execution_context: ar.execution_context ?? null,
|
|
586
|
+
provider: ar.provider ?? null,
|
|
587
|
+
model: ar.model ?? null,
|
|
588
|
+
execution_context: ar.execution_context ?? null,
|
|
574
589
|
selection_source: ar.selection_source ?? null,
|
|
575
590
|
selection_trace: ar.selection_trace ?? null,
|
|
576
591
|
status: ar.status ?? 'failed',
|
|
@@ -628,8 +643,8 @@ export function createWorkflowRuntime(adapters, {
|
|
|
628
643
|
phase: job.phase,
|
|
629
644
|
status: job.status,
|
|
630
645
|
attempt: job.attempts.length,
|
|
631
|
-
current_model: job.attempts[job.attempts.length - 1]?.model ?? null,
|
|
632
|
-
execution_context: job.attempts[job.attempts.length - 1]?.execution_context ?? null,
|
|
646
|
+
current_model: job.attempts[job.attempts.length - 1]?.model ?? null,
|
|
647
|
+
execution_context: job.attempts[job.attempts.length - 1]?.execution_context ?? null,
|
|
633
648
|
model_class_hint: job.model_class_hint,
|
|
634
649
|
source: job.source,
|
|
635
650
|
profile_id: job.profile_id,
|
|
@@ -654,14 +669,14 @@ export function createWorkflowRuntime(adapters, {
|
|
|
654
669
|
workspace_retained: job.workspace_retained === true,
|
|
655
670
|
decision: job.decision,
|
|
656
671
|
candidate_available: !!job.candidate,
|
|
657
|
-
review_status: job.review ? job.review.status ?? null : null,
|
|
658
|
-
review_gate: job.review_gate ?? 'required',
|
|
672
|
+
review_status: job.review ? job.review.status ?? null : null,
|
|
673
|
+
review_gate: job.review_gate ?? 'required',
|
|
659
674
|
event_cursor: job.canonical_events.at(-1)?.sequence ?? 0,
|
|
660
675
|
};
|
|
661
676
|
if (withResult) {
|
|
662
677
|
v.child_attempts = job.attempts.map((a) => ({
|
|
663
|
-
id: a.id, role: a.role, attempt: a.attempt, provider: a.provider, model: a.model,
|
|
664
|
-
execution_context: a.execution_context ?? null,
|
|
678
|
+
id: a.id, role: a.role, attempt: a.attempt, provider: a.provider, model: a.model,
|
|
679
|
+
execution_context: a.execution_context ?? null,
|
|
665
680
|
selection_source: a.selection_source, selection_trace: a.selection_trace ?? null,
|
|
666
681
|
status: a.status, stopReason: a.stopReason,
|
|
667
682
|
outcome_task: a.outcome?.task_status ?? null,
|
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
@echo off
|
|
2
|
-
setlocal EnableExtensions
|
|
3
|
-
title DSH Crew Launcher
|
|
4
|
-
|
|
5
|
-
set "LAUNCH_REQUEST=%*"
|
|
6
|
-
set "LAUNCH_MODE=open"
|
|
7
|
-
set "LAUNCH_DIR=%~dp0"
|
|
8
|
-
|
|
9
|
-
if "%~1"=="" goto :run
|
|
10
|
-
if /i "%~1"=="--background" (
|
|
11
|
-
set "LAUNCH_MODE=background"
|
|
12
|
-
shift
|
|
13
|
-
goto :validate
|
|
14
|
-
)
|
|
15
|
-
if /i "%~1"=="--open" (
|
|
16
|
-
set "LAUNCH_MODE=open"
|
|
17
|
-
shift
|
|
18
|
-
goto :validate
|
|
19
|
-
)
|
|
20
|
-
if /i "%~1"=="--watch" (
|
|
21
|
-
set "LAUNCH_MODE=watch"
|
|
22
|
-
shift
|
|
23
|
-
goto :validate
|
|
24
|
-
)
|
|
25
|
-
if /i "%~1"=="--help" goto :help
|
|
26
|
-
goto :invalid_argument
|
|
27
|
-
|
|
28
|
-
:validate
|
|
29
|
-
if not "%~1"=="" goto :invalid_argument
|
|
30
|
-
|
|
31
|
-
:run
|
|
32
|
-
set "LAUNCH_HELPER=%LAUNCH_DIR%start-dsh-crew.ps1"
|
|
33
|
-
set "LAUNCH_LOG=%TEMP%\dsh-crew-launcher.log"
|
|
34
|
-
if not exist "%LAUNCH_HELPER%" (
|
|
35
|
-
>>"%LAUNCH_LOG%" echo [%date% %time%] ERROR Managed launcher helper is missing: %LAUNCH_HELPER%
|
|
36
|
-
echo ERROR: DSH Crew launcher helper is missing.
|
|
37
|
-
echo Repair it with: dsh-crew update
|
|
38
|
-
if /i "%LAUNCH_MODE%"=="open" pause
|
|
39
|
-
exit /b 1
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "%LAUNCH_HELPER%" -Mode "%LAUNCH_MODE%"
|
|
43
|
-
set "LAUNCH_EXIT=%ERRORLEVEL%"
|
|
44
|
-
if not "%LAUNCH_EXIT%"=="0" if /i "%LAUNCH_MODE%"=="open" pause
|
|
45
|
-
exit /b %LAUNCH_EXIT%
|
|
46
|
-
|
|
47
|
-
:invalid_argument
|
|
48
|
-
echo ERROR: Unsupported launcher arguments: %LAUNCH_REQUEST%
|
|
49
|
-
echo Use --open, --background, or --watch.
|
|
50
|
-
exit /b 64
|
|
51
|
-
|
|
52
|
-
:help
|
|
53
|
-
echo Usage: %~nx0 [--open ^| --background ^| --watch]
|
|
54
|
-
echo --open
|
|
55
|
-
echo --background Start the
|
|
56
|
-
echo --watch Keep the
|
|
57
|
-
exit /b 0
|
|
1
|
+
@echo off
|
|
2
|
+
setlocal EnableExtensions
|
|
3
|
+
title DSH Crew Launcher
|
|
4
|
+
|
|
5
|
+
set "LAUNCH_REQUEST=%*"
|
|
6
|
+
set "LAUNCH_MODE=open"
|
|
7
|
+
set "LAUNCH_DIR=%~dp0"
|
|
8
|
+
|
|
9
|
+
if "%~1"=="" goto :run
|
|
10
|
+
if /i "%~1"=="--background" (
|
|
11
|
+
set "LAUNCH_MODE=background"
|
|
12
|
+
shift
|
|
13
|
+
goto :validate
|
|
14
|
+
)
|
|
15
|
+
if /i "%~1"=="--open" (
|
|
16
|
+
set "LAUNCH_MODE=open"
|
|
17
|
+
shift
|
|
18
|
+
goto :validate
|
|
19
|
+
)
|
|
20
|
+
if /i "%~1"=="--watch" (
|
|
21
|
+
set "LAUNCH_MODE=watch"
|
|
22
|
+
shift
|
|
23
|
+
goto :validate
|
|
24
|
+
)
|
|
25
|
+
if /i "%~1"=="--help" goto :help
|
|
26
|
+
goto :invalid_argument
|
|
27
|
+
|
|
28
|
+
:validate
|
|
29
|
+
if not "%~1"=="" goto :invalid_argument
|
|
30
|
+
|
|
31
|
+
:run
|
|
32
|
+
set "LAUNCH_HELPER=%LAUNCH_DIR%start-dsh-crew.ps1"
|
|
33
|
+
set "LAUNCH_LOG=%TEMP%\dsh-crew-launcher.log"
|
|
34
|
+
if not exist "%LAUNCH_HELPER%" (
|
|
35
|
+
>>"%LAUNCH_LOG%" echo [%date% %time%] ERROR Managed launcher helper is missing: %LAUNCH_HELPER%
|
|
36
|
+
echo ERROR: DSH Crew launcher helper is missing.
|
|
37
|
+
echo Repair it with: dsh-crew update
|
|
38
|
+
if /i "%LAUNCH_MODE%"=="open" pause
|
|
39
|
+
exit /b 1
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "%LAUNCH_HELPER%" -Mode "%LAUNCH_MODE%"
|
|
43
|
+
set "LAUNCH_EXIT=%ERRORLEVEL%"
|
|
44
|
+
if not "%LAUNCH_EXIT%"=="0" if /i "%LAUNCH_MODE%"=="open" pause
|
|
45
|
+
exit /b %LAUNCH_EXIT%
|
|
46
|
+
|
|
47
|
+
:invalid_argument
|
|
48
|
+
echo ERROR: Unsupported launcher arguments: %LAUNCH_REQUEST%
|
|
49
|
+
echo Use --open, --background, or --watch.
|
|
50
|
+
exit /b 64
|
|
51
|
+
|
|
52
|
+
:help
|
|
53
|
+
echo Usage: %~nx0 [--open ^| --background ^| --watch]
|
|
54
|
+
echo --open Open official Harness on 3080, then start Crew silently on 3210.
|
|
55
|
+
echo --background Start the Crew-owned 3210 service silently.
|
|
56
|
+
echo --watch Keep the Crew-owned 3210 service healthy.
|
|
57
|
+
exit /b 0
|