@maccesar/titools 2.0.6 → 2.2.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 (132) hide show
  1. package/{AGENTS-TEMPLATE.md → AGENTS-VERCEL-RESEARCH.md} +16 -18
  2. package/README.md +250 -168
  3. package/agents/{ti-researcher.md → ti-pro.md} +10 -10
  4. package/bin/titools.js +16 -12
  5. package/lib/cleanup.js +95 -0
  6. package/lib/commands/agents.js +146 -70
  7. package/lib/commands/skills.js +349 -0
  8. package/lib/commands/uninstall.js +189 -154
  9. package/lib/commands/update.js +104 -21
  10. package/lib/config.js +26 -20
  11. package/lib/downloader.js +1 -1
  12. package/lib/installer.js +37 -97
  13. package/lib/platform.js +9 -5
  14. package/lib/prompts/checkboxCancel.js +264 -0
  15. package/lib/prompts/selectCancel.js +204 -0
  16. package/lib/symlink.js +19 -7
  17. package/lib/utils.js +21 -31
  18. package/package.json +10 -10
  19. package/skills/alloy-guides/SKILL.md +8 -30
  20. package/skills/alloy-guides/references/CLI_TASKS.md +14 -24
  21. package/skills/alloy-guides/references/CONCEPTS.md +5 -25
  22. package/skills/alloy-guides/references/CONTROLLERS.md +2 -19
  23. package/skills/alloy-guides/references/MODELS.md +40 -10
  24. package/skills/alloy-guides/references/PURGETSS.md +1 -11
  25. package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +8 -14
  26. package/skills/alloy-guides/references/VIEWS_STYLES.md +14 -25
  27. package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +2 -8
  28. package/skills/alloy-guides/references/VIEWS_XML.md +29 -40
  29. package/skills/alloy-guides/references/WIDGETS.md +1 -17
  30. package/skills/alloy-howtos/SKILL.md +1 -22
  31. package/skills/alloy-howtos/references/best_practices.md +0 -17
  32. package/skills/alloy-howtos/references/cli_reference.md +1 -23
  33. package/skills/alloy-howtos/references/config_files.md +86 -15
  34. package/skills/alloy-howtos/references/custom_tags.md +14 -13
  35. package/skills/alloy-howtos/references/debugging_troubleshooting.md +3 -22
  36. package/skills/alloy-howtos/references/samples.md +4 -14
  37. package/skills/purgetss/SKILL.md +11 -37
  38. package/skills/purgetss/references/EXAMPLES.md +106 -17
  39. package/skills/purgetss/references/animation-system.md +0 -67
  40. package/skills/purgetss/references/apply-directive.md +0 -18
  41. package/skills/purgetss/references/arbitrary-values.md +0 -25
  42. package/skills/purgetss/references/class-index.md +0 -46
  43. package/skills/purgetss/references/cli-commands.md +0 -41
  44. package/skills/purgetss/references/configurable-properties.md +0 -55
  45. package/skills/purgetss/references/custom-rules.md +0 -14
  46. package/skills/purgetss/references/customization-deep-dive.md +0 -49
  47. package/skills/purgetss/references/dynamic-component-creation.md +56 -37
  48. package/skills/purgetss/references/grid-layout.md +0 -32
  49. package/skills/purgetss/references/icon-fonts.md +0 -50
  50. package/skills/purgetss/references/installation-setup.md +61 -32
  51. package/skills/purgetss/references/migration-guide.md +127 -0
  52. package/skills/purgetss/references/opacity-modifier.md +0 -34
  53. package/skills/purgetss/references/performance-tips.md +261 -0
  54. package/skills/purgetss/references/platform-modifiers.md +0 -46
  55. package/skills/purgetss/references/smart-mappings.md +0 -12
  56. package/skills/purgetss/references/tikit-components.md +393 -0
  57. package/skills/purgetss/references/titanium-resets.md +1 -27
  58. package/skills/purgetss/references/ui-ux-design.md +467 -117
  59. package/skills/{alloy-expert → ti-expert}/SKILL.md +45 -54
  60. package/skills/ti-expert/references/alloy-builtins.md +387 -0
  61. package/skills/{alloy-expert → ti-expert}/references/alloy-structure.md +147 -40
  62. package/skills/ti-expert/references/anti-patterns.md +90 -0
  63. package/skills/ti-expert/references/cli-expert.md +109 -0
  64. package/skills/{alloy-expert → ti-expert}/references/code-conventions.md +182 -49
  65. package/skills/{alloy-expert → ti-expert}/references/controller-patterns.md +103 -93
  66. package/skills/{alloy-expert → ti-expert}/references/error-handling.md +12 -12
  67. package/skills/{alloy-expert → ti-expert}/references/examples.md +144 -85
  68. package/skills/{alloy-expert → ti-expert}/references/migration-patterns.md +38 -36
  69. package/skills/{alloy-expert → ti-expert}/references/patterns.md +8 -8
  70. package/skills/ti-expert/references/performance-listview.md +251 -0
  71. package/skills/{alloy-expert/references/performance-patterns.md → ti-expert/references/performance-optimization.md} +67 -283
  72. package/skills/{alloy-expert/references/security-patterns.md → ti-expert/references/security-device.md} +12 -295
  73. package/skills/ti-expert/references/security-fundamentals.md +284 -0
  74. package/skills/{alloy-expert → ti-expert}/references/state-management.md +10 -10
  75. package/skills/ti-expert/references/testing-e2e-ci.md +432 -0
  76. package/skills/ti-expert/references/testing-unit.md +433 -0
  77. package/skills/ti-expert/references/theming.md +394 -0
  78. package/skills/ti-guides/SKILL.md +1 -14
  79. package/skills/ti-guides/references/advanced-data-and-images.md +126 -10
  80. package/skills/ti-guides/references/app-distribution.md +48 -10
  81. package/skills/ti-guides/references/application-frameworks.md +9 -2
  82. package/skills/ti-guides/references/cli-reference.md +338 -82
  83. package/skills/ti-guides/references/coding-best-practices.md +14 -4
  84. package/skills/ti-guides/references/commonjs-advanced.md +103 -6
  85. package/skills/ti-guides/references/hello-world.md +5 -2
  86. package/skills/ti-guides/references/hyperloop-native-access.md +439 -46
  87. package/skills/ti-guides/references/javascript-primer.md +4 -3
  88. package/skills/ti-guides/references/resources.md +0 -1
  89. package/skills/ti-guides/references/style-and-conventions.md +57 -9
  90. package/skills/ti-guides/references/tiapp-config.md +48 -6
  91. package/skills/ti-howtos/SKILL.md +2 -27
  92. package/skills/ti-howtos/references/android-platform-deep-dives.md +41 -90
  93. package/skills/ti-howtos/references/automation-fastlane-appium.md +15 -14
  94. package/skills/ti-howtos/references/buffer-codec-streams.md +22 -22
  95. package/skills/ti-howtos/references/cross-platform-development.md +68 -37
  96. package/skills/ti-howtos/references/debugging-profiling.md +8 -53
  97. package/skills/ti-howtos/references/extending-titanium.md +12 -51
  98. package/skills/ti-howtos/references/google-maps-v2.md +30 -29
  99. package/skills/ti-howtos/references/ios-map-kit.md +19 -25
  100. package/skills/ti-howtos/references/ios-platform-deep-dives.md +95 -283
  101. package/skills/ti-howtos/references/local-data-sources.md +45 -37
  102. package/skills/ti-howtos/references/location-and-maps.md +47 -28
  103. package/skills/ti-howtos/references/media-apis.md +84 -27
  104. package/skills/ti-howtos/references/notification-services.md +40 -89
  105. package/skills/ti-howtos/references/remote-data-sources.md +21 -36
  106. package/skills/ti-howtos/references/tutorials.md +79 -39
  107. package/skills/ti-howtos/references/using-modules.md +4 -30
  108. package/skills/ti-howtos/references/web-content-integration.md +28 -45
  109. package/skills/ti-howtos/references/webpack-build-pipeline.md +54 -18
  110. package/skills/ti-ui/SKILL.md +1 -21
  111. package/skills/ti-ui/references/accessibility-deep-dive.md +71 -25
  112. package/skills/ti-ui/references/animation-and-matrices.md +0 -47
  113. package/skills/ti-ui/references/application-structures.md +0 -46
  114. package/skills/ti-ui/references/custom-fonts-styling.md +9 -57
  115. package/skills/ti-ui/references/event-handling.md +32 -40
  116. package/skills/ti-ui/references/gestures.md +0 -40
  117. package/skills/ti-ui/references/icons-and-splash-screens.md +21 -44
  118. package/skills/ti-ui/references/layouts-and-positioning.md +47 -39
  119. package/skills/ti-ui/references/listviews-and-performance.md +187 -73
  120. package/skills/ti-ui/references/orientation.md +57 -71
  121. package/skills/ti-ui/references/platform-ui-android.md +114 -48
  122. package/skills/ti-ui/references/platform-ui-ios.md +63 -38
  123. package/skills/ti-ui/references/scrolling-views.md +14 -23
  124. package/skills/ti-ui/references/tableviews.md +6 -56
  125. package/lib/commands/install.js +0 -188
  126. package/skills/alloy-expert/references/anti-patterns.md +0 -133
  127. package/skills/alloy-expert/references/testing.md +0 -872
  128. package/skills/ti-guides/references/alloy-cli-advanced.md +0 -84
  129. package/skills/ti-guides/references/alloy-data-mastery.md +0 -29
  130. package/skills/ti-guides/references/alloy-widgets-and-themes.md +0 -19
  131. /package/skills/{alloy-expert → ti-expert}/assets/ControllerAutoCleanup.js +0 -0
  132. /package/skills/{alloy-expert → ti-expert}/references/contracts.md +0 -0
