Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 48 additions & 5 deletions src/commands/management/doctor.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,65 @@
import { PUBLIC_COMMANDS } from '@agent-device/command-registry/catalog';
import type { CommandSchemaOverride } from '@agent-device/command-registry/command-schema';
import * as commandInput from '../command-input.ts';
import type { CommandResultMap } from '@agent-device/command-registry/command-result';
import { DEVICE_TARGETS } from '@agent-device/kernel/device';
import {
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
booleanField,
enumSchema,
looseObjectSchema,
numberSchema,
objectSchema,
stringField,
stringSchema,
} from '../command-input.ts';
import { commonInputFromFlags, direct } from '../cli-grammar/common.ts';
import type { CliReader, DaemonWriter } from '../cli-grammar/types.ts';
import type { JsonSchema } from '../command-contract.ts';
import { defineCommandFacet } from '../family/types.ts';
import { defineFieldCommandMetadata } from '../field-command-contract.ts';
import { managementCliOutputFormatters } from './output.ts';

/**
* This family's advertised MCP `outputSchema`, keyed by daemon command name and projected into
* the command map by `src/mcp/command-output-schemas.ts`.
*/
export const DOCTOR_COMMAND_OUTPUT_SCHEMAS = {
// packages/contracts/src/doctor.ts
doctor: objectSchema(
{
status: enumSchema(['pass', 'warn', 'fail', 'info']),
summary: stringSchema(),
kind: enumSchema(['auto', 'react-native', 'expo', 'repack']),
platform: stringSchema(),
target: enumSchema(DEVICE_TARGETS),
targetApp: stringSchema(),
metro: objectSchema({ host: stringSchema(), port: numberSchema() }, ['host', 'port']),
checks: {
type: 'array',
items: objectSchema(
{
id: stringSchema(),
status: enumSchema(['pass', 'warn', 'fail', 'info']),
summary: stringSchema(),
hint: stringSchema(),
command: stringSchema(),
evidence: looseObjectSchema(),
},
['id', 'status', 'summary'],
),
},
},
['status', 'summary', 'kind', 'checks'],
),
} satisfies Pick<Record<keyof CommandResultMap, JsonSchema>, 'doctor'>;

