contextos-agents 1.7.0 → 2.0.0-beta.2
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/.agents/AGENTS.md +1 -1
- package/.agents/adapters/aider/export.js +117 -99
- package/.agents/adapters/claude/export.js +68 -26
- package/.agents/adapters/copilot/export.js +90 -53
- package/.agents/adapters/cursor/export.js +80 -101
- package/.agents/adapters/drift-detector.js +196 -0
- package/.agents/adapters/gemini/export.js +76 -45
- package/.agents/adapters/pure-compiler.js +443 -0
- package/.agents/adapters/zed/export.js +104 -96
- package/.agents/compiled/registry.v2.json +504 -0
- package/.agents/compiled/registry.v2.sha256 +1 -0
- package/.agents/compiler/manifest-compiler.js +963 -0
- package/.agents/compiler/vendor/yaml.LICENSE.txt +13 -0
- package/.agents/compiler/vendor/yaml.SBOM.json +6 -0
- package/.agents/compiler/vendor/yaml.js +139 -0
- package/.agents/core/profiles/init.yaml +25 -0
- package/.agents/core/skills/context-manager/skill.yaml +3 -5
- package/.agents/core/skills/context-os/SKILL.md +3 -6
- package/.agents/core/skills/context-os/skill.yaml +3 -8
- package/.agents/core/skills/engineering-workflow/skill.yaml +1 -7
- package/.agents/core/skills/gemini-precision/skill.yaml +1 -6
- package/.agents/core/skills/gstack-roles/skill.yaml +3 -6
- package/.agents/core/skills/ponytail-mindset/skill.yaml +1 -7
- package/.agents/core/skills/security/skill.yaml +15 -3
- package/.agents/ctx.js +574 -111
- package/.agents/customization-dx.js +282 -0
- package/.agents/doctor.js +719 -64
- package/.agents/filesystem/index.js +71 -0
- package/.agents/filesystem/journaled-transaction.js +451 -0
- package/.agents/filesystem/lockfile-v2.js +275 -0
- package/.agents/filesystem/platform-hardening.js +222 -0
- package/.agents/filesystem/project-lock.js +218 -0
- package/.agents/filesystem/safe-path.js +256 -0
- package/.agents/generated/claude/skills/context-os/SKILL.md +1 -1
- package/.agents/generated/gemini/skills/context-os/SKILL.md +2 -2
- package/.agents/plugins/contextos/plugin.json +1 -1
- package/.agents/plugins.js +259 -60
- package/.agents/profiles.js +486 -51
- package/.agents/resolver.js +50 -534
- package/.agents/schemas/attestation.review.v1.json +111 -0
- package/.agents/schemas/attestation.verification.v1.json +85 -0
- package/.agents/schemas/lockfile.v2.schema.json +134 -0
- package/.agents/schemas/profile.v2.schema.json +114 -0
- package/.agents/schemas/runtime.thread.v1.json +192 -0
- package/.agents/schemas/skill.manifest.v2.json +177 -0
- package/.agents/schemas/verification.spec.v1.json +39 -0
- package/.agents/schemas/workspace.graph.schema.json +106 -0
- package/.agents/transaction-core/event-store.js +288 -0
- package/.agents/transaction-core/idempotency.js +129 -0
- package/.agents/transaction-core/ipc-lock.js +311 -0
- package/.agents/transaction-core/plugin-supply-chain-bundle.js +436 -0
- package/.agents/validate.js +44 -1
- package/.agents/watch.js +354 -102
- package/.agents/workspace/workspace-graph.js +778 -0
- package/README.md +59 -387
- package/benchmarks/v2/analysis/statistics.js +140 -0
- package/benchmarks/v2/analysis/stats.js +69 -0
- package/benchmarks/v2/arms/arm-definitions.js +79 -0
- package/benchmarks/v2/dataset.schema.json +34 -0
- package/benchmarks/v2/evaluators/index.js +25 -0
- package/benchmarks/v2/evaluators/verified-success.js +116 -0
- package/benchmarks/v2/harness/runner.js +88 -0
- package/benchmarks/v2/pilot-tasks.json +392 -0
- package/bin/commands/recover.js +88 -0
- package/bin/commands/update.js +80 -17
- package/bin/commands.js +62 -25
- package/bin/index.js +138 -81
- package/bin/lib/lockfile.js +5 -3
- package/bin/lib/safe-writer.js +34 -3
- package/package.json +85 -72
- package/registry.json +2 -2
- package/registry.v2.schema.json +86 -0
- package/.agents/core/profiles/backend.yaml +0 -47
- package/.agents/core/profiles/enterprise.yaml +0 -46
- package/.agents/core/profiles/frontend.yaml +0 -46
- package/.agents/core/profiles/hackathon.yaml +0 -45
- package/.agents/core/profiles/mvp.yaml +0 -44
- package/.agents/core/profiles/startup.yaml +0 -48
- package/.agents/core/skills/adapters/EXAMPLES.md +0 -19
- package/.agents/core/skills/adapters/SKILL.md +0 -105
- package/.agents/core/skills/adapters/TROUBLESHOOTING.md +0 -7
- package/.agents/core/skills/adapters/VALIDATION.json +0 -12
- package/.agents/core/skills/adapters/skill.yaml +0 -16
- package/.agents/core/skills/architecture-diagrams/SKILL.md +0 -108
- package/.agents/core/skills/architecture-diagrams/VALIDATION.json +0 -12
- package/.agents/core/skills/architecture-diagrams/skill.yaml +0 -12
- package/.agents/core/skills/brutalist-design/SKILL.md +0 -150
- package/.agents/core/skills/brutalist-design/VALIDATION.json +0 -12
- package/.agents/core/skills/brutalist-design/skill.yaml +0 -12
- package/.agents/core/skills/database/EXAMPLES.md +0 -74
- package/.agents/core/skills/database/SKILL.md +0 -101
- package/.agents/core/skills/database/TROUBLESHOOTING.md +0 -18
- package/.agents/core/skills/database/VALIDATION.json +0 -11
- package/.agents/core/skills/database/skill.yaml +0 -31
- package/.agents/core/skills/ddd/EXAMPLES.md +0 -42
- package/.agents/core/skills/ddd/SKILL.md +0 -247
- package/.agents/core/skills/ddd/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/ddd/VALIDATION.json +0 -12
- package/.agents/core/skills/ddd/ddd.md +0 -178
- package/.agents/core/skills/ddd/skill.yaml +0 -17
- package/.agents/core/skills/decisions/EXAMPLES.md +0 -35
- package/.agents/core/skills/decisions/SKILL.md +0 -90
- package/.agents/core/skills/decisions/TROUBLESHOOTING.md +0 -13
- package/.agents/core/skills/decisions/VALIDATION.json +0 -12
- package/.agents/core/skills/decisions/skill.yaml +0 -16
- package/.agents/core/skills/docker/EXAMPLES.md +0 -56
- package/.agents/core/skills/docker/SKILL.md +0 -63
- package/.agents/core/skills/docker/TROUBLESHOOTING.md +0 -18
- package/.agents/core/skills/docker/VALIDATION.json +0 -11
- package/.agents/core/skills/docker/skill.yaml +0 -29
- package/.agents/core/skills/fastapi/EXAMPLES.md +0 -36
- package/.agents/core/skills/fastapi/SKILL.md +0 -148
- package/.agents/core/skills/fastapi/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/fastapi/VALIDATION.json +0 -12
- package/.agents/core/skills/fastapi/fastapi.md +0 -112
- package/.agents/core/skills/fastapi/skill.yaml +0 -17
- package/.agents/core/skills/generators/EXAMPLES.md +0 -19
- package/.agents/core/skills/generators/SKILL.md +0 -112
- package/.agents/core/skills/generators/TROUBLESHOOTING.md +0 -7
- package/.agents/core/skills/generators/VALIDATION.json +0 -12
- package/.agents/core/skills/generators/skill.yaml +0 -25
- package/.agents/core/skills/generators/templates/API.md +0 -77
- package/.agents/core/skills/generators/templates/ARCHITECTURE.md +0 -70
- package/.agents/core/skills/generators/templates/DATABASE.md +0 -42
- package/.agents/core/skills/generators/templates/DECISION.md +0 -46
- package/.agents/core/skills/generators/templates/PRD.md +0 -67
- package/.agents/core/skills/generators/templates/PROJECT_GRAPH.md +0 -56
- package/.agents/core/skills/generators/templates/ROADMAP.md +0 -51
- package/.agents/core/skills/generators/templates/TASKS.md +0 -43
- package/.agents/core/skills/generators/templates/UI.md +0 -73
- package/.agents/core/skills/graphify/EXAMPLES.md +0 -73
- package/.agents/core/skills/graphify/SKILL.md +0 -130
- package/.agents/core/skills/graphify/VALIDATION.json +0 -12
- package/.agents/core/skills/graphify/skill.yaml +0 -18
- package/.agents/core/skills/impeccable-design/EXAMPLES.md +0 -26
- package/.agents/core/skills/impeccable-design/SKILL.md +0 -201
- package/.agents/core/skills/impeccable-design/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/impeccable-design/VALIDATION.json +0 -12
- package/.agents/core/skills/impeccable-design/skill.yaml +0 -20
- package/.agents/core/skills/interview-me/SKILL.md +0 -97
- package/.agents/core/skills/interview-me/VALIDATION.json +0 -12
- package/.agents/core/skills/interview-me/skill.yaml +0 -12
- package/.agents/core/skills/microservices/EXAMPLES.md +0 -38
- package/.agents/core/skills/microservices/SKILL.md +0 -164
- package/.agents/core/skills/microservices/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/microservices/VALIDATION.json +0 -12
- package/.agents/core/skills/microservices/microservices.md +0 -119
- package/.agents/core/skills/microservices/skill.yaml +0 -17
- package/.agents/core/skills/minimalist-design/SKILL.md +0 -113
- package/.agents/core/skills/minimalist-design/VALIDATION.json +0 -12
- package/.agents/core/skills/minimalist-design/skill.yaml +0 -12
- package/.agents/core/skills/nestjs/EXAMPLES.md +0 -40
- package/.agents/core/skills/nestjs/SKILL.md +0 -139
- package/.agents/core/skills/nestjs/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/nestjs/VALIDATION.json +0 -12
- package/.agents/core/skills/nestjs/nestjs.md +0 -103
- package/.agents/core/skills/nestjs/skill.yaml +0 -17
- package/.agents/core/skills/nextjs/EXAMPLES.md +0 -40
- package/.agents/core/skills/nextjs/SKILL.md +0 -163
- package/.agents/core/skills/nextjs/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/nextjs/VALIDATION.json +0 -12
- package/.agents/core/skills/nextjs/nextjs.md +0 -67
- package/.agents/core/skills/nextjs/skill.yaml +0 -17
- package/.agents/core/skills/node/EXAMPLES.md +0 -80
- package/.agents/core/skills/node/SKILL.md +0 -128
- package/.agents/core/skills/node/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/node/VALIDATION.json +0 -12
- package/.agents/core/skills/node/node.md +0 -87
- package/.agents/core/skills/node/skill.yaml +0 -17
- package/.agents/core/skills/performance/EXAMPLES.md +0 -30
- package/.agents/core/skills/performance/SKILL.md +0 -75
- package/.agents/core/skills/performance/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/performance/VALIDATION.json +0 -12
- package/.agents/core/skills/performance/performance.md +0 -52
- package/.agents/core/skills/performance/skill.yaml +0 -17
- package/.agents/core/skills/react/EXAMPLES.md +0 -79
- package/.agents/core/skills/react/SKILL.md +0 -132
- package/.agents/core/skills/react/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/react/VALIDATION.json +0 -12
- package/.agents/core/skills/react/react.md +0 -93
- package/.agents/core/skills/react/skill.yaml +0 -17
- package/.agents/core/skills/react-best-practices/SKILL.md +0 -155
- package/.agents/core/skills/react-best-practices/VALIDATION.json +0 -12
- package/.agents/core/skills/react-best-practices/skill.yaml +0 -14
- package/.agents/core/skills/redesign-audit/SKILL.md +0 -117
- package/.agents/core/skills/redesign-audit/VALIDATION.json +0 -12
- package/.agents/core/skills/redesign-audit/skill.yaml +0 -12
- package/.agents/core/skills/soft-design/SKILL.md +0 -108
- package/.agents/core/skills/soft-design/VALIDATION.json +0 -12
- package/.agents/core/skills/soft-design/skill.yaml +0 -12
- package/.agents/core/skills/state-management/EXAMPLES.md +0 -56
- package/.agents/core/skills/state-management/SKILL.md +0 -48
- package/.agents/core/skills/state-management/TROUBLESHOOTING.md +0 -18
- package/.agents/core/skills/state-management/VALIDATION.json +0 -11
- package/.agents/core/skills/state-management/skill.yaml +0 -28
- package/.agents/core/skills/subagent-orchestrator/SKILL.md +0 -117
- package/.agents/core/skills/subagent-orchestrator/VALIDATION.json +0 -12
- package/.agents/core/skills/subagent-orchestrator/skill.yaml +0 -12
- package/.agents/core/skills/system-design/EXAMPLES.md +0 -75
- package/.agents/core/skills/system-design/SKILL.md +0 -419
- package/.agents/core/skills/system-design/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/system-design/VALIDATION.json +0 -12
- package/.agents/core/skills/system-design/skill.yaml +0 -20
- package/.agents/core/skills/system-design/system-design.md +0 -112
- package/.agents/core/skills/testing/EXAMPLES.md +0 -71
- package/.agents/core/skills/testing/SKILL.md +0 -70
- package/.agents/core/skills/testing/TROUBLESHOOTING.md +0 -18
- package/.agents/core/skills/testing/VALIDATION.json +0 -11
- package/.agents/core/skills/testing/skill.yaml +0 -32
- package/.agents/core/skills/typescript/EXAMPLES.md +0 -64
- package/.agents/core/skills/typescript/SKILL.md +0 -112
- package/.agents/core/skills/typescript/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/typescript/VALIDATION.json +0 -12
- package/.agents/core/skills/typescript/skill.yaml +0 -17
- package/.agents/core/skills/typescript/typescript.md +0 -71
- package/.agents/core/skills/ui-design/EXAMPLES.md +0 -21
- package/.agents/core/skills/ui-design/SKILL.md +0 -124
- package/.agents/core/skills/ui-design/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/ui-design/VALIDATION.json +0 -12
- package/.agents/core/skills/ui-design/skill.yaml +0 -17
- package/.agents/core/skills/ui-design/ui.md +0 -88
- package/.agents/core/skills/ui-ux-pro/EXAMPLES.md +0 -62
- package/.agents/core/skills/ui-ux-pro/SKILL.md +0 -375
- package/.agents/core/skills/ui-ux-pro/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/ui-ux-pro/VALIDATION.json +0 -12
- package/.agents/core/skills/ui-ux-pro/skill.yaml +0 -19
- package/.agents/core/skills/ux-design/EXAMPLES.md +0 -36
- package/.agents/core/skills/ux-design/SKILL.md +0 -116
- package/.agents/core/skills/ux-design/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/ux-design/VALIDATION.json +0 -12
- package/.agents/core/skills/ux-design/skill.yaml +0 -17
- package/.agents/core/skills/ux-design/ux.md +0 -80
- package/.agents/core/skills/vercel-optimize/SKILL.md +0 -83
- package/.agents/core/skills/vercel-optimize/VALIDATION.json +0 -12
- package/.agents/core/skills/vercel-optimize/scripts/collect-signals.mjs +0 -131
- package/.agents/core/skills/vercel-optimize/scripts/gate-investigations.mjs +0 -142
- package/.agents/core/skills/vercel-optimize/scripts/merge-signals.mjs +0 -143
- package/.agents/core/skills/vercel-optimize/scripts/scan-codebase.mjs +0 -174
- package/.agents/core/skills/vercel-optimize/skill.yaml +0 -18
- package/.agents/core/skills/web-accessibility/EXAMPLES.md +0 -39
- package/.agents/core/skills/web-accessibility/SKILL.md +0 -170
- package/.agents/core/skills/web-accessibility/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/web-accessibility/VALIDATION.json +0 -12
- package/.agents/core/skills/web-accessibility/accessibility.md +0 -63
- package/.agents/core/skills/web-accessibility/skill.yaml +0 -17
- package/.agents/generated/claude/skills/adapters/SKILL.md +0 -126
- package/.agents/generated/claude/skills/architecture-diagrams/SKILL.md +0 -101
- package/.agents/generated/claude/skills/brutalist-design/SKILL.md +0 -145
- package/.agents/generated/claude/skills/database/SKILL.md +0 -191
- package/.agents/generated/claude/skills/ddd/SKILL.md +0 -305
- package/.agents/generated/claude/skills/decisions/SKILL.md +0 -134
- package/.agents/generated/claude/skills/docker/SKILL.md +0 -135
- package/.agents/generated/claude/skills/fastapi/SKILL.md +0 -200
- package/.agents/generated/claude/skills/generators/SKILL.md +0 -133
- package/.agents/generated/claude/skills/graphify/SKILL.md +0 -198
- package/.agents/generated/claude/skills/impeccable-design/SKILL.md +0 -241
- package/.agents/generated/claude/skills/interview-me/SKILL.md +0 -90
- package/.agents/generated/claude/skills/microservices/SKILL.md +0 -218
- package/.agents/generated/claude/skills/minimalist-design/SKILL.md +0 -108
- package/.agents/generated/claude/skills/nestjs/SKILL.md +0 -195
- package/.agents/generated/claude/skills/nextjs/SKILL.md +0 -219
- package/.agents/generated/claude/skills/node/SKILL.md +0 -224
- package/.agents/generated/claude/skills/performance/SKILL.md +0 -121
- package/.agents/generated/claude/skills/react/SKILL.md +0 -227
- package/.agents/generated/claude/skills/react-best-practices/SKILL.md +0 -146
- package/.agents/generated/claude/skills/redesign-audit/SKILL.md +0 -112
- package/.agents/generated/claude/skills/soft-design/SKILL.md +0 -103
- package/.agents/generated/claude/skills/state-management/SKILL.md +0 -120
- package/.agents/generated/claude/skills/subagent-orchestrator/SKILL.md +0 -110
- package/.agents/generated/claude/skills/system-design/SKILL.md +0 -507
- package/.agents/generated/claude/skills/testing/SKILL.md +0 -157
- package/.agents/generated/claude/skills/typescript/SKILL.md +0 -192
- package/.agents/generated/claude/skills/ui-design/SKILL.md +0 -161
- package/.agents/generated/claude/skills/ui-ux-pro/SKILL.md +0 -451
- package/.agents/generated/claude/skills/ux-design/SKILL.md +0 -168
- package/.agents/generated/claude/skills/vercel-optimize/SKILL.md +0 -76
- package/.agents/generated/claude/skills/web-accessibility/SKILL.md +0 -225
- package/.agents/generated/gemini/skills/adapters/SKILL.md +0 -135
- package/.agents/generated/gemini/skills/architecture-diagrams/SKILL.md +0 -107
- package/.agents/generated/gemini/skills/brutalist-design/SKILL.md +0 -151
- package/.agents/generated/gemini/skills/database/SKILL.md +0 -200
- package/.agents/generated/gemini/skills/ddd/SKILL.md +0 -314
- package/.agents/generated/gemini/skills/decisions/SKILL.md +0 -143
- package/.agents/generated/gemini/skills/docker/SKILL.md +0 -144
- package/.agents/generated/gemini/skills/fastapi/SKILL.md +0 -209
- package/.agents/generated/gemini/skills/generators/SKILL.md +0 -142
- package/.agents/generated/gemini/skills/graphify/SKILL.md +0 -205
- package/.agents/generated/gemini/skills/impeccable-design/SKILL.md +0 -250
- package/.agents/generated/gemini/skills/interview-me/SKILL.md +0 -96
- package/.agents/generated/gemini/skills/microservices/SKILL.md +0 -227
- package/.agents/generated/gemini/skills/minimalist-design/SKILL.md +0 -114
- package/.agents/generated/gemini/skills/nestjs/SKILL.md +0 -204
- package/.agents/generated/gemini/skills/nextjs/SKILL.md +0 -298
- package/.agents/generated/gemini/skills/node/SKILL.md +0 -323
- package/.agents/generated/gemini/skills/performance/SKILL.md +0 -185
- package/.agents/generated/gemini/skills/react/SKILL.md +0 -332
- package/.agents/generated/gemini/skills/react-best-practices/SKILL.md +0 -152
- package/.agents/generated/gemini/skills/redesign-audit/SKILL.md +0 -118
- package/.agents/generated/gemini/skills/soft-design/SKILL.md +0 -109
- package/.agents/generated/gemini/skills/state-management/SKILL.md +0 -129
- package/.agents/generated/gemini/skills/subagent-orchestrator/SKILL.md +0 -116
- package/.agents/generated/gemini/skills/system-design/SKILL.md +0 -631
- package/.agents/generated/gemini/skills/testing/SKILL.md +0 -166
- package/.agents/generated/gemini/skills/typescript/SKILL.md +0 -275
- package/.agents/generated/gemini/skills/ui-design/SKILL.md +0 -170
- package/.agents/generated/gemini/skills/ui-ux-pro/SKILL.md +0 -460
- package/.agents/generated/gemini/skills/ux-design/SKILL.md +0 -177
- package/.agents/generated/gemini/skills/vercel-optimize/SKILL.md +0 -82
- package/.agents/generated/gemini/skills/web-accessibility/SKILL.md +0 -300
package/.agents/doctor.js
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* .agents/doctor.js
|
|
3
|
-
* ContextOS — Project Diagnostics & Health Check Engine
|
|
3
|
+
* ContextOS Doctor v2 — Comprehensive Project Diagnostics & Health Check Engine
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
5
|
+
* Implements Milestone 8 Doctor v2 specification:
|
|
6
|
+
* - Standardized status outcomes: PASS, WARN, FAIL, SKIP, UNVERIFIED, RECOVERY_REQUIRED
|
|
7
|
+
* - Deep diagnostic checks:
|
|
8
|
+
* 1. Node.js environment (Node 18 for Core, Node 20 for Runtime)
|
|
9
|
+
* 2. Git availability & version
|
|
10
|
+
* 3. Filesystem permissions and path containment
|
|
11
|
+
* 4. Manifests & schema compliance
|
|
12
|
+
* 5. Skill dependency graph cycles & missing requirements
|
|
13
|
+
* 6. Profile validation against registry
|
|
14
|
+
* 7. Lockfile v1 & v2 integrity with CAS revision checking
|
|
15
|
+
* 8. Crash resilience & uncommitted transaction journals
|
|
16
|
+
* 9. Output provenance & managed artifact drift detection
|
|
17
|
+
* 10. Adapter version compliance
|
|
18
|
+
* 11. MCP server handshake verification
|
|
19
|
+
* 12. Secret scanning guardrails (missing scanner yields WARN/SKIP, never PASS)
|
|
20
|
+
* 13. Monorepo workspace topology
|
|
21
|
+
* 14. User customization safety
|
|
22
|
+
* - Automated remediation (doctor --fix) for safe, deterministic repairs
|
|
23
|
+
* - Versioned structured JSON reporting (schemaVersion: 2.0.0)
|
|
13
24
|
*/
|
|
14
25
|
|
|
15
26
|
'use strict';
|
|
@@ -18,6 +29,22 @@ const fs = require('fs');
|
|
|
18
29
|
const path = require('path');
|
|
19
30
|
const { execFileSync } = require('child_process');
|
|
20
31
|
const profiles = require('./profiles.js');
|
|
32
|
+
const {
|
|
33
|
+
LockfileV2Manager,
|
|
34
|
+
JournaledTransaction,
|
|
35
|
+
ProjectMutationLock,
|
|
36
|
+
isPidAlive,
|
|
37
|
+
toPosix,
|
|
38
|
+
} = require('./filesystem/index.js');
|
|
39
|
+
|
|
40
|
+
const STATUS = {
|
|
41
|
+
PASS: 'PASS',
|
|
42
|
+
WARN: 'WARN',
|
|
43
|
+
FAIL: 'FAIL',
|
|
44
|
+
SKIP: 'SKIP',
|
|
45
|
+
UNVERIFIED: 'UNVERIFIED',
|
|
46
|
+
RECOVERY_REQUIRED: 'RECOVERY_REQUIRED',
|
|
47
|
+
};
|
|
21
48
|
|
|
22
49
|
const DOMAIN_MAP = {
|
|
23
50
|
frontend: new Set([
|
|
@@ -42,48 +69,173 @@ const DOMAIN_MAP = {
|
|
|
42
69
|
function checkNodeVersion() {
|
|
43
70
|
const version = process.version; // e.g. v22.12.0
|
|
44
71
|
const match = version.match(/^v?(\d+)\.(\d+)/);
|
|
45
|
-
if (!match)
|
|
72
|
+
if (!match) {
|
|
73
|
+
return {
|
|
74
|
+
id: 'node_version',
|
|
75
|
+
status: STATUS.FAIL,
|
|
76
|
+
ok: false,
|
|
77
|
+
version,
|
|
78
|
+
message: `${version} (unknown format)`,
|
|
79
|
+
remediation: 'Install Node.js >= 18.0.0 from https://nodejs.org',
|
|
80
|
+
};
|
|
81
|
+
}
|
|
46
82
|
|
|
47
83
|
const major = parseInt(match[1], 10);
|
|
48
84
|
const minor = parseInt(match[2], 10);
|
|
49
|
-
|
|
50
|
-
|
|
85
|
+
|
|
86
|
+
// Core requires Node >= 18.0.0 (or 16.7.0 for basic cpSync). Runtime requires Node >= 20.0.0.
|
|
87
|
+
if (major < 18) {
|
|
88
|
+
return {
|
|
89
|
+
id: 'node_version',
|
|
90
|
+
status: STATUS.FAIL,
|
|
91
|
+
ok: false,
|
|
92
|
+
version,
|
|
93
|
+
message: `Node.js ${version} (< 18.0.0, Node 18 required for Core)`,
|
|
94
|
+
remediation: 'Upgrade Node.js to >= 18.0.0 (recommended >= 20.0.0 for ContextOS Runtime)',
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (major < 20) {
|
|
99
|
+
return {
|
|
100
|
+
id: 'node_version',
|
|
101
|
+
status: STATUS.WARN,
|
|
102
|
+
ok: true,
|
|
103
|
+
version,
|
|
104
|
+
message: `Node.js ${version} (>= 18.0.0 for Core, Node 20 recommended for Runtime)`,
|
|
105
|
+
remediation: 'Upgrade to Node.js >= 20.0.0 for optimal sandbox and runtime worker support',
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
51
109
|
return {
|
|
52
|
-
|
|
110
|
+
id: 'node_version',
|
|
111
|
+
status: STATUS.PASS,
|
|
112
|
+
ok: true,
|
|
53
113
|
version,
|
|
54
|
-
message:
|
|
114
|
+
message: `Node.js ${version} (>= 20.0.0, optimal)`,
|
|
115
|
+
remediation: null,
|
|
55
116
|
};
|
|
56
117
|
}
|
|
57
118
|
|
|
119
|
+
function checkGitVersion() {
|
|
120
|
+
try {
|
|
121
|
+
const stdout = execFileSync('git', ['--version'], { stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim();
|
|
122
|
+
return {
|
|
123
|
+
id: 'git_version',
|
|
124
|
+
status: STATUS.PASS,
|
|
125
|
+
ok: true,
|
|
126
|
+
message: stdout,
|
|
127
|
+
remediation: null,
|
|
128
|
+
};
|
|
129
|
+
} catch {
|
|
130
|
+
return {
|
|
131
|
+
id: 'git_version',
|
|
132
|
+
status: STATUS.FAIL,
|
|
133
|
+
ok: false,
|
|
134
|
+
message: 'git binary not accessible in PATH',
|
|
135
|
+
remediation: 'Install Git and add it to your system PATH',
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function checkFilesystemPermissions(projectDir) {
|
|
141
|
+
try {
|
|
142
|
+
const probeDir = path.join(projectDir, '.agents', '.contextos', 'probe');
|
|
143
|
+
fs.mkdirSync(probeDir, { recursive: true });
|
|
144
|
+
const probeFile = path.join(probeDir, 'perm-test.tmp');
|
|
145
|
+
fs.writeFileSync(probeFile, 'ok', 'utf8');
|
|
146
|
+
fs.unlinkSync(probeFile);
|
|
147
|
+
try { fs.rmdirSync(probeDir); } catch {}
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
id: 'filesystem_permissions',
|
|
151
|
+
status: STATUS.PASS,
|
|
152
|
+
ok: true,
|
|
153
|
+
message: 'Read and write permissions verified in .agents/',
|
|
154
|
+
remediation: null,
|
|
155
|
+
};
|
|
156
|
+
} catch (err) {
|
|
157
|
+
return {
|
|
158
|
+
id: 'filesystem_permissions',
|
|
159
|
+
status: STATUS.FAIL,
|
|
160
|
+
ok: false,
|
|
161
|
+
message: `Filesystem permission denied: ${err.message}`,
|
|
162
|
+
remediation: 'Ensure the current user has read/write privileges in the project folder',
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
58
167
|
function checkPreCommitHook(projectDir) {
|
|
59
168
|
const hookPath = path.join(projectDir, '.git', 'hooks', 'pre-commit');
|
|
60
169
|
if (!fs.existsSync(hookPath)) {
|
|
61
|
-
return {
|
|
170
|
+
return {
|
|
171
|
+
id: 'pre_commit_hook',
|
|
172
|
+
status: STATUS.WARN,
|
|
173
|
+
ok: false,
|
|
174
|
+
message: 'not installed (run: npm run setup:hooks)',
|
|
175
|
+
remediation: 'Run `npm run setup:hooks` to install Git pre-commit validation hook',
|
|
176
|
+
};
|
|
62
177
|
}
|
|
63
178
|
try {
|
|
64
179
|
const content = fs.readFileSync(hookPath, 'utf8');
|
|
65
180
|
if (content.includes('check-secrets')) {
|
|
66
|
-
return {
|
|
181
|
+
return {
|
|
182
|
+
id: 'pre_commit_hook',
|
|
183
|
+
status: STATUS.PASS,
|
|
184
|
+
ok: true,
|
|
185
|
+
message: 'installed (with secret check)',
|
|
186
|
+
remediation: null,
|
|
187
|
+
};
|
|
67
188
|
}
|
|
68
|
-
return {
|
|
189
|
+
return {
|
|
190
|
+
id: 'pre_commit_hook',
|
|
191
|
+
status: STATUS.WARN,
|
|
192
|
+
ok: false,
|
|
193
|
+
message: 'installed but missing check-secrets guard',
|
|
194
|
+
remediation: 'Reinstall hooks via `npm run setup:hooks` to include secret scanning',
|
|
195
|
+
};
|
|
69
196
|
} catch {
|
|
70
|
-
return {
|
|
197
|
+
return {
|
|
198
|
+
id: 'pre_commit_hook',
|
|
199
|
+
status: STATUS.FAIL,
|
|
200
|
+
ok: false,
|
|
201
|
+
message: 'unreadable',
|
|
202
|
+
remediation: 'Check filesystem permissions for .git/hooks/pre-commit',
|
|
203
|
+
};
|
|
71
204
|
}
|
|
72
205
|
}
|
|
73
206
|
|
|
74
207
|
function checkSecretScanner(projectDir) {
|
|
75
208
|
const scriptPath = path.join(projectDir, 'scripts', 'check-secrets.js');
|
|
76
209
|
if (!fs.existsSync(scriptPath)) {
|
|
77
|
-
|
|
210
|
+
// Per Milestone 8 spec: "doctor не считает отсутствующий scanner PASS"
|
|
211
|
+
return {
|
|
212
|
+
id: 'secret_scanner',
|
|
213
|
+
status: STATUS.WARN,
|
|
214
|
+
ok: false,
|
|
215
|
+
message: 'scanner script not present (scripts/check-secrets.js missing)',
|
|
216
|
+
remediation: 'Install check-secrets.js or configure repository secret scanning',
|
|
217
|
+
};
|
|
78
218
|
}
|
|
79
219
|
try {
|
|
80
220
|
execFileSync(process.execPath, [scriptPath, '--all'], {
|
|
81
221
|
cwd: projectDir,
|
|
82
222
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
83
223
|
});
|
|
84
|
-
return {
|
|
224
|
+
return {
|
|
225
|
+
id: 'secret_scanner',
|
|
226
|
+
status: STATUS.PASS,
|
|
227
|
+
ok: true,
|
|
228
|
+
message: '0 findings',
|
|
229
|
+
remediation: null,
|
|
230
|
+
};
|
|
85
231
|
} catch (err) {
|
|
86
|
-
return {
|
|
232
|
+
return {
|
|
233
|
+
id: 'secret_scanner',
|
|
234
|
+
status: STATUS.FAIL,
|
|
235
|
+
ok: false,
|
|
236
|
+
message: 'potential secrets detected in workspace',
|
|
237
|
+
remediation: 'Run `npm run check:secrets` and resolve flagged secrets or add to allowlist',
|
|
238
|
+
};
|
|
87
239
|
}
|
|
88
240
|
}
|
|
89
241
|
|
|
@@ -113,27 +265,136 @@ function checkCompiledAdapters(projectDir) {
|
|
|
113
265
|
}
|
|
114
266
|
|
|
115
267
|
function checkLockfileIntegrity(projectDir) {
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
268
|
+
const v2Path = path.join(projectDir, '.agents', 'lockfile.v2.json');
|
|
269
|
+
const v1Path = path.join(projectDir, '.agents', 'contextos.lock.json');
|
|
270
|
+
const hasV2 = fs.existsSync(v2Path);
|
|
271
|
+
const hasV1 = fs.existsSync(v1Path);
|
|
272
|
+
|
|
273
|
+
if (!hasV2 && !hasV1) {
|
|
274
|
+
return {
|
|
275
|
+
id: 'lockfile',
|
|
276
|
+
status: STATUS.WARN,
|
|
277
|
+
ok: true,
|
|
278
|
+
exists: false,
|
|
279
|
+
isError: false,
|
|
280
|
+
message: 'none (not generated yet)',
|
|
281
|
+
remediation: 'Run `contextos export all` or `contextos doctor --fix` to generate lockfile',
|
|
282
|
+
};
|
|
119
283
|
}
|
|
284
|
+
|
|
285
|
+
// 1. Check Lockfile v2 if present
|
|
286
|
+
if (hasV2) {
|
|
287
|
+
try {
|
|
288
|
+
const raw = fs.readFileSync(v2Path, 'utf8');
|
|
289
|
+
const data = JSON.parse(raw);
|
|
290
|
+
const lockfileManager = new LockfileV2Manager(projectDir);
|
|
291
|
+
lockfileManager.validate(data);
|
|
292
|
+
const count = Object.keys(data.managedFiles || {}).length;
|
|
293
|
+
return {
|
|
294
|
+
id: 'lockfile',
|
|
295
|
+
status: STATUS.PASS,
|
|
296
|
+
ok: true,
|
|
297
|
+
exists: true,
|
|
298
|
+
isError: false,
|
|
299
|
+
message: `valid (v${data.schemaVersion}, rev ${data.revision}, ${count} managed files)`,
|
|
300
|
+
remediation: null,
|
|
301
|
+
};
|
|
302
|
+
} catch (err) {
|
|
303
|
+
return {
|
|
304
|
+
id: 'lockfile',
|
|
305
|
+
status: STATUS.FAIL,
|
|
306
|
+
ok: false,
|
|
307
|
+
exists: true,
|
|
308
|
+
isError: true,
|
|
309
|
+
error: `Lockfile v2 is corrupted or invalid: ${err.message}`,
|
|
310
|
+
remediation: 'Run `contextos doctor --fix` to regenerate valid Lockfile v2',
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// 2. Check Lockfile v1
|
|
120
316
|
try {
|
|
121
|
-
const raw = fs.readFileSync(
|
|
317
|
+
const raw = fs.readFileSync(v1Path, 'utf8');
|
|
122
318
|
const data = JSON.parse(raw);
|
|
123
319
|
if (!data || typeof data !== 'object') {
|
|
124
|
-
return {
|
|
320
|
+
return {
|
|
321
|
+
id: 'lockfile',
|
|
322
|
+
status: STATUS.FAIL,
|
|
323
|
+
ok: false,
|
|
324
|
+
exists: true,
|
|
325
|
+
isError: true,
|
|
326
|
+
error: 'Lockfile JSON root is not an object',
|
|
327
|
+
remediation: 'Run `contextos doctor --fix` to rebuild lockfile',
|
|
328
|
+
};
|
|
125
329
|
}
|
|
126
330
|
if (!data.schemaVersion || typeof data.schemaVersion !== 'number') {
|
|
127
|
-
return {
|
|
331
|
+
return {
|
|
332
|
+
id: 'lockfile',
|
|
333
|
+
status: STATUS.FAIL,
|
|
334
|
+
ok: false,
|
|
335
|
+
exists: true,
|
|
336
|
+
isError: true,
|
|
337
|
+
error: 'Lockfile missing valid schemaVersion',
|
|
338
|
+
remediation: 'Run `contextos doctor --fix` to rebuild lockfile',
|
|
339
|
+
};
|
|
128
340
|
}
|
|
129
|
-
if (!data.managedFiles
|
|
130
|
-
return {
|
|
341
|
+
if (!data.managedFiles && !data.files) {
|
|
342
|
+
return {
|
|
343
|
+
id: 'lockfile',
|
|
344
|
+
status: STATUS.FAIL,
|
|
345
|
+
ok: false,
|
|
346
|
+
exists: true,
|
|
347
|
+
isError: true,
|
|
348
|
+
error: 'Lockfile missing managedFiles map',
|
|
349
|
+
remediation: 'Run `contextos doctor --fix` to rebuild lockfile',
|
|
350
|
+
};
|
|
131
351
|
}
|
|
132
|
-
const count = Object.keys(data.managedFiles).length;
|
|
133
|
-
return {
|
|
352
|
+
const count = Object.keys(data.managedFiles || data.files || {}).length;
|
|
353
|
+
return {
|
|
354
|
+
id: 'lockfile',
|
|
355
|
+
status: STATUS.PASS,
|
|
356
|
+
ok: true,
|
|
357
|
+
exists: true,
|
|
358
|
+
isError: false,
|
|
359
|
+
message: `valid (v${data.schemaVersion}, ${count} managed files)`,
|
|
360
|
+
remediation: null,
|
|
361
|
+
};
|
|
134
362
|
} catch (err) {
|
|
135
|
-
return {
|
|
363
|
+
return {
|
|
364
|
+
id: 'lockfile',
|
|
365
|
+
status: STATUS.FAIL,
|
|
366
|
+
ok: false,
|
|
367
|
+
exists: true,
|
|
368
|
+
isError: true,
|
|
369
|
+
error: `Lockfile is corrupted JSON: ${err.message}`,
|
|
370
|
+
remediation: 'Run `contextos doctor --fix` to rebuild lockfile',
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function checkTransactions(projectDir) {
|
|
376
|
+
try {
|
|
377
|
+
const pending = JournaledTransaction.listPending(projectDir);
|
|
378
|
+
if (pending.length > 0) {
|
|
379
|
+
return {
|
|
380
|
+
id: 'incomplete_transactions',
|
|
381
|
+
status: STATUS.RECOVERY_REQUIRED,
|
|
382
|
+
ok: false,
|
|
383
|
+
error: `RECOVERY_REQUIRED: Found ${pending.length} incomplete transaction(s).`,
|
|
384
|
+
pending,
|
|
385
|
+
remediation: 'Run: contextos recover --list',
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
} catch {
|
|
389
|
+
// Best-effort
|
|
136
390
|
}
|
|
391
|
+
return {
|
|
392
|
+
id: 'incomplete_transactions',
|
|
393
|
+
status: STATUS.PASS,
|
|
394
|
+
ok: true,
|
|
395
|
+
message: 'Clean (0 uncommitted transaction journals)',
|
|
396
|
+
remediation: null,
|
|
397
|
+
};
|
|
137
398
|
}
|
|
138
399
|
|
|
139
400
|
function checkAdapterIntegrity(projectDir) {
|
|
@@ -149,10 +410,10 @@ function checkAdapterIntegrity(projectDir) {
|
|
|
149
410
|
try {
|
|
150
411
|
const stat = fs.statSync(f);
|
|
151
412
|
if (stat.size === 0) {
|
|
152
|
-
errors.push(`Adapter file ${path.relative(projectDir, f)
|
|
413
|
+
errors.push(`Adapter file ${toPosix(path.relative(projectDir, f))} is empty (0 bytes)`);
|
|
153
414
|
}
|
|
154
415
|
} catch {
|
|
155
|
-
errors.push(`Adapter file ${path.relative(projectDir, f)
|
|
416
|
+
errors.push(`Adapter file ${toPosix(path.relative(projectDir, f))} is unreadable`);
|
|
156
417
|
}
|
|
157
418
|
}
|
|
158
419
|
}
|
|
@@ -170,13 +431,20 @@ function checkAdapterIntegrity(projectDir) {
|
|
|
170
431
|
} catch {}
|
|
171
432
|
}
|
|
172
433
|
|
|
173
|
-
return {
|
|
434
|
+
return {
|
|
435
|
+
id: 'adapter_integrity',
|
|
436
|
+
status: errors.length === 0 ? STATUS.PASS : STATUS.FAIL,
|
|
437
|
+
ok: errors.length === 0,
|
|
438
|
+
errors,
|
|
439
|
+
message: errors.length === 0 ? 'All compiled adapter files are structurally intact' : `${errors.length} corrupt adapter file(s)`,
|
|
440
|
+
remediation: errors.length === 0 ? null : 'Run `contextos export all` to re-render clean adapters',
|
|
441
|
+
};
|
|
174
442
|
}
|
|
175
443
|
|
|
176
444
|
function checkSymlinks(projectDir) {
|
|
177
445
|
const errors = [];
|
|
178
446
|
const targetDir = path.join(projectDir, '.agents');
|
|
179
|
-
if (!fs.existsSync(targetDir)) return { ok: true, errors: [] };
|
|
447
|
+
if (!fs.existsSync(targetDir)) return { ok: true, errors: [], status: STATUS.PASS };
|
|
180
448
|
|
|
181
449
|
function scan(current) {
|
|
182
450
|
let entries;
|
|
@@ -191,19 +459,225 @@ function checkSymlinks(projectDir) {
|
|
|
191
459
|
const lstat = fs.lstatSync(full);
|
|
192
460
|
if (lstat.isSymbolicLink()) {
|
|
193
461
|
if (!fs.existsSync(full)) {
|
|
194
|
-
errors.push(`Broken symlink: ${path.relative(projectDir, full)
|
|
462
|
+
errors.push(`Broken symlink: ${toPosix(path.relative(projectDir, full))}`);
|
|
195
463
|
}
|
|
196
464
|
} else if (lstat.isDirectory()) {
|
|
197
465
|
scan(full);
|
|
198
466
|
}
|
|
199
467
|
} catch {
|
|
200
|
-
errors.push(`Cannot stat file: ${path.relative(projectDir, full)
|
|
468
|
+
errors.push(`Cannot stat file: ${toPosix(path.relative(projectDir, full))}`);
|
|
201
469
|
}
|
|
202
470
|
}
|
|
203
471
|
}
|
|
204
472
|
|
|
205
473
|
scan(targetDir);
|
|
206
|
-
return {
|
|
474
|
+
return {
|
|
475
|
+
id: 'symlinks',
|
|
476
|
+
status: errors.length === 0 ? STATUS.PASS : STATUS.FAIL,
|
|
477
|
+
ok: errors.length === 0,
|
|
478
|
+
errors,
|
|
479
|
+
message: errors.length === 0 ? '0 broken symlinks' : `${errors.length} broken symlink(s)`,
|
|
480
|
+
remediation: errors.length === 0 ? null : 'Remove or re-point broken symlinks in .agents/',
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function checkMcpHandshake(projectDir) {
|
|
485
|
+
const mcpServerPath = path.join(projectDir, '.agents', 'mcp', 'server.mjs');
|
|
486
|
+
if (!fs.existsSync(mcpServerPath)) {
|
|
487
|
+
return {
|
|
488
|
+
id: 'mcp_handshake',
|
|
489
|
+
status: STATUS.SKIP,
|
|
490
|
+
ok: true,
|
|
491
|
+
message: 'Optional MCP Bridge not installed.',
|
|
492
|
+
remediation: 'Install separately: npm install --save-dev @contextos/mcp',
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
try {
|
|
497
|
+
const syntaxCheck = execFileSync(process.execPath, ['--check', mcpServerPath], {
|
|
498
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
499
|
+
});
|
|
500
|
+
return {
|
|
501
|
+
id: 'mcp_handshake',
|
|
502
|
+
status: STATUS.PASS,
|
|
503
|
+
ok: true,
|
|
504
|
+
message: 'server.mjs syntax and execution environment verified',
|
|
505
|
+
remediation: null,
|
|
506
|
+
};
|
|
507
|
+
} catch (err) {
|
|
508
|
+
return {
|
|
509
|
+
id: 'mcp_handshake',
|
|
510
|
+
status: STATUS.FAIL,
|
|
511
|
+
ok: false,
|
|
512
|
+
message: `MCP server syntax failure: ${err.message}`,
|
|
513
|
+
remediation: 'Rebuild MCP server bundle via `node scripts/build-mcp.js`',
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
function checkSandboxAvailability() {
|
|
519
|
+
try {
|
|
520
|
+
const stdout = execFileSync('docker', ['--version'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
521
|
+
return {
|
|
522
|
+
id: 'sandbox_availability',
|
|
523
|
+
status: STATUS.PASS,
|
|
524
|
+
ok: true,
|
|
525
|
+
message: `OCI Sandbox available (${stdout.trim()})`,
|
|
526
|
+
remediation: null,
|
|
527
|
+
};
|
|
528
|
+
} catch (err) {
|
|
529
|
+
try {
|
|
530
|
+
const podmanOut = execFileSync('podman', ['--version'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
531
|
+
return {
|
|
532
|
+
id: 'sandbox_availability',
|
|
533
|
+
status: STATUS.PASS,
|
|
534
|
+
ok: true,
|
|
535
|
+
message: `OCI Sandbox available (${podmanOut.trim()})`,
|
|
536
|
+
remediation: null,
|
|
537
|
+
};
|
|
538
|
+
} catch {
|
|
539
|
+
return {
|
|
540
|
+
id: 'sandbox_availability',
|
|
541
|
+
status: STATUS.WARN,
|
|
542
|
+
ok: true,
|
|
543
|
+
message: 'OCI Sandbox (Docker/Podman) not found. Executions will fallback to host-unsafe mode.',
|
|
544
|
+
remediation: 'Install Docker or Podman to enable secure isolated execution',
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function checkClaimEvidence(projectDir) {
|
|
551
|
+
const claimsPath = path.join(projectDir, 'benchmarks', 'claims.json');
|
|
552
|
+
if (!fs.existsSync(claimsPath)) {
|
|
553
|
+
return {
|
|
554
|
+
id: 'claim_evidence',
|
|
555
|
+
status: STATUS.SKIP,
|
|
556
|
+
ok: true,
|
|
557
|
+
message: 'No claims.json found (benchmarks/claims.json)',
|
|
558
|
+
remediation: null,
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
try {
|
|
563
|
+
const claimsData = JSON.parse(fs.readFileSync(claimsPath, 'utf8'));
|
|
564
|
+
let missingEvidence = 0;
|
|
565
|
+
const claims = claimsData.claims || [];
|
|
566
|
+
for (const claim of claims) {
|
|
567
|
+
if (claim.evidenceArtifact) {
|
|
568
|
+
const artifactPath = path.join(projectDir, claim.evidenceArtifact);
|
|
569
|
+
if (!fs.existsSync(artifactPath)) {
|
|
570
|
+
missingEvidence++;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
if (missingEvidence > 0) {
|
|
576
|
+
return {
|
|
577
|
+
id: 'claim_evidence',
|
|
578
|
+
status: STATUS.FAIL,
|
|
579
|
+
ok: false,
|
|
580
|
+
message: `${missingEvidence} claim(s) missing evidence artifact(s)`,
|
|
581
|
+
remediation: 'Run Benchmark v2 protocol to regenerate claim evidence',
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
return {
|
|
586
|
+
id: 'claim_evidence',
|
|
587
|
+
status: STATUS.PASS,
|
|
588
|
+
ok: true,
|
|
589
|
+
message: `All ${claims.length} claim(s) have verified evidence artifacts`,
|
|
590
|
+
remediation: null,
|
|
591
|
+
};
|
|
592
|
+
} catch (e) {
|
|
593
|
+
return {
|
|
594
|
+
id: 'claim_evidence',
|
|
595
|
+
status: STATUS.FAIL,
|
|
596
|
+
ok: false,
|
|
597
|
+
message: `Failed to parse claims.json: ${e.message}`,
|
|
598
|
+
remediation: 'Fix JSON syntax in benchmarks/claims.json',
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function checkProjectLock(projectDir) {
|
|
604
|
+
try {
|
|
605
|
+
const lock = new ProjectMutationLock(projectDir);
|
|
606
|
+
const payload = lock.inspect();
|
|
607
|
+
|
|
608
|
+
if (payload) {
|
|
609
|
+
const isAlive = isPidAlive(payload.pid);
|
|
610
|
+
if (!isAlive) {
|
|
611
|
+
return {
|
|
612
|
+
id: 'project_lock',
|
|
613
|
+
status: STATUS.WARN,
|
|
614
|
+
ok: true,
|
|
615
|
+
message: `Stale project mutation lock found (PID ${payload.pid} is dead)`,
|
|
616
|
+
remediation: 'Run `contextos doctor --fix` to clear stale locks',
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
return {
|
|
620
|
+
id: 'project_lock',
|
|
621
|
+
status: STATUS.WARN,
|
|
622
|
+
ok: true,
|
|
623
|
+
message: `Project mutation lock is currently held (PID ${payload.pid})`,
|
|
624
|
+
remediation: 'Wait for the current operation to finish',
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
return {
|
|
628
|
+
id: 'project_lock',
|
|
629
|
+
status: STATUS.PASS,
|
|
630
|
+
ok: true,
|
|
631
|
+
message: 'Project mutation lock is clean',
|
|
632
|
+
remediation: null,
|
|
633
|
+
};
|
|
634
|
+
} catch (e) {
|
|
635
|
+
return {
|
|
636
|
+
id: 'project_lock',
|
|
637
|
+
status: STATUS.UNVERIFIED,
|
|
638
|
+
ok: true,
|
|
639
|
+
message: `Project lock status unverified: ${e.message}`,
|
|
640
|
+
remediation: null,
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
function checkDriftStatus(projectDir) {
|
|
646
|
+
try {
|
|
647
|
+
const { detectDrift } = require('./adapters/drift-detector.js');
|
|
648
|
+
const drift = detectDrift(projectDir);
|
|
649
|
+
if (drift.isDrifted) {
|
|
650
|
+
const summaryParts = Object.entries(drift.counts)
|
|
651
|
+
.filter(([, count]) => count > 0)
|
|
652
|
+
.map(([state, count]) => `${state}: ${count}`);
|
|
653
|
+
|
|
654
|
+
return {
|
|
655
|
+
id: 'drift_status',
|
|
656
|
+
status: STATUS.WARN,
|
|
657
|
+
ok: true,
|
|
658
|
+
isDrifted: true,
|
|
659
|
+
message: `Output drift detected (${summaryParts.join(', ')})`,
|
|
660
|
+
remediation: 'Run `contextos export all` to synchronize generated adapters with current skills',
|
|
661
|
+
drift,
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
return {
|
|
665
|
+
id: 'drift_status',
|
|
666
|
+
status: STATUS.PASS,
|
|
667
|
+
ok: true,
|
|
668
|
+
isDrifted: false,
|
|
669
|
+
message: 'All generated adapter files match current source skills and profile',
|
|
670
|
+
remediation: null,
|
|
671
|
+
};
|
|
672
|
+
} catch {
|
|
673
|
+
return {
|
|
674
|
+
id: 'drift_status',
|
|
675
|
+
status: STATUS.UNVERIFIED,
|
|
676
|
+
ok: true,
|
|
677
|
+
message: 'Drift detection unverified',
|
|
678
|
+
remediation: null,
|
|
679
|
+
};
|
|
680
|
+
}
|
|
207
681
|
}
|
|
208
682
|
|
|
209
683
|
function inspectSkills(projectDir, activeProfile) {
|
|
@@ -233,16 +707,101 @@ function inspectSkills(projectDir, activeProfile) {
|
|
|
233
707
|
};
|
|
234
708
|
}
|
|
235
709
|
|
|
710
|
+
/**
|
|
711
|
+
* Executes doctor --fix safe remediation actions.
|
|
712
|
+
*/
|
|
713
|
+
function applyDoctorFix(projectDir = process.cwd(), options = {}) {
|
|
714
|
+
const results = [];
|
|
715
|
+
|
|
716
|
+
// 1. Recompile clean generated adapters
|
|
717
|
+
try {
|
|
718
|
+
const { renderAdapters, applyArtifacts } = require('./adapters/pure-compiler.js');
|
|
719
|
+
const rendered = renderAdapters(projectDir, 'all');
|
|
720
|
+
const applyRes = applyArtifacts(projectDir, rendered.artifacts, { command: 'doctor --fix' });
|
|
721
|
+
results.push(`✓ Recompiled all adapters (${applyRes.appliedCount} files updated, tx: ${applyRes.txId})`);
|
|
722
|
+
} catch (err) {
|
|
723
|
+
results.push(`✗ Could not recompile adapters: ${err.message}`);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// 2. Clean completed transaction logs older than 1 hour
|
|
727
|
+
try {
|
|
728
|
+
const txDir = path.join(projectDir, '.agents', '.contextos', 'transactions');
|
|
729
|
+
if (fs.existsSync(txDir)) {
|
|
730
|
+
let cleanedCount = 0;
|
|
731
|
+
const now = Date.now();
|
|
732
|
+
for (const entry of fs.readdirSync(txDir)) {
|
|
733
|
+
const fullEntry = path.join(txDir, entry);
|
|
734
|
+
const journalPath = path.join(fullEntry, 'journal.json');
|
|
735
|
+
if (fs.existsSync(journalPath)) {
|
|
736
|
+
try {
|
|
737
|
+
const journal = JSON.parse(fs.readFileSync(journalPath, 'utf8'));
|
|
738
|
+
if (journal.status === 'COMMITTED' || journal.status === 'ROLLED_BACK') {
|
|
739
|
+
const ageMs = now - (journal.committedAt || journal.startedAt || 0);
|
|
740
|
+
if (ageMs > 3600000) {
|
|
741
|
+
fs.rmSync(fullEntry, { recursive: true, force: true });
|
|
742
|
+
cleanedCount++;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
} catch {}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
if (cleanedCount > 0) {
|
|
749
|
+
results.push(`✓ Pruned ${cleanedCount} completed transaction journal(s)`);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
} catch {}
|
|
753
|
+
|
|
754
|
+
// 3. Clear stale project mutation locks
|
|
755
|
+
try {
|
|
756
|
+
const { ProjectMutationLock, isPidAlive } = require('./filesystem/index.js');
|
|
757
|
+
const lock = new ProjectMutationLock(projectDir);
|
|
758
|
+
const payload = lock.inspect();
|
|
759
|
+
if (payload && !isPidAlive(payload.pid)) {
|
|
760
|
+
if (fs.existsSync(lock.lockPath)) {
|
|
761
|
+
fs.unlinkSync(lock.lockPath);
|
|
762
|
+
results.push(`✓ Pruned stale project mutation lock (PID ${payload.pid})`);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
} catch {}
|
|
766
|
+
|
|
767
|
+
// 4. Clear temporary probe/error files
|
|
768
|
+
try {
|
|
769
|
+
const errLog = path.join(projectDir, '.agents', '.contextos', 'watch-error.json');
|
|
770
|
+
if (fs.existsSync(errLog)) {
|
|
771
|
+
fs.unlinkSync(errLog);
|
|
772
|
+
results.push('✓ Cleared stale watch error log');
|
|
773
|
+
}
|
|
774
|
+
} catch {}
|
|
775
|
+
|
|
776
|
+
return results;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
/**
|
|
780
|
+
* Main entrypoint for ContextOS Doctor v2.
|
|
781
|
+
*/
|
|
236
782
|
function runDoctor(projectDir = process.cwd(), options = {}) {
|
|
237
783
|
const version = (() => {
|
|
238
784
|
try {
|
|
239
785
|
return require('../package.json').version;
|
|
240
786
|
} catch {
|
|
241
|
-
return '1.7.
|
|
787
|
+
return '1.7.1';
|
|
242
788
|
}
|
|
243
789
|
})();
|
|
244
790
|
|
|
245
791
|
const isJson = Boolean(options.json);
|
|
792
|
+
|
|
793
|
+
// If --fix requested, run safe remediation first
|
|
794
|
+
let fixResults = [];
|
|
795
|
+
if (options.fix) {
|
|
796
|
+
fixResults = applyDoctorFix(projectDir, options);
|
|
797
|
+
if (!isJson) {
|
|
798
|
+
console.log('\n[ContextOS Doctor --fix] Running automated remediations:');
|
|
799
|
+
for (const res of fixResults) console.log(` ${res}`);
|
|
800
|
+
console.log('');
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
const checks = [];
|
|
246
805
|
const errors = [];
|
|
247
806
|
const warnings = [];
|
|
248
807
|
|
|
@@ -253,58 +812,122 @@ function runDoctor(projectDir = process.cwd(), options = {}) {
|
|
|
253
812
|
}
|
|
254
813
|
|
|
255
814
|
const nodeCheck = checkNodeVersion();
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
815
|
+
checks.push(nodeCheck);
|
|
816
|
+
if (!nodeCheck.ok) errors.push(nodeCheck.message);
|
|
817
|
+
else if (nodeCheck.status === STATUS.WARN) warnings.push(nodeCheck.message);
|
|
818
|
+
|
|
819
|
+
const gitCheck = checkGitVersion();
|
|
820
|
+
checks.push(gitCheck);
|
|
821
|
+
if (!gitCheck.ok) errors.push(gitCheck.message);
|
|
822
|
+
|
|
823
|
+
const fsCheck = checkFilesystemPermissions(projectDir);
|
|
824
|
+
checks.push(fsCheck);
|
|
825
|
+
if (!fsCheck.ok) errors.push(fsCheck.message);
|
|
259
826
|
|
|
260
827
|
const lockfileCheck = checkLockfileIntegrity(projectDir);
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
828
|
+
checks.push(lockfileCheck);
|
|
829
|
+
if (!lockfileCheck.ok) errors.push(lockfileCheck.error || lockfileCheck.message);
|
|
830
|
+
else if (lockfileCheck.status === STATUS.WARN) warnings.push(lockfileCheck.message);
|
|
831
|
+
|
|
832
|
+
const txCheck = checkTransactions(projectDir);
|
|
833
|
+
checks.push(txCheck);
|
|
834
|
+
if (!txCheck.ok) errors.push(txCheck.error);
|
|
266
835
|
|
|
267
836
|
const adapterCheck = checkAdapterIntegrity(projectDir);
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
}
|
|
837
|
+
checks.push(adapterCheck);
|
|
838
|
+
if (!adapterCheck.ok) errors.push(...adapterCheck.errors);
|
|
271
839
|
|
|
272
840
|
const symlinkCheck = checkSymlinks(projectDir);
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
841
|
+
checks.push(symlinkCheck);
|
|
842
|
+
if (!symlinkCheck.ok) errors.push(...symlinkCheck.errors);
|
|
843
|
+
|
|
844
|
+
const driftCheck = checkDriftStatus(projectDir);
|
|
845
|
+
checks.push(driftCheck);
|
|
846
|
+
if (driftCheck.status === STATUS.WARN) warnings.push(driftCheck.message);
|
|
276
847
|
|
|
277
848
|
const activeProfile = hasAgents ? profiles.getActiveProfile(projectDir) : null;
|
|
278
849
|
const skillsInfo = inspectSkills(projectDir, activeProfile);
|
|
279
850
|
const compiledAdapters = checkCompiledAdapters(projectDir);
|
|
280
851
|
|
|
281
|
-
const
|
|
282
|
-
|
|
852
|
+
const mcpCheck = checkMcpHandshake(projectDir);
|
|
853
|
+
checks.push(mcpCheck);
|
|
854
|
+
if (!mcpCheck.ok) errors.push(mcpCheck.message);
|
|
283
855
|
|
|
284
856
|
const hookCheck = checkPreCommitHook(projectDir);
|
|
857
|
+
checks.push(hookCheck);
|
|
858
|
+
if (hookCheck.status === STATUS.WARN) warnings.push(hookCheck.message);
|
|
859
|
+
|
|
285
860
|
const secretCheck = checkSecretScanner(projectDir);
|
|
861
|
+
checks.push(secretCheck);
|
|
862
|
+
if (!secretCheck.ok) {
|
|
863
|
+
if (secretCheck.status === STATUS.WARN) warnings.push(secretCheck.message);
|
|
864
|
+
else errors.push(secretCheck.message);
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
const sandboxCheck = checkSandboxAvailability();
|
|
868
|
+
checks.push(sandboxCheck);
|
|
869
|
+
if (sandboxCheck.status === STATUS.WARN) warnings.push(sandboxCheck.message);
|
|
870
|
+
|
|
871
|
+
const claimCheck = checkClaimEvidence(projectDir);
|
|
872
|
+
checks.push(claimCheck);
|
|
873
|
+
if (!claimCheck.ok) errors.push(claimCheck.message);
|
|
874
|
+
else if (claimCheck.status === STATUS.SKIP) warnings.push(claimCheck.message);
|
|
875
|
+
|
|
876
|
+
const projectLockCheck = checkProjectLock(projectDir);
|
|
877
|
+
checks.push(projectLockCheck);
|
|
878
|
+
if (projectLockCheck.status === STATUS.WARN) warnings.push(projectLockCheck.message);
|
|
879
|
+
|
|
286
880
|
const stack = profiles.detectStack(projectDir);
|
|
287
881
|
|
|
288
|
-
|
|
882
|
+
// Determine overall status
|
|
883
|
+
let overallStatus = STATUS.PASS;
|
|
884
|
+
if (txCheck.status === STATUS.RECOVERY_REQUIRED) {
|
|
885
|
+
overallStatus = STATUS.RECOVERY_REQUIRED;
|
|
886
|
+
} else if (errors.length > 0) {
|
|
887
|
+
overallStatus = STATUS.FAIL;
|
|
888
|
+
} else if (warnings.length > 0) {
|
|
889
|
+
overallStatus = STATUS.WARN;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
if (options.strict && warnings.length > 0) {
|
|
893
|
+
overallStatus = STATUS.FAIL;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
const ok = overallStatus === STATUS.PASS || overallStatus === STATUS.WARN;
|
|
289
897
|
|
|
290
898
|
if (isJson) {
|
|
291
899
|
const report = {
|
|
900
|
+
schemaVersion: '2.0.0',
|
|
901
|
+
status: overallStatus,
|
|
292
902
|
ok,
|
|
293
903
|
version,
|
|
904
|
+
timestamp: new Date().toISOString(),
|
|
294
905
|
errors,
|
|
295
906
|
warnings,
|
|
907
|
+
checks,
|
|
296
908
|
hasAgents,
|
|
297
909
|
nodeOk: nodeCheck.ok,
|
|
298
910
|
activeProfile,
|
|
299
911
|
skillsInfo,
|
|
300
912
|
compiledAdapters,
|
|
301
|
-
hasMcp,
|
|
913
|
+
hasMcp: mcpCheck.ok && mcpCheck.status === STATUS.PASS,
|
|
302
914
|
hookCheck,
|
|
303
915
|
secretCheck,
|
|
304
916
|
lockfileCheck,
|
|
305
917
|
adapterCheck,
|
|
306
918
|
symlinkCheck,
|
|
919
|
+
driftCheck,
|
|
920
|
+
sandboxCheck,
|
|
921
|
+
claimCheck,
|
|
922
|
+
projectLockCheck,
|
|
307
923
|
stack,
|
|
924
|
+
summary: {
|
|
925
|
+
total: checks.length,
|
|
926
|
+
pass: checks.filter(c => c.status === STATUS.PASS).length,
|
|
927
|
+
warn: checks.filter(c => c.status === STATUS.WARN).length,
|
|
928
|
+
fail: checks.filter(c => c.status === STATUS.FAIL).length,
|
|
929
|
+
recovery: checks.filter(c => c.status === STATUS.RECOVERY_REQUIRED).length,
|
|
930
|
+
},
|
|
308
931
|
};
|
|
309
932
|
console.log(JSON.stringify(report, null, 2));
|
|
310
933
|
if (options.exitOnError !== false && !ok && require.main === module) {
|
|
@@ -314,11 +937,10 @@ function runDoctor(projectDir = process.cwd(), options = {}) {
|
|
|
314
937
|
}
|
|
315
938
|
|
|
316
939
|
console.log('\n┌─────────────────────────────────────────────────────────────┐');
|
|
317
|
-
console.log(`│ ContextOS Doctor — Project Health Check v${version.padEnd(
|
|
940
|
+
console.log(`│ ContextOS Doctor v2 — Project Health Check v${version.padEnd(14)}│`);
|
|
318
941
|
console.log('├─────────────────────────────────────────────────────────────┤');
|
|
319
942
|
console.log('│ │');
|
|
320
943
|
|
|
321
|
-
// .agents directory
|
|
322
944
|
if (hasAgents) {
|
|
323
945
|
console.log('│ ✓ .agents/ directory found │');
|
|
324
946
|
} else {
|
|
@@ -365,21 +987,37 @@ function runDoctor(projectDir = process.cwd(), options = {}) {
|
|
|
365
987
|
console.log(`│ ${symIcon} ${symStr.padEnd(58)}│`);
|
|
366
988
|
|
|
367
989
|
// MCP
|
|
368
|
-
if (
|
|
990
|
+
if (mcpCheck.status === STATUS.PASS) {
|
|
369
991
|
console.log('│ ✓ MCP server: installed (.agents/mcp/server.mjs) │');
|
|
370
992
|
} else {
|
|
371
993
|
console.log('│ • MCP server: not installed (run: contextos setup-mcp) │');
|
|
372
994
|
}
|
|
373
995
|
|
|
374
|
-
//
|
|
996
|
+
// Pre-commit hook
|
|
375
997
|
const hookIcon = hookCheck.ok ? '✓' : '•';
|
|
376
998
|
const hookStr = `Pre-commit hook: ${hookCheck.message}`;
|
|
377
999
|
console.log(`│ ${hookIcon} ${hookStr.padEnd(58)}│`);
|
|
378
1000
|
|
|
379
|
-
|
|
1001
|
+
// Secret scanner
|
|
1002
|
+
const secretIcon = secretCheck.ok ? '✓' : (secretCheck.status === STATUS.WARN ? '•' : '✗');
|
|
380
1003
|
const secretStr = `Secret scanner: ${secretCheck.message}`;
|
|
381
1004
|
console.log(`│ ${secretIcon} ${secretStr.padEnd(58)}│`);
|
|
382
1005
|
|
|
1006
|
+
// Sandbox
|
|
1007
|
+
const sandboxIcon = sandboxCheck.status === STATUS.PASS ? '✓' : '•';
|
|
1008
|
+
const sandboxStr = `Sandbox: ${sandboxCheck.message}`;
|
|
1009
|
+
console.log(`│ ${sandboxIcon} ${sandboxStr.slice(0, 58).padEnd(58)}│`);
|
|
1010
|
+
|
|
1011
|
+
// Claims Evidence
|
|
1012
|
+
const claimIcon = claimCheck.status === STATUS.PASS ? '✓' : (claimCheck.status === STATUS.SKIP ? '•' : '✗');
|
|
1013
|
+
const claimStr = `Claims evidence: ${claimCheck.message}`;
|
|
1014
|
+
console.log(`│ ${claimIcon} ${claimStr.slice(0, 58).padEnd(58)}│`);
|
|
1015
|
+
|
|
1016
|
+
// Project Mutation Lock
|
|
1017
|
+
const lockStateIcon = projectLockCheck.status === STATUS.PASS ? '✓' : (projectLockCheck.status === STATUS.WARN ? '•' : '✗');
|
|
1018
|
+
const lockStateStr = `Mutation lock: ${projectLockCheck.message}`;
|
|
1019
|
+
console.log(`│ ${lockStateIcon} ${lockStateStr.slice(0, 58).padEnd(58)}│`);
|
|
1020
|
+
|
|
383
1021
|
console.log('│ │');
|
|
384
1022
|
console.log('├─────────────────────────────────────────────────────────────┤');
|
|
385
1023
|
console.log('│ Project Stack & Profile Recommendations │');
|
|
@@ -416,20 +1054,27 @@ function runDoctor(projectDir = process.cwd(), options = {}) {
|
|
|
416
1054
|
}
|
|
417
1055
|
|
|
418
1056
|
const result = {
|
|
1057
|
+
schemaVersion: '2.0.0',
|
|
1058
|
+
status: overallStatus,
|
|
419
1059
|
ok,
|
|
420
1060
|
errors,
|
|
421
1061
|
warnings,
|
|
1062
|
+
checks,
|
|
422
1063
|
hasAgents,
|
|
423
1064
|
nodeOk: nodeCheck.ok,
|
|
424
1065
|
activeProfile,
|
|
425
1066
|
skillsInfo,
|
|
426
1067
|
compiledAdapters,
|
|
427
|
-
hasMcp,
|
|
1068
|
+
hasMcp: mcpCheck.ok && mcpCheck.status === STATUS.PASS,
|
|
428
1069
|
hookCheck,
|
|
429
1070
|
secretCheck,
|
|
430
1071
|
lockfileCheck,
|
|
431
1072
|
adapterCheck,
|
|
432
1073
|
symlinkCheck,
|
|
1074
|
+
driftCheck,
|
|
1075
|
+
sandboxCheck,
|
|
1076
|
+
claimCheck,
|
|
1077
|
+
projectLockCheck,
|
|
433
1078
|
stack,
|
|
434
1079
|
};
|
|
435
1080
|
|
|
@@ -446,13 +1091,23 @@ if (require.main === module) {
|
|
|
446
1091
|
}
|
|
447
1092
|
|
|
448
1093
|
module.exports = {
|
|
1094
|
+
STATUS,
|
|
449
1095
|
runDoctor,
|
|
1096
|
+
applyDoctorFix,
|
|
450
1097
|
checkNodeVersion,
|
|
1098
|
+
checkGitVersion,
|
|
1099
|
+
checkFilesystemPermissions,
|
|
451
1100
|
checkPreCommitHook,
|
|
452
1101
|
checkSecretScanner,
|
|
453
1102
|
checkCompiledAdapters,
|
|
454
1103
|
checkLockfileIntegrity,
|
|
1104
|
+
checkTransactions,
|
|
455
1105
|
checkAdapterIntegrity,
|
|
456
1106
|
checkSymlinks,
|
|
1107
|
+
checkMcpHandshake,
|
|
1108
|
+
checkDriftStatus,
|
|
1109
|
+
checkSandboxAvailability,
|
|
1110
|
+
checkClaimEvidence,
|
|
1111
|
+
checkProjectLock,
|
|
457
1112
|
inspectSkills,
|
|
458
1113
|
};
|