@@ -1,8 +1,8 @@
1
1
  ---
2
- name: ti-researcher
2
+ name: ti-pro
3
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
4
  skills:
5
- - alloy-expert
5
+ - ti-expert
6
6
  - alloy-guides
7
7
  - alloy-howtos
8
8
  - purgetss
@@ -21,10 +21,10 @@ You are a deep-dive research specialist for Titanium SDK and Alloy mobile develo
21
21
 
22
22
  When invoked, you research complex topics by consulting **all 7 preloaded titanium-\*** skills:
23
23
 
24
- - `alloy-expert` - Architecture, patterns, PurgeTSS conventions
24
+ - `ti-expert` - Architecture, patterns, conventions
25
25
  - `alloy-guides` - Alloy MVC complete reference
26
26
  - `alloy-howtos` - CLI, config, debugging
27
- - `purgetss` - Utility-first styling classes
27
+ - `purgetss` - Utility-first styling classes (optional addon — use when the project already has it or the user asks about it)
28
28
  - `ti-guides` - SDK official guides, Hyperloop, distribution
29
29
  - `ti-howtos` - Native features, platform-specific APIs
30
30
  - `ti-ui` - UI/UX patterns, layouts, gestures
@@ -43,7 +43,7 @@ When invoked, you research complex topics by consulting **all 7 preloaded titani
43
43
  | -------------------------- | ------------------------------------------------------------------ |
