@maccesar/titools 2.0.0

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.
Files changed (120) hide show
  1. package/AGENTS-TEMPLATE.md +173 -0
  2. package/README.md +867 -0
  3. package/agents/ti-researcher.md +108 -0
  4. package/bin/titools.js +53 -0
  5. package/lib/commands/agents.js +126 -0
  6. package/lib/commands/install.js +188 -0
  7. package/lib/commands/uninstall.js +215 -0
  8. package/lib/commands/update.js +159 -0
  9. package/lib/config.js +119 -0
  10. package/lib/downloader.js +153 -0
  11. package/lib/installer.js +253 -0
  12. package/lib/platform.js +108 -0
  13. package/lib/symlink.js +142 -0
  14. package/lib/utils.js +270 -0
  15. package/package.json +67 -0
  16. package/skills/alloy-expert/SKILL.md +247 -0
  17. package/skills/alloy-expert/assets/ControllerAutoCleanup.js +182 -0
  18. package/skills/alloy-expert/references/alloy-structure.md +381 -0
  19. package/skills/alloy-expert/references/anti-patterns.md +133 -0
  20. package/skills/alloy-expert/references/code-conventions.md +469 -0
  21. package/skills/alloy-expert/references/contracts.md +280 -0
  22. package/skills/alloy-expert/references/controller-patterns.md +520 -0
  23. package/skills/alloy-expert/references/error-handling.md +484 -0
  24. package/skills/alloy-expert/references/examples.md +735 -0
  25. package/skills/alloy-expert/references/migration-patterns.md +298 -0
  26. package/skills/alloy-expert/references/patterns.md +448 -0
  27. package/skills/alloy-expert/references/performance-patterns.md +855 -0
  28. package/skills/alloy-expert/references/security-patterns.md +847 -0
  29. package/skills/alloy-expert/references/state-management.md +779 -0
  30. package/skills/alloy-expert/references/testing.md +872 -0
  31. package/skills/alloy-guides/SKILL.md +214 -0
  32. package/skills/alloy-guides/references/CLI_TASKS.md +243 -0
  33. package/skills/alloy-guides/references/CONCEPTS.md +191 -0
  34. package/skills/alloy-guides/references/CONTROLLERS.md +298 -0
  35. package/skills/alloy-guides/references/MODELS.md +1028 -0
  36. package/skills/alloy-guides/references/PURGETSS.md +56 -0
  37. package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +242 -0
  38. package/skills/alloy-guides/references/VIEWS_STYLES.md +388 -0
  39. package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +109 -0
  40. package/skills/alloy-guides/references/VIEWS_XML.md +558 -0
  41. package/skills/alloy-guides/references/WIDGETS.md +176 -0
  42. package/skills/alloy-howtos/SKILL.md +203 -0
  43. package/skills/alloy-howtos/references/best_practices.md +138 -0
  44. package/skills/alloy-howtos/references/cli_reference.md +253 -0
  45. package/skills/alloy-howtos/references/config_files.md +87 -0
  46. package/skills/alloy-howtos/references/custom_tags.md +147 -0
  47. package/skills/alloy-howtos/references/debugging_troubleshooting.md +101 -0
  48. package/skills/alloy-howtos/references/samples.md +167 -0
  49. package/skills/purgetss/SKILL.md +442 -0
  50. package/skills/purgetss/assets/purgetss.config.cjs +17 -0
  51. package/skills/purgetss/references/EXAMPLES.md +247 -0
  52. package/skills/purgetss/references/animation-system.md +1294 -0
  53. package/skills/purgetss/references/apply-directive.md +375 -0
  54. package/skills/purgetss/references/arbitrary-values.md +612 -0
  55. package/skills/purgetss/references/class-index.md +1350 -0
  56. package/skills/purgetss/references/cli-commands.md +948 -0
  57. package/skills/purgetss/references/configurable-properties.md +654 -0
  58. package/skills/purgetss/references/custom-rules.md +161 -0
  59. package/skills/purgetss/references/customization-deep-dive.md +722 -0
  60. package/skills/purgetss/references/dynamic-component-creation.md +489 -0
  61. package/skills/purgetss/references/grid-layout.md +455 -0
  62. package/skills/purgetss/references/icon-fonts.md +609 -0
  63. package/skills/purgetss/references/installation-setup.md +366 -0
  64. package/skills/purgetss/references/opacity-modifier.md +291 -0
  65. package/skills/purgetss/references/platform-modifiers.md +479 -0
  66. package/skills/purgetss/references/smart-mappings.md +42 -0
  67. package/skills/purgetss/references/titanium-resets.md +359 -0
  68. package/skills/purgetss/references/ui-ux-design.md +1526 -0
  69. package/skills/ti-guides/SKILL.md +94 -0
  70. package/skills/ti-guides/references/advanced-data-and-images.md +19 -0
  71. package/skills/ti-guides/references/alloy-cli-advanced.md +84 -0
  72. package/skills/ti-guides/references/alloy-data-mastery.md +29 -0
  73. package/skills/ti-guides/references/alloy-widgets-and-themes.md +19 -0
  74. package/skills/ti-guides/references/android-manifest.md +97 -0
  75. package/skills/ti-guides/references/app-distribution.md +258 -0
  76. package/skills/ti-guides/references/application-frameworks.md +377 -0
  77. package/skills/ti-guides/references/cli-reference.md +402 -0
  78. package/skills/ti-guides/references/coding-best-practices.md +102 -0
  79. package/skills/ti-guides/references/commonjs-advanced.md +134 -0
  80. package/skills/ti-guides/references/hello-world.md +100 -0
  81. package/skills/ti-guides/references/hyperloop-native-access.md +62 -0
  82. package/skills/ti-guides/references/javascript-primer.md +411 -0
  83. package/skills/ti-guides/references/reserved-words.md +36 -0
  84. package/skills/ti-guides/references/resources.md +183 -0
  85. package/skills/ti-guides/references/style-and-conventions.md +48 -0
  86. package/skills/ti-guides/references/tiapp-config.md +609 -0
  87. package/skills/ti-howtos/SKILL.md +174 -0
  88. package/skills/ti-howtos/references/android-platform-deep-dives.md +658 -0
  89. package/skills/ti-howtos/references/automation-fastlane-appium.md +95 -0
  90. package/skills/ti-howtos/references/buffer-codec-streams.md +140 -0
  91. package/skills/ti-howtos/references/cross-platform-development.md +348 -0
  92. package/skills/ti-howtos/references/debugging-profiling.md +543 -0
  93. package/skills/ti-howtos/references/extending-titanium.md +723 -0
  94. package/skills/ti-howtos/references/google-maps-v2.md +169 -0
  95. package/skills/ti-howtos/references/ios-map-kit.md +143 -0
  96. package/skills/ti-howtos/references/ios-platform-deep-dives.md +783 -0
  97. package/skills/ti-howtos/references/local-data-sources.md +301 -0
  98. package/skills/ti-howtos/references/location-and-maps.md +252 -0
  99. package/skills/ti-howtos/references/media-apis.md +210 -0
  100. package/skills/ti-howtos/references/notification-services.md +599 -0
  101. package/skills/ti-howtos/references/remote-data-sources.md +349 -0
  102. package/skills/ti-howtos/references/tutorials.md +502 -0
  103. package/skills/ti-howtos/references/using-modules.md +237 -0
  104. package/skills/ti-howtos/references/web-content-integration.md +307 -0
  105. package/skills/ti-howtos/references/webpack-build-pipeline.md +78 -0
  106. package/skills/ti-ui/SKILL.md +179 -0
  107. package/skills/ti-ui/references/accessibility-deep-dive.md +242 -0
  108. package/skills/ti-ui/references/animation-and-matrices.md +599 -0
  109. package/skills/ti-ui/references/application-structures.md +655 -0
  110. package/skills/ti-ui/references/custom-fonts-styling.md +579 -0
  111. package/skills/ti-ui/references/event-handling.md +393 -0
  112. package/skills/ti-ui/references/gestures.md +473 -0
  113. package/skills/ti-ui/references/icons-and-splash-screens.md +409 -0
  114. package/skills/ti-ui/references/layouts-and-positioning.md +462 -0
  115. package/skills/ti-ui/references/listviews-and-performance.md +619 -0
  116. package/skills/ti-ui/references/orientation.md +362 -0
  117. package/skills/ti-ui/references/platform-ui-android.md +635 -0
  118. package/skills/ti-ui/references/platform-ui-ios.md +469 -0
  119. package/skills/ti-ui/references/scrolling-views.md +252 -0
  120. package/skills/ti-ui/references/tableviews.md +568 -0
