@maccesar/titools 2.2.8 → 2.2.10

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/ti-pro.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: ti-pro
3
- description: Titanium SDK and Alloy research specialist. Preloads all 7 titanium-related 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.
3
+ description: Titanium SDK and Alloy research specialist. Loads the 7 Titanium skills and uses them together to answer research-style questions. Use for codebase analysis, architecture reviews, Titanium SDK implementation research, cross-feature questions, and platform-specific differences. Returns concrete findings with file and line references.
4
4
  skills:
5
5
  - alloy-guides
6
6
  - alloy-howtos
@@ -15,27 +15,27 @@ model: sonnet
15
15
 
16
16
  # Titanium SDK Research Specialist
17
17
 
18
- You are a deep-dive research specialist for Titanium SDK and Alloy mobile development.
18
+ You are a research specialist for Titanium SDK and Alloy mobile development. With more than 15 year of experience.
19
19
 
20
20
  ## What You Do
21
21
 
22
- When invoked, you research complex topics by consulting **all 7 preloaded titanium-\*** skills:
22
+ When invoked, you research complex topics by consulting all 7 Titanium skills:
23
23
 
24
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 (optional addon use when the project already has it or the user asks about it)
27
+ - `purgetss` - Utility-first styling classes (optional add-on; 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
31
31
 
32
32
  ## Research Process
33
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
34
+ 1. **Understand the query** - Identify what needs research.
35
+ 2. **Consult all relevant skills** - Use the full set.
36
+ 3. **Cross-reference** - Connect findings across skills.
37
+ 4. **Provide specifics** - Include file paths, line numbers, and code examples.
38
+ 5. **Cite sources** - Note which skill and file each answer comes from.
39
39
 
40
40
  ## What You're Good For
41
41
 
@@ -47,7 +47,7 @@ When invoked, you research complex topics by consulting **all 7 preloaded titani
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
 
50
- ## What You're NOT For
50
+ ## What You're Not For
51
51
 
52
52
  | Use Instead | Reason |
53
53
  | -------------------------------------------- | -------------------------------------- |
@@ -60,11 +60,11 @@ When invoked, you research complex topics by consulting **all 7 preloaded titani
60
60
 
61
61
  When returning research findings:
62
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
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
68
 
69
69
  Example:
70
70
  ```markdown
@@ -81,7 +81,7 @@ Your app uses `Ti.App.fireEvent` which causes memory leaks.
81
81
 
82
82
  ## Tool Usage
83
83
 
84
- You have **read-only tools**: `Read`, `Grep`, `Glob`, `Bash`
84
+ You have read-only tools: `Read`, `Grep`, `Glob`, `Bash`.
85
85
 
86
86
  Use them to:
87
87
  - Search the codebase when asked to analyze it
@@ -89,7 +89,7 @@ Use them to:
89
89
  - Verify claims against actual code
90
90
  - List files/directories and inspect structure with shell commands
91
91
 
92
- 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
+ You cannot modify files. If the user asks for changes, provide the research and suggest using the appropriate skill or main conversation for implementation.
93
93
 
94
94
  ---
95
95
 
@@ -23,7 +23,7 @@ import {
23
23
  import { agentsCommand } from './agents.js';
24
24
  import {
25
25
  checkForUpdate,
26
- fetchLatestVersion,
26
+ fetchLatestNpmVersion,
27
27
  } from '../downloader.js';
28
28
  import { createSkillSymlinks } from '../symlink.js';
29
29
  import { formatList, isTitaniumProject } from '../utils.js';
@@ -42,6 +42,49 @@ function hasAnySkillSymlink(platformSkillsDir) {
42
42
  return skillList.some((skill) => existsSync(join(platformSkillsDir, skill)));
43
43
  }
44
44
 
45
+ /**
46
+ * Perform the actual update for a specific scope
47
+ * @param {string|undefined} baseDir - Base directory (undefined = global, path = local)
48
+ * @param {string} repoDir - Repository directory
49
+ * @param {Object} spinner - Ora spinner instance
50
+ * @returns {Promise<void>}
51
+ */
52
+ async function performUpdate(baseDir, repoDir, spinner) {
53
+ // Detect platforms with existing symlinks (only update those)
54
+ const detectedPlatforms = detectPlatforms(baseDir);
55
+ const platformsWithSymlinks = detectedPlatforms.filter((p) =>
56
+ hasAnySkillSymlink(p.skillsDir)
57
+ );
58
+
59
+ // Install skills
60
+ spinner.start('Syncing skills...');
61
+ const skillsResult = await installSkills(repoDir, baseDir);
62
+ spinner.succeed(`${skillsResult.installed.length} skills updated`);
63
+
64
+ // Install agents (only if Claude Code has symlinks)
65
+ const claudePlatform = platformsWithSymlinks.find((p) => p.name === 'claude');
66
+ if (claudePlatform) {
67
+ spinner.start('Syncing agents...');
68
+ const agentsResult = await installAgents(repoDir, baseDir);
69
+ if (agentsResult.installed.length > 0) {
70
+ spinner.succeed('Platform agents updated');
71
+ } else {
72
+ spinner.info('No agents to sync');
73
+ }
74
+ }
75
+
76
+ cleanupLegacyArtifacts(baseDir);
77
+
78
+ // Update symlinks silently for platforms that already had them
79
+ for (const platform of platformsWithSymlinks) {
80
+ await createSkillSymlinks(
81
+ platform.skillsDir,
82
+ SKILLS,
83
+ baseDir
84
+ );
85
+ }
86
+ }
87
+
45
88
  /**
46
89
  * Update command handler
47
90
  * @param {Object} options - Command options
@@ -65,15 +108,16 @@ export async function updateCommand(options) {
65
108
  const localPlatforms = detectPlatforms(projectDir);
66
109
  const hasLocalSkills = isProject && hasSkillsAt(projectDir);
67
110
  const hasGlobalSkills = hasSkillsAt(undefined);
68
- if (hasLocalSkills && !hasGlobalSkills) {
69
- baseDir = projectDir;
70
- } else if (isProject && localPlatforms.length > 0) {
111
+
112
+ // Only show prompt if BOTH local and global skills exist
113
+ if (hasLocalSkills && hasGlobalSkills) {
71
114
  try {
72
115
  const scope = await select({
73
- message: 'Local installation detected. What do you want to update:',
116
+ message: 'Both local and global skills detected. What do you want to update:',
74
117
  choices: [
75
118
  { name: 'Global skills (user home)', value: 'global' },
76
119
  { name: 'Local skills (current project)', value: 'local' },
120
+ { name: 'Both locations', value: 'both' },
77
121
  ],
78
122
  theme: {
79
123
  style: {
@@ -87,32 +131,44 @@ export async function updateCommand(options) {
87
131
  process.exit(0);
88
132
  }
89
133
  if (scope === 'local') {
90
- baseDir = process.cwd();
134
+ baseDir = projectDir;
135
+ } else if (scope === 'both') {
136
+ baseDir = 'both';
91
137
  }
92
138
  } catch (error) {
93
139
  console.log('\nCancelled.');
94
140
  process.exit(0);
95
141
  }
142
+ } else if (hasLocalSkills && !hasGlobalSkills) {
143
+ // Only local skills exist, update local
144
+ baseDir = projectDir;
96
145
  }
146
+ // If only global skills exist, baseDir remains undefined (global)
97
147
  }
98
148
 
99
- if (baseDir) {
149
+ // Display mode
150
+ if (baseDir === 'both') {
151
+ console.log(chalk.cyan('Mode: Updating both global and local skills'));
152
+ } else if (baseDir) {
100
153
  console.log(chalk.cyan('Mode: Local update (current project)'));
101
154
  } else {
102
155
  console.log(chalk.cyan('Mode: Global update (user home)'));
103
156
  }
104
157
  console.log('');
105
158
 
106
- const skillsDir = getAgentsSkillsDir(baseDir);
107
- const hasSkillsInstalled = skillsDir && SKILLS.some((skill) => existsSync(join(skillsDir, skill)));
108
- if (!hasSkillsInstalled) {
109
- console.log(chalk.yellow('No skills installed at this location.'));
110
- console.log('Install them first with:');
111
- console.log(' titools install');
112
- console.log('');
113
- console.log('Looked for skills in:');
114
- console.log(` ${baseDir ? 'Local' : 'Global'}: ${skillsDir}`);
115
- return;
159
+ // Verify skills are installed
160
+ if (baseDir !== 'both') {
161
+ const skillsDir = getAgentsSkillsDir(baseDir);
162
+ const hasSkillsInstalled = skillsDir && SKILLS.some((skill) => existsSync(join(skillsDir, skill)));
163
+ if (!hasSkillsInstalled) {
164
+ console.log(chalk.yellow('No skills installed at this location.'));
165
+ console.log('Install them first with:');
166
+ console.log(' titools install');
167
+ console.log('');
168
+ console.log('Looked for skills in:');
169
+ console.log(` ${baseDir ? 'Local' : 'Global'}: ${skillsDir}`);
170
+ return;
171
+ }
116
172
  }
117
173
 
118
174
  // Check for updates
@@ -121,11 +177,11 @@ export async function updateCommand(options) {
121
177
  try {
122
178
  const hasUpdate = await checkForUpdate(PACKAGE_VERSION);
123
179
 
124
- // If there's a newer version on GitHub, prompt user to update CLI first
180
+ // If there's a newer version on npm, prompt user to update CLI first
125
181
  if (hasUpdate) {
126
182
  let latestVersion = '(newer)';
127
183
  try {
128
- latestVersion = await fetchLatestVersion();
184
+ latestVersion = await fetchLatestNpmVersion();
129
185
  } catch {
130
186
  // Ignore error, we already know there's an update
131
187
  }
@@ -158,38 +214,18 @@ export async function updateCommand(options) {
158
214
  return;
159
215
  }
160
216
 
161
- // Detect platforms with existing symlinks (only update those)
162
- const detectedPlatforms = detectPlatforms(baseDir);
163
- const platformsWithSymlinks = detectedPlatforms.filter((p) =>
164
- hasAnySkillSymlink(p.skillsDir)
165
- );
166
-
167
- // Install skills
168
- spinner.start('Syncing skills...');
169
- const skillsResult = await installSkills(repoDir, baseDir);
170
- spinner.succeed(`${skillsResult.installed.length} skills updated`);
171
-
172
- // Install agents (only if Claude Code has symlinks)
173
- const claudePlatform = platformsWithSymlinks.find((p) => p.name === 'claude');
174
- if (claudePlatform) {
175
- spinner.start('Syncing agents...');
176
- const agentsResult = await installAgents(repoDir, baseDir);
177
- if (agentsResult.installed.length > 0) {
178
- spinner.succeed('Platform agents updated');
179
- } else {
180
- spinner.info('No agents to sync');
181
- }
182
- }
183
-
184
- cleanupLegacyArtifacts(baseDir);
217
+ // Perform update(s)
218
+ if (baseDir === 'both') {
219
+ // Update both global and local
220
+ console.log(chalk.bold('Updating global skills...'));
221
+ await performUpdate(undefined, repoDir, spinner);
222
+ console.log('');
185
223
 
186
- // Update symlinks silently for platforms that already had them
187
- for (const platform of platformsWithSymlinks) {
188
- await createSkillSymlinks(
189
- platform.skillsDir,
190
- SKILLS,
191
- baseDir
192
- );
224
+ console.log(chalk.bold('Updating local skills...'));
225
+ await performUpdate(process.cwd(), repoDir, spinner);
226
+ } else {
227
+ // Update single scope
228
+ await performUpdate(baseDir, repoDir, spinner);
193
229
  }
194
230
 
195
231
  // Summary
package/lib/downloader.js CHANGED
@@ -112,13 +112,28 @@ export async function downloadRawFile(filePath, destPath, ref = 'main') {
112
112
  }
113
113
 
114
114
  /**
115
- * Check if an update is available
115
+ * Fetch latest version from npm registry
116
+ * @returns {Promise<string>} Latest version number
117
+ */
118
+ export async function fetchLatestNpmVersion() {
119
+ const response = await fetch('https://registry.npmjs.org/@maccesar/titools');
120
+
121
+ if (!response.ok) {
122
+ throw new Error(`Failed to fetch npm info: ${response.statusText}`);
123
+ }
124
+
125
+ const data = await response.json();
126
+ return data['dist-tags'].latest;
127
+ }
128
+
129
+ /**
130
+ * Check if an update is available (checks npm)
116
131
  * @param {string} currentVersion - Current version
117
132
  * @returns {Promise<boolean>} True if update available
118
133
  */
119
134
  export async function checkForUpdate(currentVersion) {
120
135
  try {
121
- const latestVersion = await fetchLatestVersion();
136
+ const latestVersion = await fetchLatestNpmVersion();
122
137
  // Remove 'v' prefix if present
123
138
  const latest = latestVersion.replace(/^v/, '');
124
139
  const current = currentVersion.replace(/^v/, '');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maccesar/titools",
3
- "version": "2.2.8",
3
+ "version": "2.2.10",
4
4
  "description": "Titanium SDK skills and agents for AI coding assistants (Claude Code, Gemini CLI, Codex CLI)",
5
5
  "main": "lib/index.js",
6
6
  "type": "module",