44
44
  | **Codebase analysis** | "Analyze this Alloy app's architecture and identify anti-patterns" |
45
45
  | **Multi-feature research** | "Research how to implement location + push + background sync" |
46
- | **Cross-skills questions** | "Compare ListView vs TableView performance with PurgeTSS styling" |
46
+ | **Cross-skills questions** | "Compare ListView vs TableView performance and styling approaches" |
47
47
  | **Architecture review** | "Review this project's folder structure and service layer" |
48
48
  | **Platform differences** | "Research iOS vs Android differences for this feature" |
49
49
 
@@ -51,7 +51,7 @@ When invoked, you research complex topics by consulting **all 7 preloaded titani
51
51
 
52
52
  | Use Instead | Reason |
53
53
  | -------------------------------------------- | -------------------------------------- |
54
- | `/alloy-expert` for architecture guidance | Inline consultation during development |
54
+ | `/ti-expert` for architecture guidance | Inline consultation during development |
55
55
  | `/purgetss` to verify a class | Quick inline reference |
56
56
  | `/ti-howtos` for step-by-step implementation | Task-oriented guidance |
57
57
  | Main conversation for iterative work | Sub-agents run in isolation |
@@ -72,7 +72,7 @@ Example:
72
72
  Your app uses `Ti.App.fireEvent` which causes memory leaks.
