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.
- package/README.md +41 -0
- package/dist/chunk-F77DHFYU.js +988 -0
- package/dist/chunk-FZICDHTN.js +603 -0
- package/dist/chunk-KFSFN6L5.js +44744 -0
- package/dist/chunk-PIZUXHCN.js +159 -0
- package/dist/chunk-RJO6Z3SQ.js +14714 -0
- package/dist/chunk-RJO6Z3SQ.js.LEGAL.txt +38 -0
- package/dist/chunk-UCN75R46.js +1185 -0
- package/dist/chunk-YCBBC5MH.js +26660 -0
- package/dist/chunk-YCBBC5MH.js.LEGAL.txt +7 -0
- package/dist/chunk-Z64QXV3O.js +2547 -0
- package/dist/priiisk-host.js +27171 -0
- package/dist/priiisk.js +20661 -0
- package/package.json +33 -0
- package/profiles/_base/instructions.md +37 -0
- package/profiles/assayer/instructions.md +13 -0
- package/profiles/prospector/instructions.md +13 -0
- package/profiles/wright/instructions.md +18 -0
- package/worker-skills/codegraph/SKILL.md +21 -0
|
@@ -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
|
+
};
|