@@ -8,7 +8,7 @@ import { loadRing, detectRegression } from '../lib/health-history.mjs';
88import * as paths from '../lib/paths.mjs' ;
99import { nativesStatus , rufloRuntimeNatives , dbPathPinStatus , aidefencePresent , securityPresent } from '../lib/natives.mjs' ;
1010import { scanNpxStale } from '../lib/npx.mjs' ;
11- import { registrationStatus , codexMcpStatus , rufloCodexMcpStatus } from '../lib/mcp.mjs' ;
11+ import { registrationStatus , codexMcpStatus , rufloCodexMcpStatus , ruvectorRegistered } from '../lib/mcp.mjs' ;
1212import { listDaemons , staleDaemons } from '../lib/daemons.mjs' ;
1313import { scanRvf } from '../lib/rvf.mjs' ;
1414import { registry , syncBlocks , blocksForTarget , retiredForTarget , guidanceTargets } from '../lib/blocks.mjs' ;
@@ -19,8 +19,9 @@ import { drift as ruvnetBrainDrift, nightlyAgentPresent as rbNightlyPresent, NIG
1919import { coherence as adbCoherence } from '../lib/agentdb.mjs' ;
2020import { readJson } from '../lib/settings.mjs' ;
2121import { have } from '../lib/exec.mjs' ;
22- import { HOSTS , settingsTarget , isDefault , managedEnv , MANAGED_ENV_KEYS , hostInstallState , hostAuthState , bothHostsEnabled , aqeRouterFile , aqeSupportsAgentOverrides } from '../lib/providers.mjs' ;
23- import { policyToAgentOverrides , routingSummary } from '../lib/routing.mjs' ;
22+ import { HOSTS , settingsTarget , isDefault , managedEnv , MANAGED_ENV_KEYS , hostInstallState , hostAuthState , bothHostsEnabled , aqeRouterFile , aqeSupportsAgentOverrides , credentialGaps } from '../lib/providers.mjs' ;
23+ import { policyToAgentOverrides , routingSummary , divergedRoutes } from '../lib/routing.mjs' ;
24+ import { drift as ruvectorDrift } from '../lib/ruvector.mjs' ;
2425
2526export const options = {
2627 json : { type : 'boolean' , default : false } ,
@@ -97,6 +98,35 @@ export async function collect({ pkgRoot, cwd = process.cwd() }) {
9798 }
9899 }
99100
101+ // ruvector — a global CLI users register as an MCP server BY HAND. ak manages
102+ // its drift, never its presence or its registration. Unregistered → no row at
103+ // all (same silence as codex-not-enabled): nudging a tool nobody opted into
104+ // would be management by ambush. Registered but kit.json ruvector:false → an
105+ // info row with NO fix, so sync never plans an upgrade the user turned off.
106+ //
107+ // Wording is deliberately "CLI": the registered command is typically
108+ // `npx -y ruvector mcp start`, so upgrading the global package does not
109+ // necessarily change what the MCP server executes. Claim only what is true.
110+ if ( ruvectorRegistered ( ) ) {
111+ if ( cfg . ruvector === false ) {
112+ rows . push ( row ( 'ruvector' , 'info' , 'ruvector MCP registered — CLI updates disabled (kit.json ruvector:false)' ) ) ;
113+ } else {
114+ try {
115+ const rv = await ruvectorDrift ( ) ;
116+ if ( rv . present && rv . outdated ) {
117+ rows . push ( row ( 'ruvector' , 'warn' ,
118+ `ruvector CLI ${ rv . installed } installed, ${ rv . latest } available` , 'sync upgrades the ruvector CLI' ) ) ;
119+ } else if ( rv . present ) {
120+ rows . push ( row ( 'ruvector' , 'ok' , `ruvector CLI ${ rv . installed } ${ rv . latest ? ' (latest)' : '' } (MCP registered, user scope)` ) ) ;
121+ } else {
122+ rows . push ( row ( 'ruvector' , 'info' , 'ruvector MCP registered but no global CLI installed (server runs via npx)' ) ) ;
123+ }
124+ } catch ( e ) {
125+ rows . push ( row ( 'ruvector' , 'warn' , `ruvector check unavailable: ${ e . message } ` ) ) ;
126+ }
127+ }
128+ }
129+
100130 // self (the kit's own version — prerelease installs track the `next` tag)
101131 try {
102132 const s = await selfDrift ( { pkgRoot } ) ;
@@ -348,6 +378,20 @@ export async function collect({ pkgRoot, cwd = process.cwd() }) {
348378 } else {
349379 rows . push ( row ( 'providers' , 'ok' , `wired: ${ on } ${ chainStr } (${ scope } )` ) ) ;
350380 }
381+ // Chain VIABILITY, separate from chain ORDER above: a chain in the right
382+ // order whose rungs have no credential fails over into nothing (#54). Warn,
383+ // not fail — the primary rung still works — and no `fix`, since only the
384+ // user can supply a key.
385+ if ( chain . length ) {
386+ const gaps = credentialGaps ( chain ) ;
387+ if ( gaps . length ) {
388+ rows . push ( row ( 'providers' , 'warn' ,
389+ `aqe chain: ${ chain . length - gaps . length } /${ chain . length } rungs have credentials `
390+ + `(${ gaps . map ( ( g ) => `${ g . provider } : needs ${ g . missing . join ( ', ' ) } ` ) . join ( '; ' ) } )` ) ) ;
391+ } else {
392+ rows . push ( row ( 'providers' , 'ok' , `aqe chain: ${ chain . length } /${ chain . length } rungs have credentials` ) ) ;
393+ }
394+ }
351395 }
352396 } catch ( e ) {
353397 rows . push ( row ( 'providers' , 'warn' , `provider check unavailable: ${ e . message } ` ) ) ;
@@ -371,6 +415,20 @@ export async function collect({ pkgRoot, cwd = process.cwd() }) {
371415 if ( drift ) rows . push ( row ( 'routing' , 'warn' , `${ base } — llm-config.json out of sync` , 'sync re-applies agentOverrides' ) ) ;
372416 else rows . push ( row ( 'routing' , 'ok' , base ) ) ;
373417 }
418+ // Seeded pins vs today's defaults. Deliberately `info` and deliberately
419+ // "diverges from": which side wins is activity-dependent (a newer default
420+ // can cost 2-3× the agentic turns on routine work), so a `warn` would push
421+ // users to spend turns clearing a lint. No `fix` — sync must never
422+ // auto-refresh a pin; `ak x provider refresh` is the opt-in path (#55).
423+ const diverged = divergedRoutes ( policy ) ;
424+ if ( diverged . length ) {
425+ const pairs = [ ...new Set ( diverged . flatMap ( ( d ) => [
426+ ...( d . modelDiverged ? [ `${ d . model } vs ${ d . defaultModel } ` ] : [ ] ) ,
427+ ...d . escalate . map ( ( e ) => `${ e . model } vs ${ e . defaultModel } (escalation)` ) ,
428+ ] ) ) ] . join ( ', ' ) ;
429+ rows . push ( row ( 'routing' , 'info' ,
430+ `${ diverged . length } seeded route(s) diverge from current defaults (${ pairs } ) — ak x provider refresh` ) ) ;
431+ }
374432 }
375433 } catch ( e ) {
376434 rows . push ( row ( 'routing' , 'warn' , `routing check unavailable: ${ e . message } ` ) ) ;
0 commit comments