@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.
- package/AGENTS-TEMPLATE.md +173 -0
- package/README.md +867 -0
- package/agents/ti-researcher.md +108 -0
- package/bin/titools.js +53 -0
- package/lib/commands/agents.js +126 -0
- package/lib/commands/install.js +188 -0
- package/lib/commands/uninstall.js +215 -0
- package/lib/commands/update.js +159 -0
- package/lib/config.js +119 -0
- package/lib/downloader.js +153 -0
- package/lib/installer.js +253 -0
- package/lib/platform.js +108 -0
- package/lib/symlink.js +142 -0
- package/lib/utils.js +270 -0
- package/package.json +67 -0
- package/skills/alloy-expert/SKILL.md +247 -0
- package/skills/alloy-expert/assets/ControllerAutoCleanup.js +182 -0
- package/skills/alloy-expert/references/alloy-structure.md +381 -0
- package/skills/alloy-expert/references/anti-patterns.md +133 -0
- package/skills/alloy-expert/references/code-conventions.md +469 -0
- package/skills/alloy-expert/references/contracts.md +280 -0
- package/skills/alloy-expert/references/controller-patterns.md +520 -0
- package/skills/alloy-expert/references/error-handling.md +484 -0
- package/skills/alloy-expert/references/examples.md +735 -0
- package/skills/alloy-expert/references/migration-patterns.md +298 -0
- package/skills/alloy-expert/references/patterns.md +448 -0
- package/skills/alloy-expert/references/performance-patterns.md +855 -0
- package/skills/alloy-expert/references/security-patterns.md +847 -0
- package/skills/alloy-expert/references/state-management.md +779 -0
- package/skills/alloy-expert/references/testing.md +872 -0
- package/skills/alloy-guides/SKILL.md +214 -0
- package/skills/alloy-guides/references/CLI_TASKS.md +243 -0
- package/skills/alloy-guides/references/CONCEPTS.md +191 -0
- package/skills/alloy-guides/references/CONTROLLERS.md +298 -0
- package/skills/alloy-guides/references/MODELS.md +1028 -0
- package/skills/alloy-guides/references/PURGETSS.md +56 -0
- package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +242 -0
- package/skills/alloy-guides/references/VIEWS_STYLES.md +388 -0
- package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +109 -0
- package/skills/alloy-guides/references/VIEWS_XML.md +558 -0
- package/skills/alloy-guides/references/WIDGETS.md +176 -0
- package/skills/alloy-howtos/SKILL.md +203 -0
- package/skills/alloy-howtos/references/best_practices.md +138 -0
- package/skills/alloy-howtos/references/cli_reference.md +253 -0
- package/skills/alloy-howtos/references/config_files.md +87 -0
- package/skills/alloy-howtos/references/custom_tags.md +147 -0
- package/skills/alloy-howtos/references/debugging_troubleshooting.md +101 -0
- package/skills/alloy-howtos/references/samples.md +167 -0
- package/skills/purgetss/SKILL.md +442 -0
- package/skills/purgetss/assets/purgetss.config.cjs +17 -0
- package/skills/purgetss/references/EXAMPLES.md +247 -0
- package/skills/purgetss/references/animation-system.md +1294 -0
- package/skills/purgetss/references/apply-directive.md +375 -0
- package/skills/purgetss/references/arbitrary-values.md +612 -0
- package/skills/purgetss/references/class-index.md +1350 -0
- package/skills/purgetss/references/cli-commands.md +948 -0
- package/skills/purgetss/references/configurable-properties.md +654 -0
- package/skills/purgetss/references/custom-rules.md +161 -0
- package/skills/purgetss/references/customization-deep-dive.md +722 -0
- package/skills/purgetss/references/dynamic-component-creation.md +489 -0
- package/skills/purgetss/references/grid-layout.md +455 -0
- package/skills/purgetss/references/icon-fonts.md +609 -0
- package/skills/purgetss/references/installation-setup.md +366 -0
- package/skills/purgetss/references/opacity-modifier.md +291 -0
- package/skills/purgetss/references/platform-modifiers.md +479 -0
- package/skills/purgetss/references/smart-mappings.md +42 -0
- package/skills/purgetss/references/titanium-resets.md +359 -0
- package/skills/purgetss/references/ui-ux-design.md +1526 -0
- package/skills/ti-guides/SKILL.md +94 -0
- package/skills/ti-guides/references/advanced-data-and-images.md +19 -0
- package/skills/ti-guides/references/alloy-cli-advanced.md +84 -0
- package/skills/ti-guides/references/alloy-data-mastery.md +29 -0
- package/skills/ti-guides/references/alloy-widgets-and-themes.md +19 -0
- package/skills/ti-guides/references/android-manifest.md +97 -0
- package/skills/ti-guides/references/app-distribution.md +258 -0
- package/skills/ti-guides/references/application-frameworks.md +377 -0
- package/skills/ti-guides/references/cli-reference.md +402 -0
- package/skills/ti-guides/references/coding-best-practices.md +102 -0
- package/skills/ti-guides/references/commonjs-advanced.md +134 -0
- package/skills/ti-guides/references/hello-world.md +100 -0
- package/skills/ti-guides/references/hyperloop-native-access.md +62 -0
- package/skills/ti-guides/references/javascript-primer.md +411 -0
- package/skills/ti-guides/references/reserved-words.md +36 -0
- package/skills/ti-guides/references/resources.md +183 -0
- package/skills/ti-guides/references/style-and-conventions.md +48 -0
- package/skills/ti-guides/references/tiapp-config.md +609 -0
- package/skills/ti-howtos/SKILL.md +174 -0
- package/skills/ti-howtos/references/android-platform-deep-dives.md +658 -0
- package/skills/ti-howtos/references/automation-fastlane-appium.md +95 -0
- package/skills/ti-howtos/references/buffer-codec-streams.md +140 -0
- package/skills/ti-howtos/references/cross-platform-development.md +348 -0
- package/skills/ti-howtos/references/debugging-profiling.md +543 -0
- package/skills/ti-howtos/references/extending-titanium.md +723 -0
- package/skills/ti-howtos/references/google-maps-v2.md +169 -0
- package/skills/ti-howtos/references/ios-map-kit.md +143 -0
- package/skills/ti-howtos/references/ios-platform-deep-dives.md +783 -0
- package/skills/ti-howtos/references/local-data-sources.md +301 -0
- package/skills/ti-howtos/references/location-and-maps.md +252 -0
- package/skills/ti-howtos/references/media-apis.md +210 -0
- package/skills/ti-howtos/references/notification-services.md +599 -0
- package/skills/ti-howtos/references/remote-data-sources.md +349 -0
- package/skills/ti-howtos/references/tutorials.md +502 -0
- package/skills/ti-howtos/references/using-modules.md +237 -0
- package/skills/ti-howtos/references/web-content-integration.md +307 -0
- package/skills/ti-howtos/references/webpack-build-pipeline.md +78 -0
- package/skills/ti-ui/SKILL.md +179 -0
- package/skills/ti-ui/references/accessibility-deep-dive.md +242 -0
- package/skills/ti-ui/references/animation-and-matrices.md +599 -0
- package/skills/ti-ui/references/application-structures.md +655 -0
- package/skills/ti-ui/references/custom-fonts-styling.md +579 -0
- package/skills/ti-ui/references/event-handling.md +393 -0
- package/skills/ti-ui/references/gestures.md +473 -0
- package/skills/ti-ui/references/icons-and-splash-screens.md +409 -0
- package/skills/ti-ui/references/layouts-and-positioning.md +462 -0
- package/skills/ti-ui/references/listviews-and-performance.md +619 -0
- package/skills/ti-ui/references/orientation.md +362 -0
- package/skills/ti-ui/references/platform-ui-android.md +635 -0
- package/skills/ti-ui/references/platform-ui-ios.md +469 -0
- package/skills/ti-ui/references/scrolling-views.md +252 -0
- 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;
|