73
73
 
74
74
  ## Key Points
75
- - **alloy-expert/references/anti-patterns.md:45** - Ti.App.fireEvent leaks memory
75
+ - **ti-expert/references/anti-patterns.md:45** - Ti.App.fireEvent leaks memory
76
76
  - **alloy-howtos/references/best_practices.md:23** - Use Backbone.Events instead
77
77
 
78
78
  ## Solution
@@ -103,6 +103,6 @@ You **cannot** modify files. If the user asks for changes, provide the research
103
103
  > **Tip**: Include words like "Titanium", "Alloy", "mobile app", or "architecture review" to ensure the agent is triggered for Titanium-specific analysis.
104
104
 
105
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"
106
+ - "Use the ti-pro agent to analyze this codebase"
107
+ - "Have ti-pro investigate the architecture of this project"
108
+ - "Use ti-pro to research platform-specific differences for this feature"
package/bin/titools.js CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  import { Command } from 'commander';
9
9
  import { PACKAGE_VERSION } from '../lib/config.js';
10
- import { installCommand } from '../lib/commands/install.js';
10
+ import { skillsCommand } from '../lib/commands/skills.js';
11
11
  import { agentsCommand } from '../lib/commands/agents.js';
12
12
  import { updateCommand } from '../lib/commands/update.js';
13
13
  import { uninstallCommand } from '../lib/commands/uninstall.js';
@@ -16,35 +16,39 @@ const program = new Command();
16
16
 
17
17
  program
18
18
  .name('titools')
19
- .description('Titanium SDK Skills CLI - Manage skills and agents for AI coding assistants')
19
+ .description('Titanium SDK Knowledge CLI - Manage skills and knowledge for AI coding assistants')
20
20
  .version(PACKAGE_VERSION);
21
21
 
22
22
  // Install command
23
23
  program
24
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')
25
+ .description('Install Titanium knowledge packages and platform links')
26
+ .option('-l, --local', 'Install skills locally in the current project')
27
+ .option('-a, --all', 'Install all detected platforms without prompting')
27
28
  .option('--path <path>', 'Install to a custom path (skips symlink setup)')
28
- .action(installCommand);
29
+ .action(skillsCommand);
29
30
 
30
- // Agents command
31
+ // Sync command
31
32
  program
32
- .command('agents')
33
- .description('Add AGENTS.md/CLAUDE.md/GEMINI.md to your Titanium project')
33
+ .command('sync')
34
+ .description('Sync knowledge index files (AGENTS.md/CLAUDE.md/GEMINI.md) in a Titanium project')
34
35
  .argument('[path]', 'Project path (defaults to current directory)', '.')
35
36
  .option('-f, --force', 'Overwrite existing files without prompting')
37
+ .option('-v, --verbose', 'Show detailed diagnostics')
36
38
  .action(agentsCommand);
37
39
 
38
40
  // Update command
39
41
  program
40
42
  .command('update')
41
- .description('Update Titanium skills and docs to the latest version')
43
+ .description('Update installed knowledge packages and agent (not the CLI)')
44
+ .option('-l, --local', 'Update local skills in the current project')
42
45
  .action(updateCommand);
43
46
 
44
- // Uninstall command
47
+ // Remove command
45
48
  program
46
- .command('uninstall')
47
- .description('Remove Titanium skills and agents')
49
+ .command('remove')
50
+ .description('Remove Titanium knowledge packages and agent')
51
+ .option('-l, --local', 'Remove local skills from the current project')
48
52
  .action(uninstallCommand);
49
53
 
50
54
  // Parse arguments