const doctorCommandMetadata = defineFieldCommandMetadata(
'doctor',
'Diagnose device, app, development-server, and React Native or Expo readiness issues. Returns compact evidence for local inventory, sessions, optional app discovery, toolchains, and server reachability.',
{
targetApp: commandInput.stringField(
targetApp: stringField(
'Installed app package/bundle id or app name to verify without opening a session.',
),
remote: commandInput.booleanField(
'Check remote connection setup instead of local device inventory.',
),
remote: booleanField('Check remote connection setup instead of local device inventory.'),
},
);

Expand Down
31 changes: 31 additions & 0 deletions src/mcp/__tests__/command-tools-management-doctor-schemas.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import assert from 'node:assert/strict';
import { test } from 'vitest';
import { ownerFilesForCommand } from '@agent-device/command-registry/owner-files';
import { DOCTOR_COMMAND_OUTPUT_SCHEMAS } from '../../commands/management/doctor.ts';
import { COMMAND_OUTPUT_SCHEMAS } from '../command-output-schemas.ts';

const DOCTOR_COMMANDS = Object.keys(DOCTOR_COMMAND_OUTPUT_SCHEMAS) as Array<
keyof typeof DOCTOR_COMMAND_OUTPUT_SCHEMAS
>;

// doctor does not carry the post-action observation trait (#1652): it is a device-runtime
// command, not an interaction command, so the composed map never copies the entry and
// reference equality must hold.
test('MCP doctor family output schemas are the family module entries, not copies', () => {
for (const command of DOCTOR_COMMANDS) {
assert.equal(
COMMAND_OUTPUT_SCHEMAS[command],
DOCTOR_COMMAND_OUTPUT_SCHEMAS[command],
`${command} is not reference-equal to the doctor module's own schema object`,
);
}
});

test('the projected family map declares exactly the commands its module owns', () => {
for (const command of DOCTOR_COMMANDS) {
assert.ok(
ownerFilesForCommand(command).includes('src/commands/management/doctor.ts'),
`${command} projects its output schema from this module but does not name it as its owner`,
);
}
});
2 changes: 2 additions & 0 deletions src/mcp/__tests__/command-tools-replay-schemas.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ownerFilesForCommand } from '@agent-device/command-registry/owner-files
import { commandSupportsSettleObservation } from '@agent-device/command-registry/registry';
import { WAIT_COMMAND_OUTPUT_SCHEMAS } from '../../commands/capture/wait.ts';
import { PREPARE_COMMAND_OUTPUT_SCHEMAS } from '../../commands/management/prepare.ts';
import { DOCTOR_COMMAND_OUTPUT_SCHEMAS } from '../../commands/management/doctor.ts';
import { DEVICE_MANAGEMENT_COMMAND_OUTPUT_SCHEMAS } from '../../commands/management/device.ts';
import { PUSH_MANAGEMENT_COMMAND_OUTPUT_SCHEMAS } from '../../commands/management/push.ts';
import { VIEWPORT_COMMAND_OUTPUT_SCHEMAS } from '../../commands/management/viewport.ts';
Expand Down Expand Up @@ -81,6 +82,7 @@ const PROJECTED_FAMILIES = [
{ name: 'interaction', schemas: INTERACTION_COMMAND_OUTPUT_SCHEMAS },
{ name: 'capture-wait', schemas: WAIT_COMMAND_OUTPUT_SCHEMAS },
{ name: 'management-prepare', schemas: PREPARE_COMMAND_OUTPUT_SCHEMAS },
{ name: 'management-doctor', schemas: DOCTOR_COMMAND_OUTPUT_SCHEMAS },
{ name: 'management-device', schemas: DEVICE_MANAGEMENT_COMMAND_OUTPUT_SCHEMAS },
{ name: 'management-push', schemas: PUSH_MANAGEMENT_COMMAND_OUTPUT_SCHEMAS },
{ name: 'management-viewport', schemas: VIEWPORT_COMMAND_OUTPUT_SCHEMAS },
Expand Down
32 changes: 2 additions & 30 deletions src/mcp/command-output-schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import {
booleanSchema,
constSchema,
enumSchema,
looseObjectSchema,
numberSchema,
objectSchema,
stringArraySchema,
stringSchema,
} from '../commands/command-input.ts';
import { WAIT_COMMAND_OUTPUT_SCHEMAS } from '../commands/capture/wait.ts';
import { PREPARE_COMMAND_OUTPUT_SCHEMAS } from '../commands/management/prepare.ts';
import { DOCTOR_COMMAND_OUTPUT_SCHEMAS } from '../commands/management/doctor.ts';
import { DEVICE_MANAGEMENT_COMMAND_OUTPUT_SCHEMAS } from '../commands/management/device.ts';
import { PUSH_MANAGEMENT_COMMAND_OUTPUT_SCHEMAS } from '../commands/management/push.ts';
import { VIEWPORT_COMMAND_OUTPUT_SCHEMAS } from '../commands/management/viewport.ts';
Expand All @@ -23,7 +23,6 @@ import {
import { RECORDING_COMMAND_OUTPUT_SCHEMAS } from '../commands/recording/output-schemas.ts';
import { REPLAY_COMMAND_OUTPUT_SCHEMAS } from '../commands/replay/index.ts';
import { SYSTEM_COMMAND_OUTPUT_SCHEMAS } from '../commands/system/index.ts';
import { DEVICE_TARGETS } from '@agent-device/kernel/device';

/**
* Registry of per-command MCP `outputSchema`s, keyed by the daemon command
Expand Down Expand Up @@ -184,34 +183,6 @@ const BASE_COMMAND_OUTPUT_SCHEMAS = {
['direction'],
),

// packages/contracts/src/doctor.ts
doctor: objectSchema(
{
status: enumSchema(['pass', 'warn', 'fail', 'info']),
summary: stringSchema(),
kind: enumSchema(['auto', 'react-native', 'expo', 'repack']),
platform: stringSchema(),
target: enumSchema(DEVICE_TARGETS),
targetApp: stringSchema(),
metro: objectSchema({ host: stringSchema(), port: numberSchema() }, ['host', 'port']),
checks: {
type: 'array',
items: objectSchema(
{
id: stringSchema(),
status: enumSchema(['pass', 'warn', 'fail', 'info']),
summary: stringSchema(),
hint: stringSchema(),
command: stringSchema(),
evidence: looseObjectSchema(),
},
['id', 'status', 'summary'],
),
},
},
['status', 'summary', 'kind', 'checks'],
),

// packages/contracts/src/diff.ts — the public Node command accepts snapshot diffs.
diff: objectSchema(
{
Expand Down Expand Up @@ -247,6 +218,7 @@ const BASE_COMMAND_OUTPUT_SCHEMAS = {
// and this map's `satisfies` still refuses a missing `CommandResultMap` key.
...WAIT_COMMAND_OUTPUT_SCHEMAS,
...PREPARE_COMMAND_OUTPUT_SCHEMAS,
...DOCTOR_COMMAND_OUTPUT_SCHEMAS,
...DEVICE_MANAGEMENT_COMMAND_OUTPUT_SCHEMAS,
...PUSH_MANAGEMENT_COMMAND_OUTPUT_SCHEMAS,
...VIEWPORT_COMMAND_OUTPUT_SCHEMAS,
Expand Down
Loading