priiisk 0.1.1

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.
@@ -0,0 +1,603 @@
1
+ import { createRequire as __priiiskCreateRequire } from "node:module";
2
+ const require = __priiiskCreateRequire(import.meta.url);
3
+ import {
4
+ DoctorCheckStatus,
5
+ detectCampSurface,
6
+ doctorCheck,
7
+ doctorErrorMessage,
8
+ makeDoctorReport,
9
+ resolveCampSurface,
10
+ withCampRpc
11
+ } from "./chunk-UCN75R46.js";
12
+ import {
13
+ PI_RUNTIME_VERSION,
14
+ PiModelCatalogIssueCode,
15
+ inspectPiModelCatalog,
16
+ makePiOperatorResources
17
+ } from "./chunk-YCBBC5MH.js";
18
+ import {
19
+ CampHealthComponentStatus,
20
+ CampHealthOverallStatus,
21
+ CampHostReadiness,
22
+ CampLifecycle,
23
+ CampManifestInvalidError,
24
+ CampManifestVersionError,
25
+ FileSystem_exports,
26
+ PRIIISK_HOST_VERSION,
27
+ PRIIISK_PROTOCOL_PACKAGE_VERSION,
28
+ PRIIISK_PROTOCOL_VERSION,
29
+ SurfacePresence,
30
+ campControllerHealthComponents,
31
+ campHealthLiveness,
32
+ campManifestHostGeneration,
33
+ campProjectPaths,
34
+ campRecoveryDiagnosticFromCause,
35
+ findCampControllerHealthFailure,
36
+ findCampRecoveryHealthComponent,
37
+ listWorkerModelCatalogEntries,
38
+ loadCampHealth,
39
+ loadCampManifest,
40
+ loadWorkerConfig,
41
+ resolveCredentialsPath,
42
+ resolveProjectScope,
43
+ resolveWorkerConfigPath
44
+ } from "./chunk-RJO6Z3SQ.js";
45
+ import {
46
+ Clock_exports,
47
+ Effect_exports,
48
+ Option_exports,
49
+ Ref_exports
50
+ } from "./chunk-KFSFN6L5.js";
51
+
52
+ // packages/cli/src/doctor/environmentDoctor.ts
53
+ import { dirname } from "node:path";
54
+ var minimumNode = { major: 24, minor: 12 };
55
+ var checkProjectScope = (project) => doctorCheck("project.scope", DoctorCheckStatus.pass, "Project scope resolved", {
56
+ cwd: project.cwd,
57
+ name: project.name,
58
+ hash: project.hash
59
+ });
60
+ var checkRuntime = () => {
61
+ const [major = 0, minor = 0] = process.versions.node.split(".").map(Number);
62
+ const supported = major > minimumNode.major || major === minimumNode.major && minor >= minimumNode.minor;
63
+ return doctorCheck(
64
+ "runtime",
65
+ supported ? DoctorCheckStatus.pass : DoctorCheckStatus.failure,
66
+ supported ? "Runtime versions available" : "Node runtime is too old",
67
+ {
68
+ nodeVersion: process.versions.node,
69
+ minimumNodeVersion: `${minimumNode.major}.${minimumNode.minor}`,
70
+ sessionRuntimeVersion: PI_RUNTIME_VERSION
71
+ }
72
+ );
73
+ };
74
+ var checkConfig = (fs) => Effect_exports.all([resolveWorkerConfigPath, loadWorkerConfig(fs)]).pipe(
75
+ Effect_exports.map(
76
+ ([path, config]) => config === void 0 ? doctorCheck("config", DoctorCheckStatus.warning, "User config is missing", { path }) : doctorCheck("config", DoctorCheckStatus.pass, "TOML config is valid", {
77
+ path,
78
+ schemaVersion: config.schemaVersion
79
+ })
80
+ ),
81
+ Effect_exports.catchAll(
82
+ (cause) => resolveWorkerConfigPath.pipe(
83
+ Effect_exports.map(
84
+ (path) => doctorCheck("config", DoctorCheckStatus.failure, "TOML config is invalid", {
85
+ path,
86
+ error: doctorErrorMessage(cause)
87
+ })
88
+ )
89
+ )
90
+ )
91
+ );
92
+ var inspectStorageEntry = (fs, entry) => fs.exists(entry.path).pipe(
93
+ Effect_exports.flatMap(
94
+ (exists) => exists ? fs.stat(entry.path).pipe(
95
+ Effect_exports.map((info) => ({
96
+ ...entry,
97
+ exists: true,
98
+ mode: info.mode & 511,
99
+ kindMatches: (info.mode & 61440) === entry.expectedMode,
100
+ private: (info.mode & 63) === 0
101
+ }))
102
+ ) : Effect_exports.succeed({
103
+ ...entry,
104
+ exists: false,
105
+ mode: void 0,
106
+ kindMatches: true,
107
+ private: true
108
+ })
109
+ )
110
+ );
111
+ var checkStorage = (fs, paths) => Effect_exports.all([resolveWorkerConfigPath, resolveCredentialsPath]).pipe(
112
+ Effect_exports.flatMap(
113
+ ([configPath, credentialsPath]) => Effect_exports.forEach(
114
+ [
115
+ { id: "state", path: paths.stateDir, expectedMode: 16384 },
116
+ { id: "quarantine", path: paths.quarantineDir, expectedMode: 16384 },
117
+ { id: "sessions", path: paths.sessionsDir, expectedMode: 16384 },
118
+ { id: "agent", path: paths.agentDir, expectedMode: 16384 },
119
+ { id: "logs", path: paths.logsDir, expectedMode: 16384 },
120
+ { id: "cache", path: paths.cacheDir, expectedMode: 16384 },
121
+ { id: "runtime", path: paths.runtimeDir, expectedMode: 16384 },
122
+ { id: "socket", path: paths.socketPath, expectedMode: 49152 },
123
+ { id: "lifecycle-lock", path: paths.lifecycleLockPath, expectedMode: 32768 },
124
+ { id: "manifest", path: paths.manifestPath, expectedMode: 32768 },
125
+ { id: "health", path: paths.healthPath, expectedMode: 32768 },
126
+ { id: "config-directory", path: dirname(configPath), expectedMode: 16384 },
127
+ {
128
+ id: "credentials-directory",
129
+ path: dirname(credentialsPath),
130
+ expectedMode: 16384
131
+ },
132
+ { id: "config", path: configPath, expectedMode: 32768 },
133
+ { id: "credentials", path: credentialsPath, expectedMode: 32768 }
134
+ ],
135
+ (entry) => inspectStorageEntry(fs, entry)
136
+ )
137
+ ),
138
+ Effect_exports.map((entries) => {
139
+ const invalid = entries.filter((entry) => !entry.private || !entry.kindMatches);
140
+ return doctorCheck(
141
+ "storage.permissions",
142
+ invalid.length === 0 ? DoctorCheckStatus.pass : DoctorCheckStatus.failure,
143
+ invalid.length === 0 ? "Existing storage paths are private" : "Storage paths have unsafe permissions or unexpected kind",
144
+ {
145
+ entries: entries.map((entry) => ({
146
+ id: entry.id,
147
+ path: entry.path,
148
+ exists: entry.exists,
149
+ kindMatches: entry.kindMatches,
150
+ ...entry.mode === void 0 ? {} : { mode: `0${entry.mode.toString(8)}` }
151
+ }))
152
+ }
153
+ );
154
+ }),
155
+ Effect_exports.catchAll(
156
+ (cause) => Effect_exports.succeed(
157
+ doctorCheck("storage.permissions", DoctorCheckStatus.failure, "Storage check failed", {
158
+ error: doctorErrorMessage(cause)
159
+ })
160
+ )
161
+ )
162
+ );
163
+
164
+ // packages/cli/src/doctor/stateDoctor.ts
165
+ var invalidManifestCheck = (path, cause) => {
166
+ const recovery = campRecoveryDiagnosticFromCause(cause);
167
+ if (cause instanceof CampManifestVersionError) {
168
+ return doctorCheck("manifest", DoctorCheckStatus.failure, recovery.summary, {
169
+ path,
170
+ errorCode: "unsupported_version",
171
+ recoveryCode: recovery.code,
172
+ expectedVersion: cause.expectedVersion,
173
+ receivedVersion: cause.receivedVersion,
174
+ recoveryAction: cause.receivedVersion === 1 ? "camp_up_fresh" : "upgrade_runtime"
175
+ });
176
+ }
177
+ if (cause instanceof CampManifestInvalidError) {
178
+ return doctorCheck("manifest", DoctorCheckStatus.failure, recovery.summary, {
179
+ path,
180
+ errorCode: cause.code,
181
+ recoveryCode: recovery.code,
182
+ error: doctorErrorMessage(cause)
183
+ });
184
+ }
185
+ return doctorCheck("manifest", DoctorCheckStatus.failure, recovery.summary, {
186
+ path,
187
+ errorCode: "state_io",
188
+ recoveryCode: recovery.code,
189
+ error: doctorErrorMessage(cause)
190
+ });
191
+ };
192
+ var checkManifest = (fs, paths, project) => loadCampManifest(fs, paths.manifestPath).pipe(
193
+ Effect_exports.map((manifest) => {
194
+ if (Option_exports.isNone(manifest)) {
195
+ return {
196
+ check: doctorCheck("manifest", DoctorCheckStatus.skipped, "Camp manifest is absent")
197
+ };
198
+ }
199
+ const value = manifest.value;
200
+ if (value.projectHash !== project.hash || value.projectCwd !== project.cwd) {
201
+ return {
202
+ check: doctorCheck(
203
+ "manifest",
204
+ DoctorCheckStatus.failure,
205
+ "Camp manifest belongs to another project scope",
206
+ {
207
+ path: paths.manifestPath,
208
+ manifestProjectHash: value.projectHash,
209
+ expectedProjectHash: project.hash
210
+ }
211
+ )
212
+ };
213
+ }
214
+ const status = value.lifecycle === CampLifecycle.starting ? DoctorCheckStatus.warning : DoctorCheckStatus.pass;
215
+ return {
216
+ check: doctorCheck("manifest", status, `Camp manifest is ${value.lifecycle}`, {
217
+ path: paths.manifestPath,
218
+ generation: campManifestHostGeneration(value) ?? null,
219
+ updatedAt: value.updatedAt
220
+ }),
221
+ manifest: value
222
+ };
223
+ }),
224
+ Effect_exports.catchAll(
225
+ (cause) => Effect_exports.succeed({
226
+ check: invalidManifestCheck(paths.manifestPath, cause)
227
+ })
228
+ )
229
+ );
230
+ var durableHealthFallback = (fs, paths, project, manifest, expectedLive) => Effect_exports.all([loadCampHealth(fs, paths.healthPath), Clock_exports.currentTimeMillis]).pipe(
231
+ Effect_exports.map(
232
+ ([snapshot, now]) => Option_exports.match(snapshot, {
233
+ onNone: () => doctorCheck(
234
+ "health.durable",
235
+ DoctorCheckStatus.skipped,
236
+ "Durable health snapshot is absent"
237
+ ),
238
+ onSome: (value) => {
239
+ const liveness = campHealthLiveness(value, now);
240
+ const matchesProject = value.projectHash === project.hash;
241
+ const manifestGeneration = manifest === void 0 ? void 0 : campManifestHostGeneration(manifest);
242
+ const matchesGeneration = manifestGeneration === void 0 || value.generation === manifestGeneration;
243
+ if (!matchesProject || !matchesGeneration) {
244
+ return doctorCheck(
245
+ "health.durable",
246
+ DoctorCheckStatus.failure,
247
+ "Durable health snapshot does not match camp identity",
248
+ {
249
+ path: paths.healthPath,
250
+ stale: true,
251
+ healthProjectHash: value.projectHash,
252
+ healthGeneration: value.generation
253
+ }
254
+ );
255
+ }
256
+ const recovery = findCampRecoveryHealthComponent(value);
257
+ if (recovery !== void 0) {
258
+ return doctorCheck(
259
+ "health.durable",
260
+ DoctorCheckStatus.failure,
261
+ recovery.message ?? recovery.code ?? "Camp recovery failed",
262
+ {
263
+ path: paths.healthPath,
264
+ stale: true,
265
+ recoveryCode: recovery.code,
266
+ recoverySummary: recovery.message,
267
+ snapshot: value
268
+ }
269
+ );
270
+ }
271
+ const controller = findCampControllerHealthFailure(value);
272
+ if (controller !== void 0) {
273
+ return doctorCheck(
274
+ "health.durable",
275
+ DoctorCheckStatus.failure,
276
+ controller.message ?? controller.code ?? `Controller component ${controller.id} failed`,
277
+ {
278
+ path: paths.healthPath,
279
+ stale: true,
280
+ controllerComponentId: controller.id,
281
+ ...controller.code === void 0 ? {} : { controllerCode: controller.code },
282
+ snapshot: value
283
+ }
284
+ );
285
+ }
286
+ if (expectedLive && liveness.stale) {
287
+ return doctorCheck(
288
+ "health.durable",
289
+ DoctorCheckStatus.failure,
290
+ `Health snapshot stopped updating ${String(Math.round(liveness.ageMs / 1e3))}s ago while the camp is ${manifest?.lifecycle ?? "running"}`,
291
+ {
292
+ path: paths.healthPath,
293
+ stale: true,
294
+ heartbeatAgeMs: liveness.ageMs,
295
+ snapshot: value
296
+ }
297
+ );
298
+ }
299
+ return doctorCheck(
300
+ "health.durable",
301
+ expectedLive ? DoctorCheckStatus.warning : DoctorCheckStatus.skipped,
302
+ `Stale health evidence: ${value.overallStatus}`,
303
+ {
304
+ path: paths.healthPath,
305
+ stale: true,
306
+ heartbeatAgeMs: liveness.ageMs,
307
+ snapshot: value
308
+ }
309
+ );
310
+ }
311
+ })
312
+ ),
313
+ Effect_exports.catchAll(
314
+ (cause) => Effect_exports.succeed(
315
+ doctorCheck(
316
+ "health.durable",
317
+ DoctorCheckStatus.failure,
318
+ "Durable health snapshot is invalid",
319
+ { path: paths.healthPath, error: doctorErrorMessage(cause) }
320
+ )
321
+ )
322
+ )
323
+ );
324
+
325
+ // packages/cli/src/doctor/hostDoctor.ts
326
+ var failureTag = (cause) => {
327
+ if (typeof cause !== "object" || cause === null || !("_tag" in cause)) return void 0;
328
+ return typeof cause._tag === "string" ? cause._tag : void 0;
329
+ };
330
+ var isCompatibilityFailure = (cause) => {
331
+ const tag = failureTag(cause);
332
+ return tag === "ProtocolVersionMismatch" || tag === "ProjectScopeMismatch";
333
+ };
334
+ var controllerCheck = (health) => {
335
+ const components = campControllerHealthComponents(health);
336
+ const failed = components.filter(
337
+ (component) => component.status === CampHealthComponentStatus.failed
338
+ );
339
+ const degraded = components.filter(
340
+ (component) => component.status === CampHealthComponentStatus.degraded
341
+ );
342
+ const worst = failed[0] ?? degraded[0];
343
+ const status = failed.length > 0 ? DoctorCheckStatus.failure : degraded.length > 0 ? DoctorCheckStatus.warning : components.length === 0 ? DoctorCheckStatus.skipped : DoctorCheckStatus.pass;
344
+ return doctorCheck(
345
+ "controller",
346
+ status,
347
+ worst === void 0 ? components.length === 0 ? "Controller components are not reported" : "Controller journal, consumers and receipts are ready" : worst.message ?? worst.code ?? `Controller component ${worst.id} is ${worst.status}`,
348
+ {
349
+ ...worst?.code === void 0 ? {} : { code: worst.code },
350
+ components: components.map((component) => ({
351
+ id: component.id,
352
+ status: component.status,
353
+ ...component.code === void 0 ? {} : { code: component.code },
354
+ ...component.diagnostics === void 0 ? {} : { diagnostics: component.diagnostics }
355
+ }))
356
+ }
357
+ );
358
+ };
359
+ var checkHost = (fs, project, paths, manifest) => Effect_exports.gen(function* () {
360
+ const retryState = yield* Ref_exports.make([]);
361
+ const result = yield* Effect_exports.either(
362
+ withCampRpc(
363
+ ({ client, context }) => Effect_exports.all({
364
+ handshake: client.Handshake(context),
365
+ health: client.Health(context)
366
+ }),
367
+ {
368
+ operation: "doctor.host",
369
+ timeoutMs: 3e3,
370
+ retryTransientErrors: true,
371
+ onRetry: (diagnostic) => Ref_exports.update(retryState, (current) => [...current, diagnostic])
372
+ }
373
+ )
374
+ );
375
+ const retries = yield* Ref_exports.get(retryState);
376
+ if (result._tag === "Left") {
377
+ const compatibilityFailure = isCompatibilityFailure(result.left);
378
+ const expectedLive = compatibilityFailure || manifest?.lifecycle === CampLifecycle.running || manifest?.lifecycle === CampLifecycle.starting;
379
+ const error = doctorErrorMessage(result.left);
380
+ return [
381
+ doctorCheck(
382
+ "host",
383
+ expectedLive ? DoctorCheckStatus.failure : DoctorCheckStatus.skipped,
384
+ expectedLive ? "Camp host is unreachable" : "Camp host is not running",
385
+ { error, retries }
386
+ ),
387
+ doctorCheck(
388
+ "versions",
389
+ compatibilityFailure ? DoctorCheckStatus.failure : DoctorCheckStatus.skipped,
390
+ compatibilityFailure ? "Protocol or project mismatch detected" : "Host version check skipped",
391
+ compatibilityFailure ? { error, failureTag: failureTag(result.left) } : void 0
392
+ ),
393
+ yield* durableHealthFallback(fs, paths, project, manifest, expectedLive)
394
+ ];
395
+ }
396
+ const { handshake, health } = result.right;
397
+ const compatible = handshake.protocolVersion === PRIIISK_PROTOCOL_VERSION && handshake.hostVersion === PRIIISK_HOST_VERSION && handshake.projectHash === project.hash && health.projectHash === project.hash && health.generation === handshake.generation;
398
+ const hostStatus = handshake.readiness === CampHostReadiness.ready && retries.length === 0 ? DoctorCheckStatus.pass : DoctorCheckStatus.warning;
399
+ const healthStatus = health.overallStatus === CampHealthOverallStatus.failed ? DoctorCheckStatus.failure : health.overallStatus === CampHealthOverallStatus.degraded ? DoctorCheckStatus.warning : DoctorCheckStatus.pass;
400
+ const recovery = findCampRecoveryHealthComponent(health);
401
+ return [
402
+ controllerCheck(health),
403
+ doctorCheck(
404
+ "host",
405
+ hostStatus,
406
+ retries.length === 0 ? `Camp host is ${handshake.readiness}` : `Camp host recovered after ${String(retries.length)} retries`,
407
+ { socketPath: paths.socketPath, generation: handshake.generation, retries }
408
+ ),
409
+ doctorCheck(
410
+ "versions",
411
+ compatible ? DoctorCheckStatus.pass : DoctorCheckStatus.failure,
412
+ compatible ? "CLI, host and protocol versions are compatible" : "Version mismatch detected",
413
+ {
414
+ protocolVersion: PRIIISK_PROTOCOL_VERSION,
415
+ protocolPackageVersion: PRIIISK_PROTOCOL_PACKAGE_VERSION,
416
+ hostVersion: PRIIISK_HOST_VERSION,
417
+ remoteProtocolVersion: handshake.protocolVersion,
418
+ remoteHostVersion: handshake.hostVersion
419
+ }
420
+ ),
421
+ doctorCheck(
422
+ "health.live",
423
+ recovery === void 0 ? healthStatus : DoctorCheckStatus.failure,
424
+ recovery?.message ?? `Live health is ${health.overallStatus}`,
425
+ {
426
+ stale: false,
427
+ ...recovery?.code === void 0 ? {} : { recoveryCode: recovery.code },
428
+ ...recovery?.message === void 0 ? {} : { recoverySummary: recovery.message },
429
+ snapshot: health
430
+ }
431
+ )
432
+ ];
433
+ });
434
+
435
+ // packages/cli/src/doctor/piDoctor.ts
436
+ var skippedChecks = (summary, details) => [
437
+ doctorCheck("models.catalog", DoctorCheckStatus.skipped, summary, details),
438
+ doctorCheck("models.auth", DoctorCheckStatus.skipped, summary, details)
439
+ ];
440
+ var checkPiModels = (fs) => Effect_exports.gen(function* () {
441
+ const configResult = yield* Effect_exports.either(loadWorkerConfig(fs));
442
+ if (configResult._tag === "Left") {
443
+ return skippedChecks("Model checks skipped because config is invalid", {
444
+ error: doctorErrorMessage(configResult.left)
445
+ });
446
+ }
447
+ if (configResult.right === void 0) {
448
+ return skippedChecks("Model checks skipped because config is missing");
449
+ }
450
+ const resourcesResult = yield* Effect_exports.either(makePiOperatorResources());
451
+ if (resourcesResult._tag === "Left") {
452
+ return [
453
+ doctorCheck(
454
+ "models.catalog",
455
+ DoctorCheckStatus.failure,
456
+ "Pi model catalog is unavailable",
457
+ { error: doctorErrorMessage(resourcesResult.left) }
458
+ ),
459
+ doctorCheck(
460
+ "models.auth",
461
+ DoctorCheckStatus.skipped,
462
+ "Model auth check skipped because catalog is unavailable"
463
+ )
464
+ ];
465
+ }
466
+ const inspection = inspectPiModelCatalog(
467
+ listWorkerModelCatalogEntries(configResult.right),
468
+ resourcesResult.right.modelRegistry,
469
+ { authDiagnosticCodes: resourcesResult.right.authDiagnosticCodes ?? [] }
470
+ );
471
+ const authIssues = inspection.issues.filter(
472
+ (issue) => issue.code === PiModelCatalogIssueCode.authMissing || issue.code === PiModelCatalogIssueCode.authUnavailable
473
+ );
474
+ const catalogIssues = inspection.issues.filter(
475
+ (issue) => issue.code !== PiModelCatalogIssueCode.authMissing && issue.code !== PiModelCatalogIssueCode.authUnavailable
476
+ );
477
+ const details = {
478
+ declaredCount: inspection.declaredCount,
479
+ providerCount: inspection.providerCount,
480
+ oauthModelCount: inspection.oauthModelCount
481
+ };
482
+ return [
483
+ doctorCheck(
484
+ "models.catalog",
485
+ catalogIssues.length === 0 ? DoctorCheckStatus.pass : DoctorCheckStatus.failure,
486
+ catalogIssues.length === 0 ? "Configured models exist in the Pi catalog" : "Configured model catalog has invalid references",
487
+ { ...details, issues: catalogIssues }
488
+ ),
489
+ doctorCheck(
490
+ "models.auth",
491
+ authIssues.length === 0 ? DoctorCheckStatus.pass : DoctorCheckStatus.failure,
492
+ authIssues.length === 0 ? "Configured model authentication is available" : authIssues.some((issue) => issue.code === PiModelCatalogIssueCode.authUnavailable) ? "Pi authentication storage is unavailable" : "Configured model authentication is missing",
493
+ { issues: authIssues }
494
+ )
495
+ ];
496
+ });
497
+
498
+ // packages/cli/src/doctor/surfaceDoctor.ts
499
+ var inspectRunningSurface = (manifest) => {
500
+ const handle = manifest.surface;
501
+ if (handle === void 0) {
502
+ return Effect_exports.succeed(
503
+ doctorCheck("surface", DoctorCheckStatus.failure, "Running camp has no surface handle")
504
+ );
505
+ }
506
+ return resolveCampSurface(handle.providerAlias).pipe(
507
+ Effect_exports.flatMap(
508
+ (surface) => Effect_exports.all({
509
+ context: surface.detectContext(),
510
+ inspection: surface.inspect(handle)
511
+ })
512
+ ),
513
+ Effect_exports.map(({ context, inspection }) => {
514
+ const present = inspection.presence === SurfacePresence.present;
515
+ const sameContainer = context.containerRef === handle.containerRef;
516
+ return doctorCheck(
517
+ "surface",
518
+ present && sameContainer ? DoctorCheckStatus.pass : DoctorCheckStatus.failure,
519
+ !present ? "Camp surface is missing" : sameContainer ? "Camp surface and current context are available" : "Current surface context belongs to another container",
520
+ {
521
+ providerAlias: handle.providerAlias,
522
+ presence: inspection.presence,
523
+ focused: inspection.focused ?? false,
524
+ sameContainer
525
+ }
526
+ );
527
+ })
528
+ );
529
+ };
530
+ var inspectCurrentSurface = () => detectCampSurface().pipe(
531
+ Effect_exports.flatMap((surface) => surface.detectContext()),
532
+ Effect_exports.map(
533
+ (context) => doctorCheck("surface", DoctorCheckStatus.pass, "Surface context is available", {
534
+ providerAlias: context.providerAlias
535
+ })
536
+ )
537
+ );
538
+ var checkSurface = (manifest) => (manifest !== void 0 && manifest.lifecycle !== CampLifecycle.stopped ? inspectRunningSurface(manifest) : inspectCurrentSurface()).pipe(
539
+ Effect_exports.catchAll(
540
+ (cause) => Effect_exports.succeed(
541
+ doctorCheck("surface", DoctorCheckStatus.failure, "Surface context is unavailable", {
542
+ error: doctorErrorMessage(cause)
543
+ })
544
+ )
545
+ )
546
+ );
547
+
548
+ // packages/cli/src/doctor/doctorService.ts
549
+ var runDoctor = Effect_exports.gen(function* () {
550
+ const fs = yield* FileSystem_exports.FileSystem;
551
+ const runtime = checkRuntime();
552
+ const config = yield* checkConfig(fs);
553
+ const piModels = yield* checkPiModels(fs);
554
+ const projectResult = yield* Effect_exports.either(resolveProjectScope);
555
+ if (projectResult._tag === "Left") {
556
+ const surface2 = yield* checkSurface();
557
+ const checkedAt2 = yield* Clock_exports.currentTimeMillis;
558
+ const skipped = [
559
+ doctorCheck("storage.permissions", DoctorCheckStatus.skipped, "Storage check skipped"),
560
+ doctorCheck("manifest", DoctorCheckStatus.skipped, "Manifest check skipped"),
561
+ doctorCheck("host", DoctorCheckStatus.skipped, "Host check skipped"),
562
+ doctorCheck("versions", DoctorCheckStatus.skipped, "Host version check skipped"),
563
+ doctorCheck("health.durable", DoctorCheckStatus.skipped, "Health check skipped")
564
+ ];
565
+ return makeDoctorReport(
566
+ [
567
+ doctorCheck("project.scope", DoctorCheckStatus.failure, "Project scope is invalid", {
568
+ error: doctorErrorMessage(projectResult.left)
569
+ }),
570
+ runtime,
571
+ config,
572
+ ...piModels,
573
+ surface2,
574
+ ...skipped
575
+ ],
576
+ checkedAt2
577
+ );
578
+ }
579
+ const project = projectResult.right;
580
+ const paths = campProjectPaths(project);
581
+ const storage = yield* checkStorage(fs, paths);
582
+ const manifestResult = yield* checkManifest(fs, paths, project);
583
+ const surface = yield* checkSurface(manifestResult.manifest);
584
+ const host = yield* checkHost(fs, project, paths, manifestResult.manifest);
585
+ const checkedAt = yield* Clock_exports.currentTimeMillis;
586
+ return makeDoctorReport(
587
+ [
588
+ checkProjectScope(project),
589
+ runtime,
590
+ config,
591
+ ...piModels,
592
+ storage,
593
+ manifestResult.check,
594
+ surface,
595
+ ...host
596
+ ],
597
+ checkedAt,
598
+ project.hash
599
+ );
600
+ });
601
+ export {
602
+ runDoctor
603
+ };