@@ -0,0 +1,108 @@
1
+ ---
2
+ name: ti-researcher
3
+ description: Titanium SDK and Alloy research specialist. Preloads all 7 titanium-* skills for comprehensive analysis. Use proactively for: analyzing Titanium/Alloy codebases, reviewing Alloy app architecture, researching Titanium SDK implementations, exploring mobile app architectural questions, multi-feature research across Titanium APIs, cross-referencing framework patterns, or investigating platform-specific Titanium differences. Returns findings with specific file/line references from all documentation.
4
+ skills:
5
+ - alloy-expert
6
+ - alloy-guides
7
+ - alloy-howtos
8
+ - purgetss
9
+ - ti-guides
10
+ - ti-howtos
11
+ - ti-ui
12
+ tools: Read, Grep, Glob
13
+ model: sonnet
14
+ ---
15
+
16
+ # Titanium SDK Research Specialist
17
+
18
+ You are a deep-dive research specialist for Titanium SDK and Alloy mobile development.
19
+
20
+ ## What You Do
21
+
22
+ When invoked, you research complex topics by consulting **all 7 preloaded titanium-\*** skills:
23
+
24
+ - `alloy-expert` - Architecture, patterns, PurgeTSS conventions
25
+ - `alloy-guides` - Alloy MVC complete reference
26
+ - `alloy-howtos` - CLI, config, debugging
27
+ - `purgetss` - Utility-first styling classes
28
+ - `ti-guides` - SDK official guides, Hyperloop, distribution
29
+ - `ti-howtos` - Native features, platform-specific APIs
30
+ - `ti-ui` - UI/UX patterns, layouts, gestures
31
+
32
+ ## Research Process
33
+
34
+ 1. **Understand the query** - What specific aspect needs research?
35
+ 2. **Consult ALL relevant skills** - All skills are preloaded in your context
36
+ 3. **Cross-reference** - Find connections across multiple skills
37
+ 4. **Provide specifics** - Include file paths, line numbers, code examples
38
+ 5. **Cite sources** - Reference which skill and file each answer comes from
39
+
40
+ ## What You're Good For
41
+
42
+ | Use Case | Example |
43
+ | -------------------------- | ------------------------------------------------------------------ |
44
+ | **Codebase analysis** | "Analyze this Alloy app's architecture and identify anti-patterns" |
45
+ | **Multi-feature research** | "Research how to implement location + push + background sync" |
46
+ | **Cross-skills questions** | "Compare ListView vs TableView performance with PurgeTSS styling" |
47
+ | **Architecture review** | "Review this project's folder structure and service layer" |
48
+ | **Platform differences** | "Research iOS vs Android differences for this feature" |
49
+
50
+ ## What You're NOT For
51
+
52
+ | Use Instead | Reason |
53
+ | -------------------------------------------- | -------------------------------------- |
54
+ | `/alloy-expert` for architecture guidance | Inline consultation during development |
55
+ | `/purgetss` to verify a class | Quick inline reference |
56
+ | `/ti-howtos` for step-by-step implementation | Task-oriented guidance |
57
+ | Main conversation for iterative work | Sub-agents run in isolation |
58
+
59
+ ## Response Format
60
+
61
+ When returning research findings:
62
+
63
+ 1. **Summary** - Brief overview of findings
64
+ 2. **Key Points** - Bulleted list with specific references
65
+ 3. **Code Examples** - From the skills, with source citations
66
+ 4. **Related Skills** - Which skills were consulted
67
+ 5. **File References** - Specific `path:line` format
68
+
69
+ Example:
70
+ ```markdown
71
+ ## Summary
72
+ Your app uses `Ti.App.fireEvent` which causes memory leaks.
73
+
74
+ ## Key Points
75
+ - **alloy-expert/references/anti-patterns.md:45** - Ti.App.fireEvent leaks memory
76
+ - **alloy-howtos/references/best_practices.md:23** - Use Backbone.Events instead
77
+
78
+ ## Solution
79
+ [Code example from alloy-howtos]
80
+ ```
81
+
82
+ ## Tool Usage
83
+
84
+ You have **read-only tools**: `Read`, `Grep`, `Glob`
85
+
86
+ Use them to:
87
+ - Search the codebase when asked to analyze it
88
+ - Find patterns across multiple files
89
+ - Verify claims against actual code
90
+
91
+ You **cannot** modify files. If the user asks for changes, provide the research and suggest using the appropriate skill or main conversation for implementation.
92
+
93
+ ---
94
+
95
+ ## Usage Examples
96
+
97
+ **Automatic activation (proactive):**
98
+ - "Analyze this **Titanium Alloy** codebase and identify architectural anti-patterns"
99
+ - "Research the best way to implement location services in this **Titanium project**"
100
+ - "Do a comprehensive analysis of the UI patterns used in this **Alloy app**"
101
+ - "Explore the architecture of this **mobile app** and identify areas for improvement"
102
+
103
+ > **Tip**: Include words like "Titanium", "Alloy", "mobile app", or "architecture review" to ensure the agent is triggered for Titanium-specific analysis.
104
+
105
+ **Manual activation (always works):**
106
+ - "Use the ti-researcher agent to analyze this codebase"
107
+ - "Have ti-researcher investigate the architecture of this project"
108
+ - "Use ti-researcher to research platform-specific differences for this feature"
package/bin/titools.js ADDED
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * titools - Titanium SDK Skills CLI Tool
5
+ * Main entry point for the NPM package
6
+ */
7
+
8
+ import { Command } from 'commander';
9
+ import { PACKAGE_VERSION } from '../lib/config.js';
10
+ import { installCommand } from '../lib/commands/install.js';
11
+ import { agentsCommand } from '../lib/commands/agents.js';
12
+ import { updateCommand } from '../lib/commands/update.js';
13
+ import { uninstallCommand } from '../lib/commands/uninstall.js';
14
+
15
+ const program = new Command();
16
+
17
+ program
18
+ .name('titools')
19
+ .description('Titanium SDK Skills CLI - Manage skills and agents for AI coding assistants')
20
+ .version(PACKAGE_VERSION);
21
+
22
+ // Install command
23
+ program
24
+ .command('install')
25
+ .description('Install Titanium skills and agents to your AI coding assistant')
26
+ .option('-a, --all', 'Install to all detected platforms without prompting')
27
+ .option('--path <path>', 'Install to a custom path (skips symlink setup)')
28
+ .action(installCommand);
29
+
30
+ // Agents command
31
+ program
32
+ .command('agents')
33
+ .description('Add AGENTS.md/CLAUDE.md/GEMINI.md to your Titanium project')
34
+ .argument('[path]', 'Project path (defaults to current directory)', '.')
35
+ .option('-f, --force', 'Overwrite existing files without prompting')
36
+ .action(agentsCommand);
37
+
38
+ // Update command
39
+ program
40
+ .command('update')
41
+ .description('Update Titanium skills and docs to the latest version')
42
+ .action(updateCommand);
43
+
44
+ // Uninstall command
45
+ program
46
+ .command('uninstall')
47
+ .description('Remove Titanium skills and agents')
48
+ .action(uninstallCommand);
49
+
50
+ // Parse arguments
51
+ program.parse();
52
+
53
+ export { program };
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Agents command
3
+ * Adds AGENTS.md/CLAUDE.md/GEMINI.md to Titanium projects
4
+ */
5
+
6
+ import inquirer from 'inquirer';
7
+ import chalk from 'chalk';
8
+ import ora from 'ora';
9
+ import {
10
+ getAgentsDir,
11
+ getAgentsSkillsDir,
12
+ TITANIUM_PROJECT_FILE,
13
+ AI_FILE_PRIORITIES,
14
+ } from '../config.js';
15
+ import {
16
+ isTitaniumProject,
17
+ detectTitaniumVersion,
18
+ getAIFiles,
19
+ determineFilesToUpdate,
20
+ addOrUpdateBlock,
21
+ } from '../utils.js';
22
+ import { existsSync, writeFileSync } from 'fs';
23
+ import { join, resolve } from 'path';
24
+
25
+ /**
26
+ * Agents command handler
27
+ * @param {string} projectPath - Project path argument
28
+ * @param {Object} options - Command options
29
+ */
30
+ export async function agentsCommand(projectPath, options) {
31
+ console.log('');
32
+ console.log(chalk.bold.blue('Titanium AGENTS.md Installer'));
33
+ console.log('');
34
+
35
+ // Resolve project path
36
+ const projectDir = resolve(projectPath);
37
+
38
+ // Verify skills are installed (needed for building index)
39
+ const agentsSkillsDir = getAgentsSkillsDir();
40
+ if (!existsSync(agentsSkillsDir)) {
41
+ console.log(chalk.red('Error: Skills not installed'));
42
+ console.log('Install titools first:');
43
+ console.log(' titools install');
44
+ console.log('');
45
+ console.log('This command needs access to Titanium skills to build the documentation index.');
46
+ process.exit(1);
47
+ }
48
+
49
+ // Verify this is a Titanium project
50
+ if (!isTitaniumProject(projectDir)) {
51
+ console.log(chalk.red('Error: Not a Titanium project (no tiapp.xml)'));
52
+ console.log('Run this command from your project root.');
53
+ process.exit(1);
54
+ }
55
+
56
+ // Detect Titanium version
57
+ const tiVersion = detectTitaniumVersion(projectDir);
58
+ console.log(chalk.green('✓'), `Titanium project (SDK ${tiVersion})`);
59
+ console.log('');
60
+
61
+ // Check which AI files exist
62
+ const aiFiles = getAIFiles(projectDir);
63
+
64
+ // Determine which files to update
65
+ let filesToUpdate = determineFilesToUpdate(aiFiles);
66
+
67
+ // If no files exist, ask which AI they use
68
+ if (filesToUpdate.length === 0) {
69
+ if (options.force) {
70
+ // Default to CLAUDE.md if force mode
71
+ filesToUpdate = ['CLAUDE.md'];
72
+ } else {
73
+ const answers = await inquirer.prompt([
74
+ {
75
+ type: 'list',
76
+ name: 'ai',
77
+ message: 'Which AI assistant are you using?',
78
+ choices: [
79
+ { name: 'Claude Code (creates CLAUDE.md)', value: 'CLAUDE.md' },
80
+ { name: 'Gemini CLI (creates GEMINI.md)', value: 'GEMINI.md' },
81
+ { name: 'Cursor/Copilot (creates AGENTS.md)', value: 'AGENTS.md' },
82
+ ],
83
+ },
84
+ ]);
85
+ filesToUpdate = [answers.ai];
86
+ }
87
+ }
88
+
89
+ // Update each file
90
+ const spinner = ora();
91
+ const updated = [];
92
+
93
+ for (const filename of filesToUpdate) {
94
+ const filePath = join(projectDir, filename);
95
+
96
+ // Create file if it doesn't exist
97
+ if (!existsSync(filePath)) {
98
+ writeFileSync(filePath, '', 'utf8');
99
+ }
100
+
101
+ spinner.start(`Updating ${filename}...`);
102
+
103
+ try {
104
+ addOrUpdateBlock(filePath);
105
+ spinner.succeed(`${filename} updated`);
106
+ updated.push(filename);
107
+ } catch (error) {
108
+ spinner.fail(`Failed to update ${filename}: ${error.message}`);
109
+ }
110
+ }
111
+
112
+ console.log('');
113
+ console.log(chalk.green('✓'), `Done! Updated: ${updated.join(', ')}`);
114
+ console.log('');
115
+
116
+ // Show notes for multiple files
117
+ if (updated.length > 1) {
118
+ console.log(
119
+ chalk.cyan('Note:'),
120
+ `Updated ${updated.length} files - Titanium knowledge synced across all.`
121
+ );
122
+ console.log('');
123
+ }
124
+ }
125
+
126
+ export default agentsCommand;
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Install command
3
+ * Installs skills and agents to AI coding assistant directories
4
+ */
5
+
6
+ import inquirer from 'inquirer';
7
+ import chalk from 'chalk';
8
+ import ora from 'ora';
9
+ import {
10
+ SKILLS,
11
+ AGENTS,
12
+ REPO_URL,
13
+ } from '../config.js';
14
+ import {
15
+ detectPlatforms,
16
+ detectOS,
17
+ } from '../platform.js';
18
+ import {
19
+ installSkills,
20
+ installAgents,
21
+ installAgentsTemplate,
22
+ getLocalRepoDir,
23
+ } from '../installer.js';
24
+ import { downloadRepoArchive } from '../downloader.js';
25
+ import { createSkillSymlinks } from '../symlink.js';
26
+ import { formatList } from '../utils.js';
27
+ import { mkdtemp } from 'fs/promises';
28
+ import { join } from 'path';
29
+ import { tmpdir } from 'os';
30
+
31
+ /**
32
+ * Install command handler
33
+ * @param {Object} options - Command options
34
+ */
35
+ export async function installCommand(options) {
36
+ console.log('');
37
+ console.log(chalk.bold.blue('Titanium SDK Skills Installer'));
38
+ console.log('');
39
+
40
+ // Detect installed platforms
41
+ const detectedPlatforms = detectPlatforms();
42
+
43
+ if (detectedPlatforms.length === 0 && !options.path) {
44
+ console.log(chalk.yellow('No AI coding assistants detected.'));
45
+ console.log('Install one of: Claude Code, Gemini CLI, or Codex CLI');
46
+ console.log('Or use: titools install --path /custom/path');
47
+ process.exit(1);
48
+ }
49
+
50
+ // Show detected platforms
51
+ for (const platform of detectedPlatforms) {
52
+ console.log(chalk.green('✓'), `${platform.displayName} detected`);
53
+ }
54
+ console.log('');
55
+
56
+ // Select platforms to install
57
+ let selectedPlatforms = [];
58
+
59
+ if (options.path) {
60
+ // Custom path mode - skip platform selection
61
+ selectedPlatforms = [];
62
+ } else if (options.all) {
63
+ // Install to all detected platforms
64
+ selectedPlatforms = detectedPlatforms;
65
+ } else {
66
+ // Interactive selection
67
+ const answers = await inquirer.prompt([
68
+ {
69
+ type: 'list',
70
+ name: 'platform',
71
+ message: 'Select platform to install:',
72
+ choices: [
73
+ { name: 'All detected platforms', value: 'all' },
74
+ ...detectedPlatforms.map((p) => ({
75
+ name: `${p.displayName} only`,
76
+ value: p.name,
77
+ })),
78
+ { name: 'Cancel', value: 'cancel' },
79
+ ],
80
+ },
81
+ ]);
82
+
83
+ if (answers.platform === 'cancel') {
84
+ console.log('Cancelled.');
85
+ process.exit(0);
86
+ }
87
+
88
+ if (answers.platform === 'all') {
89
+ selectedPlatforms = detectedPlatforms;
90
+ } else {
91
+ selectedPlatforms = detectedPlatforms.filter(
92
+ (p) => p.name === answers.platform
93
+ );
94
+ }
95
+ }
96
+
97
+ if (selectedPlatforms.length === 0 && !options.path) {
98
+ console.log('No platforms selected.');
99
+ process.exit(0);
100
+ }
101
+
102
+ // Get repository directory (local or download)
103
+ const spinner = ora();
104
+ let repoDir = getLocalRepoDir();
105
+
106
+ if (!repoDir) {
107
+ // Download from GitHub
108
+ spinner.start('Downloading from GitHub...');
109
+ try {
110
+ const tempDir = tmpdir();
111
+ repoDir = await mkdtemp(join(tempDir, 'titanium-skills-'));
112
+ await downloadRepoArchive(repoDir);
113
+ spinner.succeed('Downloaded from GitHub');
114
+ } catch (error) {
115
+ spinner.fail('Failed to download');
116
+ console.error(chalk.red(error.message));
117
+ process.exit(1);
118
+ }
119
+ } else {
120
+ console.log(chalk.green('Using local repository'));
121
+ }
122
+
123
+ try {
124
+ // Install skills
125
+ spinner.start('Installing skills...');
126
+ const skillsResult = await installSkills(repoDir);
127
+ spinner.succeed(
128
+ `Skills: ${formatList(skillsResult.installed)}`
129
+ );
130
+
131
+ // Install agents
132
+ spinner.start('Installing agents...');
133
+ const agentsResult = await installAgents(repoDir);
134
+ if (agentsResult.installed.length > 0) {
135
+ spinner.succeed(
136
+ `Agents: ${formatList(agentsResult.installed)}`
137
+ );
138
+ } else {
139
+ spinner.info('No agents to install (Claude Code not detected)');
140
+ }
141
+
142
+ // Install AGENTS-TEMPLATE.md
143
+ spinner.start('Installing AGENTS-TEMPLATE.md...');
144
+ const templateInstalled = await installAgentsTemplate(repoDir);
145
+ if (templateInstalled) {
146
+ spinner.succeed('AGENTS-TEMPLATE.md installed');
147
+ } else {
148
+ spinner.warn('AGENTS-TEMPLATE.md not found');
149
+ }
150
+
151
+ // Create symlinks for selected platforms
152
+ for (const platform of selectedPlatforms) {
153
+ spinner.start(`Linking ${platform.displayName}...`);
154
+ const symlinkResult = await createSkillSymlinks(
155
+ platform.skillsDir,
156
+ SKILLS
157
+ );
158
+ if (symlinkResult.linked.length === SKILLS.length) {
159
+ spinner.succeed(`${platform.displayName} linked`);
160
+ } else {
161
+ spinner.warn(
162
+ `${platform.displayName}: ${symlinkResult.linked.length}/${SKILLS.length} linked`
163
+ );
164
+ }
165
+ }
166
+
167
+ // Summary
168
+ console.log('');
169
+ console.log(chalk.green('✓ Installation complete!'));
170
+ console.log('');
171
+ console.log(chalk.bold('▸'), 'Add AGENTS.md to your project:', chalk.cyan('titools agents'));
172
+ console.log(chalk.bold('▸'), 'Improves AI:', chalk.red('53%'), '→', chalk.green('100%'));
173
+ console.log('');
174
+
175
+ if (detectOS() === 'windows') {
176
+ console.log(chalk.yellow('▸'), 'Windows: Ensure ~/bin is in your PATH');
177
+ console.log('');
178
+ }
179
+
180
+ } finally {
181
+ // Clean up temp directory if we downloaded
182
+ if (repoDir !== getLocalRepoDir() && repoDir.startsWith(tmpdir())) {
183
+ await import('fs-extra').then(({ remove }) => remove(repoDir));
184
+ }
185
+ }
186
+ }
187
+
188
+ export default installCommand;
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Uninstall command
3
+ * Removes installed skills and agents
4
+ */
5
+
6
+ import inquirer from 'inquirer';
7
+ import chalk from 'chalk';
8
+ import ora from 'ora';
9
+ import { SKILLS, AGENTS } from '../config.js';
10
+ import {
11
+ detectPlatforms,
12
+ } from '../platform.js';
13
+ import { remove } from 'fs-extra';
14
+ import { existsSync, rmSync } from 'fs';
15
+ import { join } from 'path';
16
+ import {
17
+ getAgentsSkillsDir,
18
+ getClaudeAgentsDir,
19
+ getClaudeSkillsDir,
20
+ getGeminiSkillsDir,
21
+ getCodexSkillsDir,
22
+ } from '../config.js';
23
+
24
+ /**
25
+ * Remove skill symlinks from a platform directory
26
+ * @param {string} platformSkillsDir - Platform skills directory
27
+ * @returns {Object} Results object with success/failure counts
28
+ */
29
+ function removeSkillSymlinks(platformSkillsDir) {
30
+ const results = {
31
+ removed: [],
32
+ failed: [],
33
+ };
34
+
35
+ if (!existsSync(platformSkillsDir)) {
36
+ return results;
37
+ }
38
+
39
+ for (const skill of SKILLS) {
40
+ const linkPath = join(platformSkillsDir, skill);
41
+
42
+ if (existsSync(linkPath)) {
43
+ try {
44
+ rmSync(linkPath, { recursive: true, force: true });
45
+ results.removed.push(skill);
46
+ } catch (error) {
47
+ results.failed.push(skill);
48
+ }
49
+ }
50
+ }
51
+
52
+ return results;
53
+ }
54
+
55
+ /**
56
+ * Remove skills from central directory
57
+ * @returns {Object} Results object
58
+ */
59
+ function removeSkills() {
60
+ const skillsDir = getAgentsSkillsDir();
61
+ const results = {
62
+ removed: [],
63
+ failed: [],
64
+ };
65
+
66
+ if (!existsSync(skillsDir)) {
67
+ return results;
68
+ }
69
+
70
+ for (const skill of SKILLS) {
71
+ const skillPath = join(skillsDir, skill);
72
+
73
+ if (existsSync(skillPath)) {
74
+ try {
75
+ rmSync(skillPath, { recursive: true, force: true });
76
+ results.removed.push(skill);
77
+ } catch (error) {
78
+ results.failed.push(skill);
79
+ }
80
+ }
81
+ }
82
+
83
+ return results;
84
+ }
85
+
86
+ /**
87
+ * Remove agents from Claude Code
88
+ * @returns {Object} Results object
89
+ */
90
+ function removeAgents() {
91
+ const agentsDir = getClaudeAgentsDir();
92
+ const results = {
93
+ removed: [],
94
+ failed: [],
95
+ };
96
+
97
+ if (!existsSync(agentsDir)) {
98
+ return results;
99
+ }
100
+
101
+ for (const agent of AGENTS) {
102
+ const agentPath = join(agentsDir, `${agent}.md`);
103
+
104
+ if (existsSync(agentPath)) {
105
+ try {
106
+ rmSync(agentPath);
107
+ results.removed.push(agent);
108
+ } catch (error) {
109
+ results.failed.push(agent);
110
+ }
111
+ }
112
+ }
113
+
114
+ return results;
115
+ }
116
+
117
+ /**
118
+ * Uninstall command handler
119
+ * @param {Object} options - Command options
120
+ */
121
+ export async function uninstallCommand(options) {
122
+ console.log('');
123
+ console.log(chalk.bold.blue('Titanium SDK Skills Uninstaller'));
124
+ console.log('');
125
+
126
+ // Detect installed platforms
127
+ const detectedPlatforms = detectPlatforms();
128
+
129
+ if (detectedPlatforms.length === 0) {
130
+ console.log(chalk.yellow('No AI coding assistants detected.'));
131
+ console.log('However, you can still remove skills from the central directory.');
132
+ console.log('');
133
+ }
134
+
135
+ // Show detected platforms
136
+ for (const platform of detectedPlatforms) {
137
+ console.log(chalk.green('✓'), `${platform.displayName} detected`);
138
+ }
139
+ console.log('');
140
+
141
+ // Select what to uninstall
142
+ const answers = await inquirer.prompt([
143
+ {
144
+ type: 'checkbox',
145
+ name: 'targets',
146
+ message: 'What do you want to uninstall?',
147
+ choices: [
148
+ { name: 'Skill symlinks from all platforms', value: 'symlinks', checked: true },
149
+ { name: 'Skills from central directory (~/.agents/skills/)', value: 'skills', checked: false },
150
+ { name: 'Agents from Claude Code', value: 'agents', checked: false },
151
+ ],
152
+ validate: (answer) => answer.length > 0 || 'Please select at least one option',
153
+ },
154
+ ]);
155
+
156
+ if (answers.targets.includes('symlinks') && detectedPlatforms.length === 0) {
157
+ console.log(chalk.yellow('No platforms detected, skipping symlink removal.'));
158
+ answers.targets = answers.targets.filter((t) => t !== 'symlinks');
159
+ }
160
+
161
+ if (answers.targets.length === 0) {
162
+ console.log('Nothing to uninstall.');
163
+ process.exit(0);
164
+ }
165
+
166
+ const spinner = ora();
167
+
168
+ // Remove symlinks from platforms
169
+ if (answers.targets.includes('symlinks')) {
170
+ for (const platform of detectedPlatforms) {
171
+ spinner.start(`Removing ${platform.displayName} symlinks...`);
172
+ const symlinkResult = removeSkillSymlinks(platform.skillsDir);
173
+
174
+ if (symlinkResult.removed.length > 0) {
175
+ spinner.succeed(`${platform.displayName}: ${symlinkResult.removed.length} removed`);
176
+ } else {
177
+ spinner.info(`${platform.displayName}: No symlinks found`);
178
+ }
179
+ }
180
+ }
181
+
182
+ // Remove skills from central directory
183
+ if (answers.targets.includes('skills')) {
184
+ spinner.start('Removing skills from central directory...');
185
+ const skillsResult = removeSkills();
186
+
187
+ if (skillsResult.removed.length > 0) {
188
+ spinner.succeed(`Skills: ${skillsResult.removed.join(', ')}`);
189
+ } else {
190
+ spinner.info('No skills found in central directory');
191
+ }
192
+ }
193
+
194
+ // Remove agents
195
+ if (answers.targets.includes('agents')) {
196
+ spinner.start('Removing agents...');
197
+ const agentsResult = removeAgents();
198
+
199
+ if (agentsResult.removed.length > 0) {
200
+ spinner.succeed(`Agents: ${agentsResult.removed.join(', ')}`);
201
+ } else {
202
+ spinner.info('No agents found');
203
+ }
204
+ }
205
+
206
+ console.log('');
207
+ console.log(chalk.green('✓ Uninstallation complete!'));
208
+ console.log('');
209
+ console.log(chalk.gray('Note: AGENTS.md/CLAUDE.md/GEMINI.md files in your projects were NOT removed.'));
210
+ console.log(chalk.gray('To remove them manually:'));
211
+ console.log(chalk.gray(' rm -f /path/to/your/project/AGENTS.md'));
212
+ console.log('');
213
+ }
214
+
215
+ export default uninstallCommand;