package/lib/cleanup.js ADDED
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Cleanup helpers for skills, agents, and symlinks
3
+ */
4
+
5
+ import {
6
+ SKILLS,
7
+ LEGACY_SKILLS,
8
+ AGENTS,
9
+ LEGACY_AGENTS,
10
+ getAgentsSkillsDir,
11
+ getClaudeAgentsDir,
12
+ } from './config.js';
13
+ import { detectPlatforms } from './platform.js';
14
+ import { existsSync, lstatSync, rmSync } from 'fs';
15
+ import { join } from 'path';
16
+
17
+ export function getSkillList({ includeLegacy = true, legacyOnly = false } = {}) {
18
+ if (legacyOnly) return [...LEGACY_SKILLS];
19
+ return includeLegacy ? [...SKILLS, ...LEGACY_SKILLS] : [...SKILLS];
20
+ }
21
+
22
+ export function getAgentList({ includeLegacy = true, legacyOnly = false } = {}) {
23
+ if (legacyOnly) return [...LEGACY_AGENTS];
24
+ return includeLegacy ? [...AGENTS, ...LEGACY_AGENTS] : [...AGENTS];
25
+ }
26
+
27
+ function removeEntriesAtDir(dir, names, { suffix = '', recursive = true } = {}) {
28
+ const results = { removed: [], failed: [] };
29
+ if (!dir || !existsSync(dir)) return results;
30
+
31
+ for (const name of names) {
32
+ const target = join(dir, suffix ? `${name}${suffix}` : name);
33
+ try {
34
+ lstatSync(target);
35
+ rmSync(target, { recursive, force: true });
36
+ results.removed.push(name);
37
+ } catch (error) {
38
+ if (error.code && error.code !== 'ENOENT') {
39
+ results.failed.push(name);
40
+ }
41
+ }
42
+ }
43
+
44
+ return results;
45
+ }
46
+
47
+ export function removeSkillSymlinks(platformSkillsDir, options = {}) {
48
+ const skillList = getSkillList(options);
49
+ return removeEntriesAtDir(platformSkillsDir, skillList, { recursive: true });
50
+ }
51
+
52
+ export function removeLegacySkillSymlinks(platformSkillsDir) {
53
+ return removeSkillSymlinks(platformSkillsDir, { legacyOnly: true });
54
+ }
55
+
56
+ export function removeSkills(baseDir, options = {}) {
57
+ const skillsDir = getAgentsSkillsDir(baseDir);
58
+ const skillList = getSkillList(options);
59
+ return removeEntriesAtDir(skillsDir, skillList, { recursive: true });
60
+ }
61
+
62
+ export function removeAgents(baseDir, options = {}) {
63
+ const agentsDir = getClaudeAgentsDir(baseDir);
64
+ const agentList = getAgentList(options);
65
+ return removeEntriesAtDir(agentsDir, agentList, { suffix: '.md', recursive: false });
66
+ }
67
+
68
+ export function cleanupLegacyArtifacts(baseDir) {
69
+ removeSkills(baseDir, { legacyOnly: true });
70
+ removeAgents(baseDir, { legacyOnly: true });
71
+
72
+ const platforms = detectPlatforms(baseDir);
73
+ for (const platform of platforms) {
74
+ removeLegacySkillSymlinks(platform.skillsDir);
75
+ }
76
+
77
+ if (baseDir) {
78
+ removeSkills(undefined, { legacyOnly: true });
79
+ removeAgents(undefined, { legacyOnly: true });
80
+ const globalPlatforms = detectPlatforms();
81
+ for (const platform of globalPlatforms) {
82
+ removeLegacySkillSymlinks(platform.skillsDir);
83
+ }
84
+ }
85
+ }
86
+
87
+ export default {
88
+ getSkillList,
89
+ getAgentList,
90
+ removeSkillSymlinks,
91
+ removeLegacySkillSymlinks,
92
+ removeSkills,
93
+ removeAgents,
94
+ cleanupLegacyArtifacts,
95
+ };
@@ -3,21 +3,19 @@
3
3
  * Adds AGENTS.md/CLAUDE.md/GEMINI.md to Titanium projects
4
4
  */
5
5
 
6
- import inquirer from 'inquirer';
7
6
  import chalk from 'chalk';
8
7
  import ora from 'ora';
9
8
  import {
10
- getAgentsDir,
11
9
  getAgentsSkillsDir,
12
- TITANIUM_PROJECT_FILE,
13
- AI_FILE_PRIORITIES,
10
+ SKILLS,
14
11
  } from '../config.js';
