chittycan
Version:
Your completely autonomous network that grows with you - DNA ownership platform with encrypted vaults, PDX portability, and ChittyFoundation governance
629 lines (622 loc) • 15.6 kB
text/typescript
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import { configMenu } from "./commands/config.js";
import { open, listRemotes } from "./commands/open.js";
import { nudgeNow, nudgeQuiet } from "./commands/nudge.js";
import { checkpoint, listCheckpoints } from "./commands/checkpoint.js";
import { installZsh, uninstallZsh } from "./commands/hook.js";
import { syncSetup, syncRun, syncStatus } from "./commands/sync.js";
import { listExtensions, enableExtension, disableExtension, installExtension } from "./commands/extension.js";
import { PluginLoader } from "./lib/plugin.js";
import { doctor } from "./commands/doctor.js";
import { briefCommand } from "./commands/brief.js";
import { chittyCommand } from "./commands/chitty.js";
import {
listMcpServers,
startMcpServer,
stopMcpServer,
mcpServerStatus,
listMcpTools,
testMcpConnection
} from "./commands/mcp.js";
import { connectSetup, connectStatus, connectToken } from "./commands/connect.js";
import { generateMcpConfig, installMcpConfig } from "./commands/mcp-config.js";
import {
exportDNACommand,
importDNACommand,
dnaStatusCommand,
dnaHistoryCommand,
revokeDNACommand,
restoreDNACommand
} from "./commands/dna.js";
import { complianceReportCommand } from "./commands/compliance.js";
import {
analyticsCommand,
predictCommand,
suggestionsCommand,
learnCommand,
growthCommand
} from "./commands/grow.js";
// Load plugins early
const config = (await import("./lib/config.js")).loadConfig();
const pluginLoader = new PluginLoader(config);
await pluginLoader.loadAll();
// Check for direct CLI routing (can gh ... instead of can chitty gh ...)
const args = hideBin(process.argv);
const firstArg = args[0];
// Import CLI configs to check supported CLIs
const { CLI_CONFIGS } = await import("./commands/chitty.js");
// If first arg is a supported CLI, auto-route to chitty handler
if (firstArg && firstArg in CLI_CONFIGS) {
// This is a direct CLI command like "can gh clone repo"
// Route to chitty handler automatically
await chittyCommand(args);
process.exit(0);
}
yargs(args)
.scriptName("can")
.usage("$0 <command> [options]")
.command(
"config",
"Interactive configuration menu (rclone-style)",
() => {},
async () => {
await configMenu();
}
)
.command(
"brief",
"Show stemcell brief (what AI sees about this project)",
() => {},
async (argv) => {
await briefCommand(argv);
}
)
.command(
"chitty [args..]",
"Natural language command interpreter (AI-powered)",
(yargs) =>
yargs.positional("args", {
describe: "CLI and natural language command",
type: "string",
array: true
}),
async (argv) => {
const args = (argv.args as string[]) || [];
await chittyCommand(args);
}
)
.command(
"remote",
"Manage remotes",
(yargs) =>
yargs.command(
"list",
"List all configured remotes",
() => {},
() => {
listRemotes();
}
),
() => {
yargs.showHelp();
}
)
.command(
"open <name> [view]",
"Open a remote in browser",
(yargs) =>
yargs
.positional("name", {
describe: "Remote name",
type: "string",
demandOption: true
})
.positional("view", {
describe: "View name (optional)",
type: "string"
}),
(argv) => {
open(argv.name as string, argv.view as string);
}
)
.command(
"nudge",
"Reminder commands",
(yargs) =>
yargs
.command(
"now",
"Interactive nudge to update tracker",
() => {},
async () => {
await nudgeNow();
}
)
.command(
"quiet",
"Quick reminder (non-interactive)",
() => {},
() => {
nudgeQuiet();
}
),
() => {
yargs.showHelp();
}
)
.command(
"checkpoint [message]",
"Save a checkpoint with optional message",
(yargs) =>
yargs.positional("message", {
describe: "Checkpoint message",
type: "string"
}),
(argv) => {
checkpoint(argv.message as string);
}
)
.command(
"checkpoints [limit]",
"List recent checkpoints",
(yargs) =>
yargs.positional("limit", {
describe: "Number of checkpoints to show",
type: "number",
default: 10
}),
(argv) => {
listCheckpoints(argv.limit as number);
}
)
.command(
"hook",
"Manage shell hooks",
(yargs) =>
yargs
.command(
"install <shell>",
"Install shell hooks",
(yargs) =>
yargs.positional("shell", {
describe: "Shell type",
type: "string",
choices: ["zsh"],
demandOption: true
}),
(argv) => {
if (argv.shell === "zsh") {
installZsh();
}
}
)
.command(
"uninstall <shell>",
"Uninstall shell hooks",
(yargs) =>
yargs.positional("shell", {
describe: "Shell type",
type: "string",
choices: ["zsh"],
demandOption: true
}),
(argv) => {
if (argv.shell === "zsh") {
uninstallZsh();
}
}
),
() => {
yargs.showHelp();
}
)
.command(
"ext",
"Manage extensions",
(yargs) =>
yargs
.command(
"list",
"List installed extensions",
() => {},
async () => {
await listExtensions();
}
)
.command(
"install <name>",
"Install an extension",
(yargs) =>
yargs.positional("name", {
describe: "Extension name",
type: "string",
demandOption: true
}),
async (argv) => {
await installExtension(argv.name as string);
}
)
.command(
"enable <name>",
"Enable an extension",
(yargs) =>
yargs.positional("name", {
describe: "Extension name",
type: "string",
demandOption: true
}),
async (argv) => {
await enableExtension(argv.name as string);
}
)
.command(
"disable <name>",
"Disable an extension",
(yargs) =>
yargs.positional("name", {
describe: "Extension name",
type: "string",
demandOption: true
}),
async (argv) => {
await disableExtension(argv.name as string);
}
),
() => {
yargs.showHelp();
}
)
.command(
"doctor",
"Check environment and configuration",
() => {},
async () => {
await doctor();
}
)
.command(
"sync",
"Sync between Notion and GitHub",
(yargs) =>
yargs
.command(
"setup",
"Configure sync",
() => {},
async () => {
await syncSetup();
}
)
.command(
"run",
"Run sync now",
(yargs) =>
yargs.option("dry-run", {
describe: "Preview changes without applying",
type: "boolean",
default: false
}),
async (argv) => {
await syncRun(argv["dry-run"]);
}
)
.command(
"status",
"Show sync configuration",
() => {},
() => {
syncStatus();
}
),
() => {
yargs.showHelp();
}
)
.command(
"mcp",
"Manage MCP (Model Context Protocol) servers",
(yargs) =>
yargs
.command(
"list",
"List configured MCP servers",
() => {},
() => {
listMcpServers();
}
)
.command(
"start <name>",
"Start an MCP server",
(yargs) =>
yargs.positional("name", {
describe: "MCP server name",
type: "string",
demandOption: true
}),
(argv) => {
startMcpServer(argv.name as string);
}
)
.command(
"stop <name>",
"Stop an MCP server",
(yargs) =>
yargs.positional("name", {
describe: "MCP server name",
type: "string",
demandOption: true
}),
(argv) => {
stopMcpServer(argv.name as string);
}
)
.command(
"status <name>",
"Check MCP server status",
(yargs) =>
yargs.positional("name", {
describe: "MCP server name",
type: "string",
demandOption: true
}),
(argv) => {
mcpServerStatus(argv.name as string);
}
)
.command(
"tools <name>",
"List tools from MCP server",
(yargs) =>
yargs.positional("name", {
describe: "MCP server name",
type: "string",
demandOption: true
}),
async (argv) => {
await listMcpTools(argv.name as string);
}
)
.command(
"test <name>",
"Test connection to MCP server",
(yargs) =>
yargs.positional("name", {
describe: "MCP server name",
type: "string",
demandOption: true
}),
async (argv) => {
await testMcpConnection(argv.name as string);
}
),
() => {
yargs.showHelp();
}
)
.command(
"connect",
"ChittyConnect integration hub (MCP, GitHub, proxies)",
(yargs) =>
yargs
.command(
"setup",
"Quick setup with auto-detection",
() => {},
async () => {
await connectSetup();
}
)
.command(
"status",
"Show configuration",
() => {},
async () => {
await connectStatus();
}
)
.command(
"token [value]",
"Update API token",
(yargs) =>
yargs.positional("value", {
describe: "New token value (or prompt)",
type: "string"
}),
async (argv) => {
await connectToken(argv.value as string);
}
)
.command(
"mcp-config",
"Generate Claude Code MCP configuration",
() => {},
async () => {
await generateMcpConfig();
}
)
.command(
"mcp-install",
"Auto-install MCP config to Claude Code",
() => {},
async () => {
await installMcpConfig();
}
),
() => {
yargs.showHelp();
}
)
.command(
"dna",
"Manage your ChittyDNA (ownership, portability, attribution)",
(yargs) =>
yargs
.command(
"export",
"Export DNA in PDX format",
(yargs) =>
yargs
.option("privacy", {
type: "string",
choices: ["full", "hash-only"],
default: "full",
description: "Privacy mode"
})
.option("output", {
type: "string",
default: "~/chittycan-dna.json",
description: "Output file path"
}),
async (argv) => {
await exportDNACommand({
privacy: argv.privacy as "full" | "hash-only",
output: argv.output as string
});
}
)
.command(
"import <file>",
"Import DNA from PDX file",
(yargs) =>
yargs
.positional("file", {
describe: "PDX file path",
type: "string",
demandOption: true
})
.option("conflict-resolution", {
type: "string",
choices: ["merge", "replace", "rename", "skip"],
default: "merge",
description: "How to handle conflicting patterns"
}),
async (argv) => {
await importDNACommand({
file: argv.file as string,
conflictResolution: argv["conflict-resolution"] as "merge" | "replace" | "rename" | "skip"
});
}
)
.command(
"status",
"Show DNA statistics and top patterns",
() => {},
async () => {
await dnaStatusCommand();
}
)
.command(
"history",
"View DNA evolution history (snapshots)",
(yargs) =>
yargs.option("limit", {
type: "number",
default: 10,
description: "Number of snapshots to show"
}),
async (argv) => {
await dnaHistoryCommand({ limit: argv.limit });
}
)
.command(
"restore",
"Restore DNA from snapshot",
() => {},
async () => {
await restoreDNACommand();
}
)
.command(
"revoke",
"Revoke DNA (ethical exit)",
() => {},
async () => {
await revokeDNACommand();
}
),
() => {
yargs.showHelp();
}
)
.command(
"compliance",
"Generate Foundation compliance report",
() => {},
async () => {
await complianceReportCommand();
}
)
.command(
"analytics",
"Show usage analytics dashboard",
() => {},
() => {
analyticsCommand();
}
)
.command(
"predict",
"Show smart command predictions",
(yargs) =>
yargs.option("quiet", {
type: "boolean",
default: false,
description: "Only output top prediction (for shell integration)"
}),
async (argv) => {
await predictCommand({ quiet: argv.quiet });
}
)
.command(
"suggestions",
"Show workflow suggestions from repeated patterns",
() => {},
async () => {
await suggestionsCommand();
}
)
.command(
"learn <type> [args..]",
"Learning hook (called from shell - usually automatic)",
(yargs) =>
yargs
.positional("type", {
describe: "Learning type",
type: "string",
choices: ["command", "context", "git"],
demandOption: true
})
.positional("args", {
describe: "Additional arguments",
type: "string",
array: true
}),
async (argv) => {
await learnCommand(argv.type as any, (argv.args as string[]) || []);
}
)
.command(
"growth",
"Show growth stats (simplified analytics)",
() => {},
() => {
growthCommand();
}
)
.fail((msg, err, yargs) => {
// For errors, show help
if (msg) console.error(msg);
if (err) console.error(err);
yargs.showHelp();
process.exit(1);
})
.demandCommand(1, "You must provide a command")
.strict()
.help()
.alias("h", "help")
.version()
.alias("v", "version")
.parse();