brainctl 0.1.18 → 0.1.19
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/dist/cli.d.ts +7 -7
- package/dist/cli.js +9 -9
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/mcp.js +2 -2
- package/dist/commands/profile.d.ts +5 -5
- package/dist/commands/profile.js +1 -1
- package/dist/commands/status.d.ts +1 -1
- package/dist/{mcp/server.d.ts → mcp-server.d.ts} +1 -1
- package/dist/{mcp/server.js → mcp-server.js} +10 -10
- package/dist/services/{agent-asset-installer.d.ts → agent/agent-asset-installer.d.ts} +1 -1
- package/dist/services/{agent-asset-installer.js → agent/agent-asset-installer.js} +2 -2
- package/dist/services/{agent-availability-service.d.ts → agent/agent-availability-service.d.ts} +1 -1
- package/dist/services/{agent-availability-service.js → agent/agent-availability-service.js} +1 -1
- package/dist/services/{agent-config-service.d.ts → agent/agent-config-service.d.ts} +6 -6
- package/dist/services/{agent-config-service.js → agent/agent-config-service.js} +6 -6
- package/dist/services/{credential-redaction-service.d.ts → credential/credential-redaction-service.d.ts} +1 -1
- package/dist/services/{credential-resolution-service.d.ts → credential/credential-resolution-service.d.ts} +1 -1
- package/dist/services/{doctor-service.d.ts → platform/doctor-service.d.ts} +2 -2
- package/dist/services/{doctor-service.js → platform/doctor-service.js} +1 -1
- package/dist/services/{mcp-preflight-service.d.ts → platform/mcp-preflight-service.d.ts} +2 -2
- package/dist/services/{mcp-preflight-service.js → platform/mcp-preflight-service.js} +1 -1
- package/dist/services/{runtime-detector.d.ts → platform/runtime-detector.d.ts} +1 -1
- package/dist/services/{status-service.d.ts → platform/status-service.d.ts} +3 -3
- package/dist/services/{status-service.js → platform/status-service.js} +2 -2
- package/dist/services/{update-check-service.js → platform/update-check-service.js} +1 -1
- package/dist/services/plugin/plugin-install-bundle.d.ts +20 -0
- package/dist/services/plugin/plugin-install-bundle.js +80 -0
- package/dist/services/plugin/plugin-install-compatibility.d.ts +15 -0
- package/dist/services/plugin/plugin-install-compatibility.js +91 -0
- package/dist/services/plugin/plugin-install-fs.d.ts +27 -0
- package/dist/services/plugin/plugin-install-fs.js +65 -0
- package/dist/services/{plugin-install-service.d.ts → plugin/plugin-install-service.d.ts} +4 -18
- package/dist/services/{plugin-install-service.js → plugin/plugin-install-service.js} +7 -308
- package/dist/services/plugin/plugin-install-uninstall.d.ts +12 -0
- package/dist/services/plugin/plugin-install-uninstall.js +76 -0
- package/dist/services/{skill-paths.d.ts → plugin/skill-paths.d.ts} +1 -1
- package/dist/services/{skill-preflight-service.d.ts → plugin/skill-preflight-service.d.ts} +1 -1
- package/dist/services/{portable-mcp-classifier.d.ts → profile/portable-mcp-classifier.d.ts} +3 -3
- package/dist/services/{portable-mcp-classifier.js → profile/portable-mcp-classifier.js} +2 -2
- package/dist/services/{portable-profile-pack-service.d.ts → profile/portable-profile-pack-service.d.ts} +2 -2
- package/dist/services/{portable-profile-pack-service.js → profile/portable-profile-pack-service.js} +5 -5
- package/dist/services/{profile-apply-service.d.ts → profile/profile-apply-service.d.ts} +2 -2
- package/dist/services/{profile-apply-service.js → profile/profile-apply-service.js} +5 -5
- package/dist/services/{profile-export-service.d.ts → profile/profile-export-service.d.ts} +2 -2
- package/dist/services/{profile-import-service.d.ts → profile/profile-import-service.d.ts} +1 -1
- package/dist/services/{profile-import-service.js → profile/profile-import-service.js} +4 -4
- package/dist/services/{profile-service.d.ts → profile/profile-service.d.ts} +1 -1
- package/dist/services/{profile-service.js → profile/profile-service.js} +1 -1
- package/dist/services/{profile-snapshot-service.d.ts → profile/profile-snapshot-service.d.ts} +1 -1
- package/dist/ui/routes.d.ts +1 -1
- package/dist/ui/routes.js +10 -10
- package/dist/ui/server.d.ts +1 -1
- package/package.json +1 -1
- /package/dist/{system/executables.d.ts → executables.d.ts} +0 -0
- /package/dist/{system/executables.js → executables.js} +0 -0
- /package/dist/services/{agent-converter-service.d.ts → agent/agent-converter-service.d.ts} +0 -0
- /package/dist/services/{agent-converter-service.js → agent/agent-converter-service.js} +0 -0
- /package/dist/services/{credential-redaction-service.js → credential/credential-redaction-service.js} +0 -0
- /package/dist/services/{credential-resolution-service.js → credential/credential-resolution-service.js} +0 -0
- /package/dist/services/{runtime-detector.js → platform/runtime-detector.js} +0 -0
- /package/dist/services/{update-check-service.d.ts → platform/update-check-service.d.ts} +0 -0
- /package/dist/services/{skill-paths.js → plugin/skill-paths.js} +0 -0
- /package/dist/services/{skill-preflight-service.js → plugin/skill-preflight-service.js} +0 -0
- /package/dist/services/{profile-export-service.js → profile/profile-export-service.js} +0 -0
- /package/dist/services/{profile-snapshot-service.js → profile/profile-snapshot-service.js} +0 -0
package/dist/cli.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
-
import { type DoctorService } from './services/doctor-service.js';
|
|
4
|
-
import { type ProfileApplyService } from './services/profile-apply-service.js';
|
|
5
|
-
import { type ProfileExportService } from './services/profile-export-service.js';
|
|
6
|
-
import { type ProfileImportService } from './services/profile-import-service.js';
|
|
7
|
-
import { type ProfileService } from './services/profile-service.js';
|
|
8
|
-
import { type ProfileSnapshotService } from './services/profile-snapshot-service.js';
|
|
9
|
-
import { type StatusService } from './services/status-service.js';
|
|
3
|
+
import { type DoctorService } from './services/platform/doctor-service.js';
|
|
4
|
+
import { type ProfileApplyService } from './services/profile/profile-apply-service.js';
|
|
5
|
+
import { type ProfileExportService } from './services/profile/profile-export-service.js';
|
|
6
|
+
import { type ProfileImportService } from './services/profile/profile-import-service.js';
|
|
7
|
+
import { type ProfileService } from './services/profile/profile-service.js';
|
|
8
|
+
import { type ProfileSnapshotService } from './services/profile/profile-snapshot-service.js';
|
|
9
|
+
import { type StatusService } from './services/platform/status-service.js';
|
|
10
10
|
export interface CliServices {
|
|
11
11
|
statusService: StatusService;
|
|
12
12
|
doctorService: DoctorService;
|
package/dist/cli.js
CHANGED
|
@@ -10,15 +10,15 @@ import { registerProfileCommand } from './commands/profile.js';
|
|
|
10
10
|
import { registerStatusCommand } from './commands/status.js';
|
|
11
11
|
import { registerUiCommand } from './commands/ui.js';
|
|
12
12
|
import { printError } from './output.js';
|
|
13
|
-
import { createUpdateCheckService } from './services/update-check-service.js';
|
|
14
|
-
import { createDoctorService } from './services/doctor-service.js';
|
|
15
|
-
import { createProfileApplyService } from './services/profile-apply-service.js';
|
|
16
|
-
import { createProfileExportService } from './services/profile-export-service.js';
|
|
17
|
-
import { createProfileImportService } from './services/profile-import-service.js';
|
|
18
|
-
import { createProfileService } from './services/profile-service.js';
|
|
19
|
-
import { createProfileSnapshotService } from './services/profile-snapshot-service.js';
|
|
20
|
-
import { createStatusService } from './services/status-service.js';
|
|
21
|
-
import { createAgentAvailabilityService } from './services/agent-availability-service.js';
|
|
13
|
+
import { createUpdateCheckService } from './services/platform/update-check-service.js';
|
|
14
|
+
import { createDoctorService } from './services/platform/doctor-service.js';
|
|
15
|
+
import { createProfileApplyService } from './services/profile/profile-apply-service.js';
|
|
16
|
+
import { createProfileExportService } from './services/profile/profile-export-service.js';
|
|
17
|
+
import { createProfileImportService } from './services/profile/profile-import-service.js';
|
|
18
|
+
import { createProfileService } from './services/profile/profile-service.js';
|
|
19
|
+
import { createProfileSnapshotService } from './services/profile/profile-snapshot-service.js';
|
|
20
|
+
import { createStatusService } from './services/platform/status-service.js';
|
|
21
|
+
import { createAgentAvailabilityService } from './services/agent/agent-availability-service.js';
|
|
22
22
|
const packageVersion = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
23
23
|
export function createProgram(overrides = {}) {
|
|
24
24
|
const services = createDefaultServices(overrides);
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
|
-
import type { DoctorService } from '../services/doctor-service.js';
|
|
2
|
+
import type { DoctorService } from '../services/platform/doctor-service.js';
|
|
3
3
|
export declare function registerDoctorCommand(program: Command, doctorService: DoctorService): void;
|
package/dist/commands/mcp.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
import { startMcpServer } from '../mcp
|
|
3
|
-
import { createUpdateCheckService } from '../services/update-check-service.js';
|
|
2
|
+
import { startMcpServer } from '../mcp-server.js';
|
|
3
|
+
import { createUpdateCheckService } from '../services/platform/update-check-service.js';
|
|
4
4
|
export function registerMcpCommand(program) {
|
|
5
5
|
program
|
|
6
6
|
.command('mcp')
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
|
-
import type { ProfileApplyService } from '../services/profile-apply-service.js';
|
|
3
|
-
import type { ProfileExportService } from '../services/profile-export-service.js';
|
|
4
|
-
import type { ProfileImportService } from '../services/profile-import-service.js';
|
|
5
|
-
import type { ProfileService } from '../services/profile-service.js';
|
|
6
|
-
import type { ProfileSnapshotService } from '../services/profile-snapshot-service.js';
|
|
2
|
+
import type { ProfileApplyService } from '../services/profile/profile-apply-service.js';
|
|
3
|
+
import type { ProfileExportService } from '../services/profile/profile-export-service.js';
|
|
4
|
+
import type { ProfileImportService } from '../services/profile/profile-import-service.js';
|
|
5
|
+
import type { ProfileService } from '../services/profile/profile-service.js';
|
|
6
|
+
import type { ProfileSnapshotService } from '../services/profile/profile-snapshot-service.js';
|
|
7
7
|
export interface ProfileCommandServices {
|
|
8
8
|
profileService: ProfileService;
|
|
9
9
|
profileExportService: ProfileExportService;
|
package/dist/commands/profile.js
CHANGED
|
@@ -131,7 +131,7 @@ export function registerProfileCommand(program, services) {
|
|
|
131
131
|
throw new Error('Provide --agent <claude|codex|gemini>.');
|
|
132
132
|
}
|
|
133
133
|
const agent = options.agent;
|
|
134
|
-
const { defaultBackupProfileName } = await import('../services/profile-snapshot-service.js');
|
|
134
|
+
const { defaultBackupProfileName } = await import('../services/profile/profile-snapshot-service.js');
|
|
135
135
|
const profileName = options.as ?? defaultBackupProfileName(agent);
|
|
136
136
|
const result = await profileSnapshotService.execute({
|
|
137
137
|
cwd: process.cwd(),
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
|
-
import type { StatusService } from '../services/status-service.js';
|
|
2
|
+
import type { StatusService } from '../services/platform/status-service.js';
|
|
3
3
|
export declare function registerStatusCommand(program: Command, statusService: StatusService): void;
|
|
@@ -2,17 +2,17 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { FastMCP } from 'fastmcp';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
import { createAgentConfigService } from '
|
|
6
|
-
import { createDoctorService } from '
|
|
7
|
-
import { startUiServer } from '
|
|
8
|
-
import { createProfileExportService } from '
|
|
9
|
-
import { createProfileImportService } from '
|
|
10
|
-
import { createProfileApplyService } from '
|
|
11
|
-
import { createProfileService } from '
|
|
12
|
-
import { createProfileSnapshotService, defaultBackupProfileName, } from '
|
|
13
|
-
import { createStatusService } from '
|
|
5
|
+
import { createAgentConfigService } from './services/agent/agent-config-service.js';
|
|
6
|
+
import { createDoctorService } from './services/platform/doctor-service.js';
|
|
7
|
+
import { startUiServer } from './ui/server.js';
|
|
8
|
+
import { createProfileExportService } from './services/profile/profile-export-service.js';
|
|
9
|
+
import { createProfileImportService } from './services/profile/profile-import-service.js';
|
|
10
|
+
import { createProfileApplyService } from './services/profile/profile-apply-service.js';
|
|
11
|
+
import { createProfileService } from './services/profile/profile-service.js';
|
|
12
|
+
import { createProfileSnapshotService, defaultBackupProfileName, } from './services/profile/profile-snapshot-service.js';
|
|
13
|
+
import { createStatusService } from './services/platform/status-service.js';
|
|
14
14
|
const ALL_AGENTS = ['claude', 'codex', 'gemini'];
|
|
15
|
-
const packageVersion = JSON.parse(readFileSync(new URL('
|
|
15
|
+
const packageVersion = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
16
16
|
export function createMcpServer(options = {}) {
|
|
17
17
|
const cwd = options.cwd ?? process.cwd();
|
|
18
18
|
const uiState = options.uiServerState ?? { current: null };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { PortablePluginSnapshot, PortableUserSkillSnapshot } from '
|
|
1
|
+
import type { PortablePluginSnapshot, PortableUserSkillSnapshot } from '../../types.js';
|
|
2
2
|
export declare function installPlugin(sourceDir: string, plugin: PortablePluginSnapshot): Promise<void>;
|
|
3
3
|
export declare function installUserSkill(sourceDir: string, skill: PortableUserSkillSnapshot): Promise<void>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { copyFile, cp, mkdir, readFile, rename, rm, stat, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import { ProfileError } from '
|
|
5
|
-
import { formatTimestamp } from '
|
|
4
|
+
import { ProfileError } from '../../errors.js';
|
|
5
|
+
import { formatTimestamp } from '../sync/agent-writer.js';
|
|
6
6
|
export async function installPlugin(sourceDir, plugin) {
|
|
7
7
|
try {
|
|
8
8
|
await stat(sourceDir);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { AgentName } from '
|
|
2
|
-
import { type AgentLiveConfig, type AgentMcpEntry, type PortableRemoteMcpMetadata } from '
|
|
3
|
-
import { type McpPreflightService } from '
|
|
4
|
-
import { type SkillPreflightService } from '
|
|
5
|
-
export type { AgentLiveConfig, AgentMcpEntry, AgentSkillEntry } from '
|
|
6
|
-
export type { PortableRemoteMcpMetadata } from '
|
|
1
|
+
import type { AgentName } from '../../types.js';
|
|
2
|
+
import { type AgentLiveConfig, type AgentMcpEntry, type PortableRemoteMcpMetadata } from '../sync/agent-reader.js';
|
|
3
|
+
import { type McpPreflightService } from '../platform/mcp-preflight-service.js';
|
|
4
|
+
import { type SkillPreflightService } from '../plugin/skill-preflight-service.js';
|
|
5
|
+
export type { AgentLiveConfig, AgentMcpEntry, AgentSkillEntry } from '../sync/agent-reader.js';
|
|
6
|
+
export type { PortableRemoteMcpMetadata } from '../sync/agent-reader.js';
|
|
7
7
|
export interface AgentConfigService {
|
|
8
8
|
readAll(options: {
|
|
9
9
|
cwd: string;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { copyFile, cp, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import { ValidationError } from '
|
|
5
|
-
import { createClaudeReader, createCodexReader, createGeminiReader, } from '
|
|
6
|
-
import { formatTimestamp } from '
|
|
7
|
-
import { createMcpPreflightService } from '
|
|
8
|
-
import { createSkillPreflightService } from '
|
|
9
|
-
import { getSkillDir } from '
|
|
4
|
+
import { ValidationError } from '../../errors.js';
|
|
5
|
+
import { createClaudeReader, createCodexReader, createGeminiReader, } from '../sync/agent-reader.js';
|
|
6
|
+
import { formatTimestamp } from '../sync/agent-writer.js';
|
|
7
|
+
import { createMcpPreflightService } from '../platform/mcp-preflight-service.js';
|
|
8
|
+
import { createSkillPreflightService } from '../plugin/skill-preflight-service.js';
|
|
9
|
+
import { getSkillDir } from '../plugin/skill-paths.js';
|
|
10
10
|
const readers = {
|
|
11
11
|
claude: createClaudeReader(),
|
|
12
12
|
codex: createCodexReader(),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServerConfig, PortableCredentialSpec } from '
|
|
1
|
+
import type { McpServerConfig, PortableCredentialSpec } from '../../types.js';
|
|
2
2
|
export interface CredentialRedactionResult<T extends McpServerConfig> {
|
|
3
3
|
redacted: T;
|
|
4
4
|
credentials: PortableCredentialSpec[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServerConfig, PortableCredentialPlaceholder, PortableCredentialSpec } from '
|
|
1
|
+
import type { McpServerConfig, PortableCredentialPlaceholder, PortableCredentialSpec } from '../../types.js';
|
|
2
2
|
export interface CredentialResolutionResult<T extends McpServerConfig> {
|
|
3
3
|
resolved: T;
|
|
4
4
|
missing: PortableCredentialSpec[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type AgentAvailabilityService } from '
|
|
2
|
-
import type { DiagnosticCheck } from '
|
|
1
|
+
import { type AgentAvailabilityService } from '../agent/agent-availability-service.js';
|
|
2
|
+
import type { DiagnosticCheck } from '../../types.js';
|
|
3
3
|
export interface DoctorResult {
|
|
4
4
|
checks: DiagnosticCheck[];
|
|
5
5
|
hasIssues: boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createAgentAvailabilityService, } from '
|
|
1
|
+
import { createAgentAvailabilityService, } from '../agent/agent-availability-service.js';
|
|
2
2
|
export function createDoctorService(dependencies = {}) {
|
|
3
3
|
const availabilityService = dependencies.availabilityService ?? createAgentAvailabilityService();
|
|
4
4
|
return {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { AgentName } from '
|
|
2
|
-
import type { AgentMcpEntry, PortableRemoteMcpMetadata } from '
|
|
1
|
+
import type { AgentName } from '../../types.js';
|
|
2
|
+
import type { AgentMcpEntry, PortableRemoteMcpMetadata } from '../agent/agent-config-service.js';
|
|
3
3
|
export interface McpPreflightCheck {
|
|
4
4
|
label: string;
|
|
5
5
|
status: 'ok' | 'warn' | 'error';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { stat } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { findExecutable } from '
|
|
3
|
+
import { findExecutable } from '../../executables.js';
|
|
4
4
|
const ENTRYPOINT_RUNNERS = new Set(['node', 'nodejs', 'python', 'python3', 'bash', 'sh', 'zsh', 'deno', 'bun']);
|
|
5
5
|
const SUPPORTED_LOCAL_LAUNCHERS = ['npx', 'uvx', 'node', 'python', 'python3', 'java -jar', 'go run', 'cargo run', 'and local binaries/scripts'];
|
|
6
6
|
export function createMcpPreflightService(dependencies = {}) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpRuntime } from '
|
|
1
|
+
import type { McpRuntime } from '../../types.js';
|
|
2
2
|
export declare function detectMcpRuntime(command: string): McpRuntime | null;
|
|
3
3
|
export declare function extractEntrypoint(command: string, args: string[]): string | null;
|
|
4
4
|
export declare function findProjectRoot(entrypointPath: string, runtime: McpRuntime): {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type AgentAvailability, type AgentAvailabilityService } from '
|
|
2
|
-
import { type ProfileService } from '
|
|
3
|
-
import type { AgentName } from '
|
|
1
|
+
import { type AgentAvailability, type AgentAvailabilityService } from '../agent/agent-availability-service.js';
|
|
2
|
+
import { type ProfileService } from '../profile/profile-service.js';
|
|
3
|
+
import type { AgentName } from '../../types.js';
|
|
4
4
|
export interface StatusResult {
|
|
5
5
|
agents: Record<AgentName, AgentAvailability>;
|
|
6
6
|
profiles: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createAgentAvailabilityService, } from '
|
|
2
|
-
import { createProfileService } from '
|
|
1
|
+
import { createAgentAvailabilityService, } from '../agent/agent-availability-service.js';
|
|
2
|
+
import { createProfileService } from '../profile/profile-service.js';
|
|
3
3
|
export function createStatusService(dependencies = {}) {
|
|
4
4
|
const availabilityService = dependencies.availabilityService ?? createAgentAvailabilityService();
|
|
5
5
|
const profileService = dependencies.profileService ?? createProfileService();
|
|
@@ -9,7 +9,7 @@ const execFileAsync = promisify(execFile);
|
|
|
9
9
|
const CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
10
10
|
const CACHE_DIR = path.join(homedir(), '.brainctl');
|
|
11
11
|
const CACHE_PATH = path.join(CACHE_DIR, 'update-check.json');
|
|
12
|
-
const packageVersion = JSON.parse(readFileSync(new URL('
|
|
12
|
+
const packageVersion = JSON.parse(readFileSync(new URL('../../../package.json', import.meta.url), 'utf8'));
|
|
13
13
|
export function createUpdateCheckService(dependencies = {}) {
|
|
14
14
|
const currentVersion = dependencies.currentVersion ?? packageVersion.version;
|
|
15
15
|
const fetchLatestVersion = dependencies.fetchLatestVersion ?? fetchFromRegistry;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AgentName } from '../../types.js';
|
|
2
|
+
import type { AgentMcpEntry } from '../agent/agent-config-service.js';
|
|
3
|
+
export interface PluginBundleAgent {
|
|
4
|
+
name: string;
|
|
5
|
+
sourceFormat: 'claude-md' | 'codex-toml';
|
|
6
|
+
content: string;
|
|
7
|
+
}
|
|
8
|
+
export interface PluginBundleCommand {
|
|
9
|
+
name: string;
|
|
10
|
+
content: string;
|
|
11
|
+
}
|
|
12
|
+
export interface PluginBundle {
|
|
13
|
+
skills: string[];
|
|
14
|
+
mcps: Record<string, AgentMcpEntry>;
|
|
15
|
+
agents: PluginBundleAgent[];
|
|
16
|
+
commands: PluginBundleCommand[];
|
|
17
|
+
}
|
|
18
|
+
export declare function isAgentInstallableOnTarget(target: AgentName): boolean;
|
|
19
|
+
export declare function isCommandInstallableOnTarget(target: AgentName): boolean;
|
|
20
|
+
export declare function defaultReadInstalledPluginBundle(installPath: string): Promise<PluginBundle>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export function isAgentInstallableOnTarget(target) {
|
|
4
|
+
return target === 'claude' || target === 'codex';
|
|
5
|
+
}
|
|
6
|
+
export function isCommandInstallableOnTarget(target) {
|
|
7
|
+
return target === 'claude' || target === 'codex';
|
|
8
|
+
}
|
|
9
|
+
export async function defaultReadInstalledPluginBundle(installPath) {
|
|
10
|
+
const skillsDir = path.join(installPath, 'skills');
|
|
11
|
+
let skills = [];
|
|
12
|
+
try {
|
|
13
|
+
const entries = await readdir(skillsDir, { withFileTypes: true });
|
|
14
|
+
skills = entries
|
|
15
|
+
.filter((entry) => !entry.name.startsWith('.') && entry.isDirectory())
|
|
16
|
+
.map((entry) => entry.name)
|
|
17
|
+
.sort((left, right) => left.localeCompare(right));
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
skills = [];
|
|
21
|
+
}
|
|
22
|
+
let mcps = {};
|
|
23
|
+
try {
|
|
24
|
+
const mcpSource = await readFile(path.join(installPath, '.mcp.json'), 'utf8');
|
|
25
|
+
const parsed = JSON.parse(mcpSource);
|
|
26
|
+
mcps = Object.fromEntries(Object.entries(parsed)
|
|
27
|
+
.filter(([, value]) => typeof value?.command === 'string')
|
|
28
|
+
.map(([key, value]) => [
|
|
29
|
+
key,
|
|
30
|
+
{
|
|
31
|
+
command: String(value.command),
|
|
32
|
+
args: Array.isArray(value.args) ? value.args.map(String) : undefined,
|
|
33
|
+
env: value.env && typeof value.env === 'object' && !Array.isArray(value.env)
|
|
34
|
+
? Object.fromEntries(Object.entries(value.env).map(([envKey, envValue]) => [
|
|
35
|
+
envKey,
|
|
36
|
+
String(envValue),
|
|
37
|
+
]))
|
|
38
|
+
: undefined,
|
|
39
|
+
},
|
|
40
|
+
]));
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
mcps = {};
|
|
44
|
+
}
|
|
45
|
+
const agents = [];
|
|
46
|
+
try {
|
|
47
|
+
const entries = await readdir(path.join(installPath, 'agents'), { withFileTypes: true });
|
|
48
|
+
for (const entry of entries) {
|
|
49
|
+
if (!entry.isFile())
|
|
50
|
+
continue;
|
|
51
|
+
if (entry.name.endsWith('.md')) {
|
|
52
|
+
const content = await readFile(path.join(installPath, 'agents', entry.name), 'utf8');
|
|
53
|
+
agents.push({ name: entry.name.replace(/\.md$/, ''), sourceFormat: 'claude-md', content });
|
|
54
|
+
}
|
|
55
|
+
else if (entry.name.endsWith('.toml')) {
|
|
56
|
+
const content = await readFile(path.join(installPath, 'agents', entry.name), 'utf8');
|
|
57
|
+
agents.push({ name: entry.name.replace(/\.toml$/, ''), sourceFormat: 'codex-toml', content });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
agents.sort((left, right) => left.name.localeCompare(right.name));
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// no agents dir
|
|
64
|
+
}
|
|
65
|
+
const commands = [];
|
|
66
|
+
try {
|
|
67
|
+
const entries = await readdir(path.join(installPath, 'commands'), { withFileTypes: true });
|
|
68
|
+
for (const entry of entries) {
|
|
69
|
+
if (!entry.isFile() || !entry.name.endsWith('.md'))
|
|
70
|
+
continue;
|
|
71
|
+
const content = await readFile(path.join(installPath, 'commands', entry.name), 'utf8');
|
|
72
|
+
commands.push({ name: entry.name.replace(/\.md$/, ''), content });
|
|
73
|
+
}
|
|
74
|
+
commands.sort((left, right) => left.name.localeCompare(right.name));
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// no commands dir
|
|
78
|
+
}
|
|
79
|
+
return { skills, mcps, agents, commands };
|
|
80
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AgentName } from '../../types.js';
|
|
2
|
+
import type { PluginInstallCheck } from './plugin-install-service.js';
|
|
3
|
+
export interface IncompatibleArtifacts {
|
|
4
|
+
hasAppConnector: boolean;
|
|
5
|
+
hasHooks: boolean;
|
|
6
|
+
hasCommands: boolean;
|
|
7
|
+
codexAgentSkills: string[];
|
|
8
|
+
claudeAgents: string[];
|
|
9
|
+
}
|
|
10
|
+
export declare function pathExists(target: string): Promise<boolean>;
|
|
11
|
+
export declare function detectIncompatibleArtifacts(installPath: string): Promise<IncompatibleArtifacts>;
|
|
12
|
+
export declare function formatCompatibilityWarnings(artifacts: IncompatibleArtifacts, context: {
|
|
13
|
+
sourceAgent: AgentName;
|
|
14
|
+
targetAgent: AgentName;
|
|
15
|
+
}): PluginInstallCheck[];
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { readdir, stat } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export async function pathExists(target) {
|
|
4
|
+
try {
|
|
5
|
+
await stat(target);
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export async function detectIncompatibleArtifacts(installPath) {
|
|
13
|
+
const [hasAppConnector, hasHooks, hasCommands, codexAgentSkills, claudeAgents] = await Promise.all([
|
|
14
|
+
pathExists(path.join(installPath, '.app.json')),
|
|
15
|
+
pathExists(path.join(installPath, 'hooks')),
|
|
16
|
+
pathExists(path.join(installPath, 'commands')),
|
|
17
|
+
listCodexAgentSkills(installPath),
|
|
18
|
+
listClaudeAgentFiles(installPath),
|
|
19
|
+
]);
|
|
20
|
+
return { hasAppConnector, hasHooks, hasCommands, codexAgentSkills, claudeAgents };
|
|
21
|
+
}
|
|
22
|
+
async function listCodexAgentSkills(installPath) {
|
|
23
|
+
const skillsDir = path.join(installPath, 'skills');
|
|
24
|
+
try {
|
|
25
|
+
const entries = await readdir(skillsDir, { withFileTypes: true });
|
|
26
|
+
const matches = [];
|
|
27
|
+
for (const entry of entries) {
|
|
28
|
+
if (!entry.isDirectory() || entry.name.startsWith('.'))
|
|
29
|
+
continue;
|
|
30
|
+
if (await pathExists(path.join(skillsDir, entry.name, 'agents'))) {
|
|
31
|
+
matches.push(entry.name);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return matches.sort((left, right) => left.localeCompare(right));
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function listClaudeAgentFiles(installPath) {
|
|
41
|
+
const agentsDir = path.join(installPath, 'agents');
|
|
42
|
+
try {
|
|
43
|
+
const entries = await readdir(agentsDir, { withFileTypes: true });
|
|
44
|
+
return entries
|
|
45
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
|
|
46
|
+
.map((entry) => entry.name.replace(/\.md$/, ''))
|
|
47
|
+
.sort((left, right) => left.localeCompare(right));
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function formatCompatibilityWarnings(artifacts, context) {
|
|
54
|
+
const warnings = [];
|
|
55
|
+
if (artifacts.hasAppConnector && context.targetAgent !== 'codex') {
|
|
56
|
+
warnings.push({
|
|
57
|
+
label: 'App connector',
|
|
58
|
+
status: 'warn',
|
|
59
|
+
message: `Plugin ships a Codex app connector (.app.json) that will NOT transfer. Skill instructions will copy over but the backing integration will not work on ${context.targetAgent}.`,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (artifacts.codexAgentSkills.length > 0 && context.targetAgent !== 'codex') {
|
|
63
|
+
warnings.push({
|
|
64
|
+
label: 'Codex agent YAML',
|
|
65
|
+
status: 'warn',
|
|
66
|
+
message: `Skills ${artifacts.codexAgentSkills.join(', ')} include Codex-specific agent YAML that will not transfer to ${context.targetAgent}.`,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
if (artifacts.hasHooks && context.targetAgent !== 'claude') {
|
|
70
|
+
warnings.push({
|
|
71
|
+
label: 'Claude hooks',
|
|
72
|
+
status: 'warn',
|
|
73
|
+
message: `Plugin ships session hooks that only work on Claude and will NOT transfer to ${context.targetAgent}.`,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
if (context.targetAgent === 'gemini' && artifacts.claudeAgents.length > 0) {
|
|
77
|
+
warnings.push({
|
|
78
|
+
label: 'Subagents',
|
|
79
|
+
status: 'warn',
|
|
80
|
+
message: `Plugin ships subagent definitions (${artifacts.claudeAgents.join(', ')}) that cannot be converted to ${context.targetAgent}.`,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
if (context.targetAgent === 'gemini' && artifacts.hasCommands) {
|
|
84
|
+
warnings.push({
|
|
85
|
+
label: 'Slash commands',
|
|
86
|
+
status: 'warn',
|
|
87
|
+
message: `Plugin ships slash commands that cannot be converted to ${context.targetAgent}.`,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return warnings;
|
|
91
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AgentName } from '../../types.js';
|
|
2
|
+
import type { PluginBundleAgent, PluginBundleCommand } from './plugin-install-bundle.js';
|
|
3
|
+
export declare function defaultInstallAgent(options: {
|
|
4
|
+
targetAgent: AgentName;
|
|
5
|
+
agent: PluginBundleAgent;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
export declare function defaultInstallCommand(options: {
|
|
8
|
+
targetAgent: AgentName;
|
|
9
|
+
command: PluginBundleCommand;
|
|
10
|
+
}): Promise<void>;
|
|
11
|
+
export declare function defaultRemoveAgentFile(options: {
|
|
12
|
+
targetAgent: AgentName;
|
|
13
|
+
agentName: string;
|
|
14
|
+
}): Promise<void>;
|
|
15
|
+
export declare function defaultRemoveCommandFile(options: {
|
|
16
|
+
targetAgent: AgentName;
|
|
17
|
+
commandName: string;
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
export declare function defaultCopySkillDirectory(options: {
|
|
20
|
+
sourceInstallPath: string;
|
|
21
|
+
skillName: string;
|
|
22
|
+
targetAgent: AgentName;
|
|
23
|
+
}): Promise<void>;
|
|
24
|
+
export declare function defaultRemoveSkillDirectory(options: {
|
|
25
|
+
targetAgent: AgentName;
|
|
26
|
+
skillName: string;
|
|
27
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { cp, mkdir, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { claudeAgentMdToCodexToml, claudeCommandMdToCodexSkill, codexAgentTomlToClaudeMd, } from '../agent/agent-converter-service.js';
|
|
4
|
+
import { getAgentFilePath, getCommandFilePath, getSkillDir } from './skill-paths.js';
|
|
5
|
+
export async function defaultInstallAgent(options) {
|
|
6
|
+
const targetPath = getAgentFilePath(options.targetAgent, options.agent.name);
|
|
7
|
+
await mkdir(path.dirname(targetPath), { recursive: true });
|
|
8
|
+
let output;
|
|
9
|
+
if (options.targetAgent === 'claude') {
|
|
10
|
+
output = options.agent.sourceFormat === 'claude-md'
|
|
11
|
+
? options.agent.content
|
|
12
|
+
: codexAgentTomlToClaudeMd(options.agent.content);
|
|
13
|
+
}
|
|
14
|
+
else if (options.targetAgent === 'codex') {
|
|
15
|
+
output = options.agent.sourceFormat === 'codex-toml'
|
|
16
|
+
? options.agent.content
|
|
17
|
+
: claudeAgentMdToCodexToml(options.agent.content);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
throw new Error(`Agent install is not supported for ${options.targetAgent}`);
|
|
21
|
+
}
|
|
22
|
+
await writeFile(targetPath, output, 'utf8');
|
|
23
|
+
}
|
|
24
|
+
export async function defaultInstallCommand(options) {
|
|
25
|
+
if (options.targetAgent === 'claude') {
|
|
26
|
+
const targetPath = getCommandFilePath('claude', options.command.name);
|
|
27
|
+
await mkdir(path.dirname(targetPath), { recursive: true });
|
|
28
|
+
await writeFile(targetPath, options.command.content, 'utf8');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (options.targetAgent === 'codex') {
|
|
32
|
+
const skillDir = getSkillDir('codex', options.command.name);
|
|
33
|
+
await mkdir(skillDir, { recursive: true });
|
|
34
|
+
const { skillMarkdown } = claudeCommandMdToCodexSkill(options.command.content);
|
|
35
|
+
await writeFile(path.join(skillDir, 'SKILL.md'), skillMarkdown, 'utf8');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
throw new Error(`Command install is not supported for ${options.targetAgent}`);
|
|
39
|
+
}
|
|
40
|
+
export async function defaultRemoveAgentFile(options) {
|
|
41
|
+
const targetPath = getAgentFilePath(options.targetAgent, options.agentName);
|
|
42
|
+
await rm(targetPath, { force: true });
|
|
43
|
+
}
|
|
44
|
+
export async function defaultRemoveCommandFile(options) {
|
|
45
|
+
if (options.targetAgent === 'claude') {
|
|
46
|
+
const targetPath = getCommandFilePath('claude', options.commandName);
|
|
47
|
+
await rm(targetPath, { force: true });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (options.targetAgent === 'codex') {
|
|
51
|
+
const skillDir = getSkillDir('codex', options.commandName);
|
|
52
|
+
await rm(skillDir, { recursive: true, force: true });
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export async function defaultCopySkillDirectory(options) {
|
|
57
|
+
const sourceDir = path.join(options.sourceInstallPath, 'skills', options.skillName);
|
|
58
|
+
const targetDir = getSkillDir(options.targetAgent, options.skillName);
|
|
59
|
+
await mkdir(path.dirname(targetDir), { recursive: true });
|
|
60
|
+
await cp(sourceDir, targetDir, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
export async function defaultRemoveSkillDirectory(options) {
|
|
63
|
+
const targetDir = getSkillDir(options.targetAgent, options.skillName);
|
|
64
|
+
await rm(targetDir, { recursive: true, force: true });
|
|
65
|
+
}
|