12
+ import checkbox, { Separator } from '../prompts/checkboxCancel.js';
15
13
  import {
16
14
  isTitaniumProject,
17
15
  detectTitaniumVersion,
18
- getAIFiles,
19
- determineFilesToUpdate,
20
16
  addOrUpdateBlock,
17
+ blockExists,
18
+ removeOldBlock,
21
19
  } from '../utils.js';
22
20
  import { existsSync, writeFileSync } from 'fs';
23
21
  import { join, resolve } from 'path';
@@ -28,28 +26,47 @@ import { join, resolve } from 'path';
28
26
  * @param {Object} options - Command options
29
27
  */
30
28
  export async function agentsCommand(projectPath, options) {
31
- console.log('');
32
- console.log(chalk.bold.blue('Titanium AGENTS.md Installer'));
29
+ const effectiveOptions = options || {};
30
+ const inline = !!effectiveOptions.inline;
31
+ if (!inline) {
32
+ console.log('');
33
+ }
34
+ console.log(chalk.bold.blue('Titanium AI Knowledge Manager'));
33
35
  console.log('');
34
36
 
35
37
  // Resolve project path
36
38
  const projectDir = resolve(projectPath);
37
39
 
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
40
  // Verify this is a Titanium project
50
41
  if (!isTitaniumProject(projectDir)) {
51
42
  console.log(chalk.red('Error: Not a Titanium project (no tiapp.xml)'));
52
- console.log('Run this command from your project root.');
43
+ console.log('Run this command from the project root.');
44
+ process.exit(1);
45
+ }
46
+ // Check for local vs global skills
47
+ const localSkillsPaths = {
48
+ 'CLAUDE.md': join(projectDir, '.claude', 'skills'),
49
+ 'GEMINI.md': join(projectDir, '.gemini', 'skills'),
50
+ 'AGENTS.md': join(projectDir, '.agents', 'skills'),
51
+ };
52
+
53
+ const agentsSkillsDir = getAgentsSkillsDir();
54
+ const hasSkillsAt = (skillsDir) =>
55
+ skillsDir && SKILLS.some((skill) => existsSync(join(skillsDir, skill)));
56
+ const hasGlobalSkills = hasSkillsAt(agentsSkillsDir);
57
+ const hasAnyLocalSkills = Object.values(localSkillsPaths).some(hasSkillsAt);
58
+
59
+ // Verify skills are installed (either global or local)
60
+ if (!hasGlobalSkills && !hasAnyLocalSkills) {
61
+ console.log(chalk.red('Error: Skills not installed.'));
62
+ console.log(`${chalk.bold('Run:')} ${chalk.cyan('titools install')}`);
63
+ if (options?.verbose) {
64
+ console.log(
65
+ chalk.gray(
66
+ `Searched: ${agentsSkillsDir} | ./.agents/skills, ./.claude/skills, ./.gemini/skills`
67
+ )
68
+ );
69
+ }
53
70
  process.exit(1);
54
71
  }
55
72
 
@@ -58,67 +75,126 @@ export async function agentsCommand(projectPath, options) {
58
75
  console.log(chalk.green('✓'), `Titanium project (SDK ${tiVersion})`);
59
76
  console.log('');
60
77
 
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
- ],
78
+ // Define potential files
79
+ const possibleFiles = [
80
+ { name: 'AGENTS.md', value: 'AGENTS.md' },
81
+ { name: 'CLAUDE.md', value: 'CLAUDE.md' },
82
+ { name: 'GEMINI.md', value: 'GEMINI.md' },
83
+ ];
84
+
85
+ // Get current state of files
86
+ const fileStates = possibleFiles.map(f => {
87
+ const filePath = join(projectDir, f.value);
88
+ return {
89
+ ...f,
90
+ exists: existsSync(filePath),
91
+ hasBlock: blockExists(filePath)
92
+ };
93
+ });
94
+
95
+ // Determine which files to process
96
+ let selectedFiles = [];
97
+
98
+ if (effectiveOptions.onlyExisting) {
99
+ selectedFiles = fileStates.filter(f => f.exists).map(f => f.value);
100
+ } else if (effectiveOptions.force) {
101
+ selectedFiles = fileStates.filter(f => f.hasBlock).map(f => f.value);
102
+ if (selectedFiles.length === 0) selectedFiles = ['CLAUDE.md'];
103
+ } else {
104
+ try {
105
+ selectedFiles = await checkbox({
106
+ message: 'Select instruction files to sync:',
107
+ choices: [
108
+ ...fileStates.map(f => ({
109
+ name: f.name,
110
+ value: f.value,
111
+ checked: f.hasBlock
112
+ })),
113
+ new Separator(' ')
114
+ ],
115
+ shortcuts: { invert: null },
116
+ theme: {
117
+ style: {
118
+ renderSelectedChoices: () => '',
119
+ },
83
120
  },
84
- ]);
85
- filesToUpdate = [answers.ai];
121
+ });
122
+ } catch (error) {
123
+ console.log('\nCancelled.');
124
+ process.exit(0);
86
125
  }
87
126
  }
88
127
 
89
- // Update each file
128
+ // Handle cancellation
129
+ if (selectedFiles.includes('cancel')) {
130
+ console.log('Cancelled.');
131
+ return;
132
+ }
133
+
134
+ // If nothing selected, proceed to remove knowledge from all existing files
135
+ if (selectedFiles.length === 0) {
136
+ console.log(chalk.yellow('No selection. Removing knowledge index from all files.'));
137
+ }
138
+
139
+ // Process each file
90
140
  const spinner = ora();
91
141
  const updated = [];
142
+ const removed = [];
92
143
 
93
- for (const filename of filesToUpdate) {
144
+ for (const f of fileStates) {
145
+ const filename = f.value;
94
146
  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}`);
147
+ const isSelected = selectedFiles.includes(filename);
148
+
149
+ if (isSelected) {
150
+ // ADD or UPDATE
151
+ spinner.start(`${f.hasBlock ? 'Updating' : 'Adding'} knowledge index in ${filename}...`);
152
+
153
+ try {
154
+ if (!f.exists && !existsSync(filePath)) {
155
+ writeFileSync(filePath, `# ${filename}\n\n`, 'utf8');
156
+ }
157
+
158
+ let rootPath = '~/.agents/skills';
159
+ const localPath = localSkillsPaths[filename];
160
+ if (localPath && existsSync(localPath)) {
161
+ rootPath = `./${filename === 'CLAUDE.md' ? '.claude' : filename === 'GEMINI.md' ? '.gemini' : '.agents'}/skills`;
162
+ } else {
163
+ if (filename === 'CLAUDE.md') rootPath = '~/.claude/skills';
164
+ if (filename === 'GEMINI.md') rootPath = '~/.gemini/skills';
165
+ }
166
+
167
+ addOrUpdateBlock(filePath, rootPath);
168
+ spinner.succeed(`${filename} updated`);
169
+ updated.push(filename);
170
+ } catch (error) {
171
+ spinner.fail(`Failed to sync ${filename}: ${error.message}`);
172
+ }
173
+ } else if (f.hasBlock) {
174
+ // REMOVE block if it was previously there but now unselected
175
+ spinner.start(`Removing knowledge index from ${filename}...`);
176
+ try {
177
+ removeOldBlock(filePath);
178
+ spinner.succeed(`${filename} knowledge index removed`);
179
+ removed.push(filename);
180
+ } catch (error) {
181
+ spinner.fail(`Failed to clean ${filename}: ${error.message}`);
182
+ }
109
183
  }
110
184
  }
111
185
 
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
- );
186
+ if (!inline) {
187
+ console.log('');
188
+ }
189
+ if (updated.length > 0 || removed.length > 0) {
190
+ const updatedText = updated.length > 0 ? ` Updated: ${updated.join(', ')}` : '';
191
+ const cleanedText = removed.length > 0 ? ` Cleaned: ${removed.join(', ')}` : '';
192
+ console.log('');
193
+ console.log(chalk.green(`✓ sync complete!${updatedText}${cleanedText}`));
194
+ } else {
195
+ console.log(chalk.yellow('No changes made.'));
196
+ }
197
+ if (!inline) {
122
198
  console.log('');
123
199
  }
124
200
  }