@maccesar/titools 2.0.7 → 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.
- package/{AGENTS-TEMPLATE.md → AGENTS-VERCEL-RESEARCH.md} +16 -18
- package/README.md +250 -168
- package/agents/{ti-researcher.md → ti-pro.md} +10 -10
- package/bin/titools.js +16 -12
- package/lib/cleanup.js +95 -0
- package/lib/commands/agents.js +146 -70
- package/lib/commands/skills.js +349 -0
- package/lib/commands/uninstall.js +189 -154
- package/lib/commands/update.js +104 -21
- package/lib/config.js +26 -20
- package/lib/downloader.js +1 -1
- package/lib/installer.js +37 -97
- package/lib/platform.js +9 -5
- package/lib/prompts/checkboxCancel.js +264 -0
- package/lib/prompts/selectCancel.js +204 -0
- package/lib/symlink.js +19 -7
- package/lib/utils.js +17 -17
- package/package.json +10 -10
- package/skills/alloy-guides/SKILL.md +8 -30
- package/skills/alloy-guides/references/CLI_TASKS.md +14 -24
- package/skills/alloy-guides/references/CONCEPTS.md +5 -25
- package/skills/alloy-guides/references/CONTROLLERS.md +2 -19
- package/skills/alloy-guides/references/MODELS.md +40 -10
- package/skills/alloy-guides/references/PURGETSS.md +1 -11
- package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +8 -14
- package/skills/alloy-guides/references/VIEWS_STYLES.md +14 -25
- package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +2 -8
- package/skills/alloy-guides/references/VIEWS_XML.md +29 -40
- package/skills/alloy-guides/references/WIDGETS.md +1 -17
- package/skills/alloy-howtos/SKILL.md +1 -22
- package/skills/alloy-howtos/references/best_practices.md +0 -17
- package/skills/alloy-howtos/references/cli_reference.md +1 -23
- package/skills/alloy-howtos/references/config_files.md +86 -15
- package/skills/alloy-howtos/references/custom_tags.md +14 -13
- package/skills/alloy-howtos/references/debugging_troubleshooting.md +3 -22
- package/skills/alloy-howtos/references/samples.md +4 -14
- package/skills/purgetss/SKILL.md +11 -37
- package/skills/purgetss/references/EXAMPLES.md +106 -17
- package/skills/purgetss/references/animation-system.md +0 -67
- package/skills/purgetss/references/apply-directive.md +0 -18
- package/skills/purgetss/references/arbitrary-values.md +0 -25
- package/skills/purgetss/references/class-index.md +0 -46
- package/skills/purgetss/references/cli-commands.md +0 -41
- package/skills/purgetss/references/configurable-properties.md +0 -55
- package/skills/purgetss/references/custom-rules.md +0 -14
- package/skills/purgetss/references/customization-deep-dive.md +0 -49
- package/skills/purgetss/references/dynamic-component-creation.md +56 -37
- package/skills/purgetss/references/grid-layout.md +0 -32
- package/skills/purgetss/references/icon-fonts.md +0 -50
- package/skills/purgetss/references/installation-setup.md +61 -32
- package/skills/purgetss/references/migration-guide.md +127 -0
- package/skills/purgetss/references/opacity-modifier.md +0 -34
- package/skills/purgetss/references/performance-tips.md +261 -0
- package/skills/purgetss/references/platform-modifiers.md +0 -46
- package/skills/purgetss/references/smart-mappings.md +0 -12
- package/skills/purgetss/references/tikit-components.md +393 -0
- package/skills/purgetss/references/titanium-resets.md +1 -27
- package/skills/purgetss/references/ui-ux-design.md +467 -117
- package/skills/{alloy-expert → ti-expert}/SKILL.md +45 -54
- package/skills/ti-expert/references/alloy-builtins.md +387 -0
- package/skills/{alloy-expert → ti-expert}/references/alloy-structure.md +147 -40
- package/skills/ti-expert/references/anti-patterns.md +90 -0
- package/skills/ti-expert/references/cli-expert.md +109 -0
- package/skills/{alloy-expert → ti-expert}/references/code-conventions.md +182 -49
- package/skills/{alloy-expert → ti-expert}/references/controller-patterns.md +103 -93
- package/skills/{alloy-expert → ti-expert}/references/error-handling.md +12 -12
- package/skills/{alloy-expert → ti-expert}/references/examples.md +144 -85
- package/skills/{alloy-expert → ti-expert}/references/migration-patterns.md +38 -36
- package/skills/{alloy-expert → ti-expert}/references/patterns.md +8 -8
- package/skills/ti-expert/references/performance-listview.md +251 -0
- package/skills/{alloy-expert/references/performance-patterns.md → ti-expert/references/performance-optimization.md} +67 -283
- package/skills/{alloy-expert/references/security-patterns.md → ti-expert/references/security-device.md} +12 -295
- package/skills/ti-expert/references/security-fundamentals.md +284 -0
- package/skills/{alloy-expert → ti-expert}/references/state-management.md +10 -10
- package/skills/ti-expert/references/testing-e2e-ci.md +432 -0
- package/skills/ti-expert/references/testing-unit.md +433 -0
- package/skills/ti-expert/references/theming.md +394 -0
- package/skills/ti-guides/SKILL.md +1 -14
- package/skills/ti-guides/references/advanced-data-and-images.md +126 -10
- package/skills/ti-guides/references/app-distribution.md +48 -10
- package/skills/ti-guides/references/application-frameworks.md +9 -2
- package/skills/ti-guides/references/cli-reference.md +338 -82
- package/skills/ti-guides/references/coding-best-practices.md +14 -4
- package/skills/ti-guides/references/commonjs-advanced.md +103 -6
- package/skills/ti-guides/references/hello-world.md +5 -2
- package/skills/ti-guides/references/hyperloop-native-access.md +439 -46
- package/skills/ti-guides/references/javascript-primer.md +4 -3
- package/skills/ti-guides/references/resources.md +0 -1
- package/skills/ti-guides/references/style-and-conventions.md +57 -9
- package/skills/ti-guides/references/tiapp-config.md +48 -6
- package/skills/ti-howtos/SKILL.md +2 -27
- package/skills/ti-howtos/references/android-platform-deep-dives.md +41 -90
- package/skills/ti-howtos/references/automation-fastlane-appium.md +15 -14
- package/skills/ti-howtos/references/buffer-codec-streams.md +22 -22
- package/skills/ti-howtos/references/cross-platform-development.md +68 -37
- package/skills/ti-howtos/references/debugging-profiling.md +8 -53
- package/skills/ti-howtos/references/extending-titanium.md +12 -51
- package/skills/ti-howtos/references/google-maps-v2.md +30 -29
- package/skills/ti-howtos/references/ios-map-kit.md +19 -25
- package/skills/ti-howtos/references/ios-platform-deep-dives.md +95 -283
- package/skills/ti-howtos/references/local-data-sources.md +45 -37
- package/skills/ti-howtos/references/location-and-maps.md +47 -28
- package/skills/ti-howtos/references/media-apis.md +84 -27
- package/skills/ti-howtos/references/notification-services.md +40 -89
- package/skills/ti-howtos/references/remote-data-sources.md +21 -36
- package/skills/ti-howtos/references/tutorials.md +79 -39
- package/skills/ti-howtos/references/using-modules.md +4 -30
- package/skills/ti-howtos/references/web-content-integration.md +28 -45
- package/skills/ti-howtos/references/webpack-build-pipeline.md +54 -18
- package/skills/ti-ui/SKILL.md +1 -21
- package/skills/ti-ui/references/accessibility-deep-dive.md +71 -25
- package/skills/ti-ui/references/animation-and-matrices.md +0 -47
- package/skills/ti-ui/references/application-structures.md +0 -46
- package/skills/ti-ui/references/custom-fonts-styling.md +9 -57
- package/skills/ti-ui/references/event-handling.md +32 -40
- package/skills/ti-ui/references/gestures.md +0 -40
- package/skills/ti-ui/references/icons-and-splash-screens.md +21 -44
- package/skills/ti-ui/references/layouts-and-positioning.md +47 -39
- package/skills/ti-ui/references/listviews-and-performance.md +187 -73
- package/skills/ti-ui/references/orientation.md +57 -71
- package/skills/ti-ui/references/platform-ui-android.md +114 -48
- package/skills/ti-ui/references/platform-ui-ios.md +63 -38
- package/skills/ti-ui/references/scrolling-views.md +14 -23
- package/skills/ti-ui/references/tableviews.md +6 -56
- package/lib/commands/install.js +0 -188
- package/skills/alloy-expert/references/anti-patterns.md +0 -133
- package/skills/alloy-expert/references/testing.md +0 -872
- package/skills/ti-guides/references/alloy-cli-advanced.md +0 -84
- package/skills/ti-guides/references/alloy-data-mastery.md +0 -29
- package/skills/ti-guides/references/alloy-widgets-and-themes.md +0 -19
- /package/skills/{alloy-expert → ti-expert}/assets/ControllerAutoCleanup.js +0 -0
- /package/skills/{alloy-expert → ti-expert}/references/contracts.md +0 -0
|
@@ -3,116 +3,27 @@
|
|
|
3
3
|
* Removes installed skills and agents
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import inquirer from 'inquirer';
|
|
7
6
|
import chalk from 'chalk';
|
|
8
7
|
import ora from 'ora';
|
|
9
|
-
import { SKILLS
|
|
8
|
+
import { SKILLS } from '../config.js';
|
|
10
9
|
import {
|
|
11
10
|
detectPlatforms,
|
|
12
11
|
} from '../platform.js';
|
|
13
|
-
import { remove } from 'fs-extra';
|
|
14
|
-
import { existsSync, rmSync } from 'fs';
|
|
15
|
-
import { join } from 'path';
|
|
16
12
|
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
}
|
|
13
|
+
removeSkillSymlinks,
|
|
14
|
+
removeSkills,
|
|
15
|
+
removeAgents,
|
|
16
|
+
} from '../cleanup.js';
|
|
17
|
+
import checkbox, { Separator } from '../prompts/checkboxCancel.js';
|
|
18
|
+
import {
|
|
19
|
+
isTitaniumProject,
|
|
20
|
+
blockExists,
|
|
21
|
+
removeOldBlock,
|
|
22
|
+
} from '../utils.js';
|
|
23
|
+
import { existsSync } from 'fs';
|
|
24
|
+
import { join, resolve } from 'path';
|
|
25
|
+
import { getAgentsSkillsDir, getClaudeAgentsDir } from '../config.js';
|
|
26
|
+
import { getSkillList, getAgentList } from '../cleanup.js';
|
|
116
27
|
|
|
117
28
|
/**
|
|
118
29
|
* Uninstall command handler
|
|
@@ -123,93 +34,217 @@ export async function uninstallCommand(options) {
|
|
|
123
34
|
console.log(chalk.bold.blue('Titanium SDK Skills Uninstaller'));
|
|
124
35
|
console.log('');
|
|
125
36
|
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
if (
|
|
130
|
-
console.log(chalk.
|
|
131
|
-
console.log('However, you can still remove skills from the central directory.');
|
|
37
|
+
const projectDir = resolve(process.cwd());
|
|
38
|
+
const isProject = isTitaniumProject(projectDir);
|
|
39
|
+
const baseDir = options.local ? projectDir : undefined;
|
|
40
|
+
if (options.local) {
|
|
41
|
+
console.log(chalk.cyan('Mode: Local uninstallation (current project)'));
|
|
132
42
|
console.log('');
|
|
133
43
|
}
|
|
134
44
|
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
|
|
45
|
+
// Detect installed platforms
|
|
46
|
+
const detectedPlatforms = detectPlatforms(baseDir);
|
|
47
|
+
|
|
48
|
+
const knowledgeFiles = ['AGENTS.md', 'CLAUDE.md', 'GEMINI.md'];
|
|
49
|
+
const existingKnowledgeFiles = knowledgeFiles
|
|
50
|
+
.map((file) => ({ file, path: join(projectDir, file) }))
|
|
51
|
+
.filter(({ path }) => existsSync(path));
|
|
52
|
+
const hasKnowledgeBlocks = isProject && existingKnowledgeFiles.some(({ path }) => blockExists(path));
|
|
53
|
+
|
|
54
|
+
const skillList = getSkillList();
|
|
55
|
+
const agentList = getAgentList().map((agent) => `${agent}.md`);
|
|
56
|
+
const homeSkillsDir = getAgentsSkillsDir();
|
|
57
|
+
const projectSkillsDir = getAgentsSkillsDir(projectDir);
|
|
58
|
+
const homeAgentsDir = getClaudeAgentsDir();
|
|
59
|
+
const projectAgentsDir = getClaudeAgentsDir(projectDir);
|
|
60
|
+
|
|
61
|
+
const hasAnyInDir = (dir, names) =>
|
|
62
|
+
!!dir && existsSync(dir) && names.some((name) => existsSync(join(dir, name)));
|
|
63
|
+
|
|
64
|
+
const hasHomeSkills = hasAnyInDir(homeSkillsDir, skillList);
|
|
65
|
+
const hasProjectSkills = isProject && hasAnyInDir(projectSkillsDir, skillList);
|
|
66
|
+
const hasHomeAgents = hasAnyInDir(homeAgentsDir, agentList);
|
|
67
|
+
const hasProjectAgents = isProject && hasAnyInDir(projectAgentsDir, agentList);
|
|
68
|
+
|
|
69
|
+
const hasHomeSymlinks = detectedPlatforms.some((platform) =>
|
|
70
|
+
hasAnyInDir(platform.skillsDir, skillList)
|
|
71
|
+
);
|
|
72
|
+
const hasProjectSymlinks = isProject && detectPlatforms(projectDir).some((platform) =>
|
|
73
|
+
hasAnyInDir(platform.skillsDir, skillList)
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const choices = [];
|
|
77
|
+
if (hasHomeAgents || hasProjectAgents) {
|
|
78
|
+
choices.push({ name: '`ti-pro` for Claude Code', value: 'agents', checked: true });
|
|
79
|
+
}
|
|
80
|
+
if (hasKnowledgeBlocks) {
|
|
81
|
+
choices.push({ name: 'Knowledge index from context files', value: 'knowledge', checked: true });
|
|
82
|
+
}
|
|
83
|
+
if (hasHomeSkills) {
|
|
84
|
+
choices.push({ name: 'Skills from the `home` directory', value: 'skills-home', checked: false });
|
|
85
|
+
}
|
|
86
|
+
if (hasProjectSkills) {
|
|
87
|
+
choices.push({ name: 'Skills from the `project` directory', value: 'skills-project', checked: false });
|
|
88
|
+
}
|
|
89
|
+
if (hasHomeSymlinks) {
|
|
90
|
+
choices.push({ name: 'Skill symlinks from `home` directory', value: 'symlinks-home', checked: false });
|
|
91
|
+
}
|
|
92
|
+
if (hasProjectSymlinks) {
|
|
93
|
+
choices.push({ name: 'Skill symlinks from `project` directory', value: 'symlinks-project', checked: false });
|
|
138
94
|
}
|
|
139
|
-
console.log('');
|
|
140
95
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
96
|
+
if (choices.length === 0) {
|
|
97
|
+
console.log(chalk.yellow('No skills, agents, symlinks, or knowledge index blocks found.'));
|
|
98
|
+
console.log('');
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Modern functional checkbox selection
|
|
103
|
+
let targets = [];
|
|
104
|
+
try {
|
|
105
|
+
targets = await checkbox({
|
|
106
|
+
message: 'What do you want to uninstall:',
|
|
147
107
|
choices: [
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
{ name: 'Agents from Claude Code', value: 'agents', checked: false },
|
|
108
|
+
...choices,
|
|
109
|
+
new Separator(' '),
|
|
151
110
|
],
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
111
|
+
shortcuts: { invert: null },
|
|
112
|
+
theme: {
|
|
113
|
+
style: {
|
|
114
|
+
renderSelectedChoices: () => '',
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.log('\nCancelled.');
|
|
120
|
+
process.exit(0);
|
|
121
|
+
}
|
|
155
122
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
123
|
+
// Handle cancellation (by 'q')
|
|
124
|
+
if (targets.includes('cancel')) {
|
|
125
|
+
console.log('Cancelled.');
|
|
126
|
+
return;
|
|
159
127
|
}
|
|
160
128
|
|
|
161
|
-
if (
|
|
162
|
-
console.log('Nothing to uninstall.');
|
|
163
|
-
|
|
129
|
+
if (targets.length === 0) {
|
|
130
|
+
console.log(chalk.yellow('Nothing to uninstall. Cancelled.'));
|
|
131
|
+
return;
|
|
164
132
|
}
|
|
165
133
|
|
|
166
134
|
const spinner = ora();
|
|
135
|
+
let actionTaken = false;
|
|
167
136
|
|
|
168
|
-
|
|
169
|
-
if (answers.targets.includes('symlinks')) {
|
|
137
|
+
if (targets.includes('symlinks-home')) {
|
|
170
138
|
for (const platform of detectedPlatforms) {
|
|
171
139
|
spinner.start(`Removing ${platform.displayName} symlinks...`);
|
|
172
140
|
const symlinkResult = removeSkillSymlinks(platform.skillsDir);
|
|
173
141
|
|
|
174
142
|
if (symlinkResult.removed.length > 0) {
|
|
175
|
-
spinner.succeed(`${platform.displayName}:
|
|
143
|
+
spinner.succeed(`${platform.displayName}: Skills unlinked`);
|
|
144
|
+
actionTaken = true;
|
|
145
|
+
} else {
|
|
146
|
+
spinner.info(`${platform.displayName}: No symlinks found`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (targets.includes('symlinks-project')) {
|
|
152
|
+
const projectPlatforms = detectPlatforms(projectDir);
|
|
153
|
+
for (const platform of projectPlatforms) {
|
|
154
|
+
spinner.start(`Removing ${platform.displayName} symlinks...`);
|
|
155
|
+
const symlinkResult = removeSkillSymlinks(platform.skillsDir);
|
|
156
|
+
|
|
157
|
+
if (symlinkResult.removed.length > 0) {
|
|
158
|
+
spinner.succeed(`${platform.displayName}: Skills unlinked`);
|
|
159
|
+
actionTaken = true;
|
|
176
160
|
} else {
|
|
177
161
|
spinner.info(`${platform.displayName}: No symlinks found`);
|
|
178
162
|
}
|
|
179
163
|
}
|
|
180
164
|
}
|
|
181
165
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
166
|
+
if (targets.includes('skills-home')) {
|
|
167
|
+
spinner.start('Removing skills...');
|
|
168
|
+
const skillsResult = removeSkills(undefined);
|
|
169
|
+
|
|
170
|
+
if (skillsResult.removed.length > 0) {
|
|
171
|
+
spinner.succeed(`${SKILLS.length} skills removed`);
|
|
172
|
+
actionTaken = true;
|
|
173
|
+
} else {
|
|
174
|
+
spinner.info('No skills to remove');
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (targets.includes('skills-project')) {
|
|
179
|
+
spinner.start('Removing skills...');
|
|
180
|
+
const skillsResult = removeSkills(projectDir);
|
|
186
181
|
|
|
187
182
|
if (skillsResult.removed.length > 0) {
|
|
188
|
-
spinner.succeed(
|
|
183
|
+
spinner.succeed(`${SKILLS.length} skills removed`);
|
|
184
|
+
actionTaken = true;
|
|
189
185
|
} else {
|
|
190
|
-
spinner.info('No skills
|
|
186
|
+
spinner.info('No skills to remove');
|
|
191
187
|
}
|
|
192
188
|
}
|
|
193
189
|
|
|
194
|
-
|
|
195
|
-
if (answers.targets.includes('agents')) {
|
|
190
|
+
if (targets.includes('agents')) {
|
|
196
191
|
spinner.start('Removing agents...');
|
|
197
|
-
const
|
|
192
|
+
const results = [];
|
|
193
|
+
results.push(removeAgents(undefined));
|
|
194
|
+
if (isProject) {
|
|
195
|
+
results.push(removeAgents(projectDir));
|
|
196
|
+
}
|
|
198
197
|
|
|
199
|
-
|
|
200
|
-
|
|
198
|
+
const removed = results.flatMap((r) => r.removed);
|
|
199
|
+
if (removed.length > 0) {
|
|
200
|
+
spinner.succeed('Platform agents removed');
|
|
201
|
+
actionTaken = true;
|
|
201
202
|
} else {
|
|
202
|
-
spinner.info('No agents
|
|
203
|
+
spinner.info('No agents to remove');
|
|
203
204
|
}
|
|
204
205
|
}
|
|
205
206
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
207
|
+
// Remove knowledge index blocks from project files
|
|
208
|
+
if (targets.includes('knowledge')) {
|
|
209
|
+
if (!isProject) {
|
|
210
|
+
spinner.info('Not a Titanium project, skipping knowledge cleanup');
|
|
211
|
+
} else {
|
|
212
|
+
spinner.start('Removing knowledge index...');
|
|
213
|
+
const cleaned = [];
|
|
214
|
+
for (const { file, path } of existingKnowledgeFiles) {
|
|
215
|
+
if (blockExists(path)) {
|
|
216
|
+
try {
|
|
217
|
+
removeOldBlock(path);
|
|
218
|
+
cleaned.push(file);
|
|
219
|
+
} catch {
|
|
220
|
+
// Ignore; we only report if no files were cleaned
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (cleaned.length > 0) {
|
|
226
|
+
spinner.succeed(`Knowledge index removed from: ${cleaned.join(', ')}`);
|
|
227
|
+
actionTaken = true;
|
|
228
|
+
} else {
|
|
229
|
+
spinner.info('No knowledge index blocks to remove');
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (actionTaken) {
|
|
235
|
+
console.log('');
|
|
236
|
+
console.log(chalk.green('✓ Uninstallation complete!'));
|
|
237
|
+
console.log('');
|
|
238
|
+
if (isProject && !targets.includes('knowledge')) {
|
|
239
|
+
console.log(chalk.gray('Note: Knowledge index blocks were not removed.'));
|
|
240
|
+
console.log('');
|
|
241
|
+
}
|
|
242
|
+
console.log('');
|
|
243
|
+
} else {
|
|
244
|
+
console.log('');
|
|
245
|
+
console.log(chalk.yellow('No changes were necessary.'));
|
|
246
|
+
console.log('');
|
|
247
|
+
}
|
|
213
248
|
}
|
|
214
249
|
|
|
215
250
|
export default uninstallCommand;
|
package/lib/commands/update.js
CHANGED
|
@@ -8,39 +8,104 @@ import ora from 'ora';
|
|
|
8
8
|
import {
|
|
9
9
|
PACKAGE_VERSION,
|
|
10
10
|
REPO_URL,
|
|
11
|
-
REPO_API_URL,
|
|
12
11
|
SKILLS,
|
|
13
|
-
AGENTS,
|
|
14
12
|
} from '../config.js';
|
|
13
|
+
import select from '../prompts/selectCancel.js';
|
|
15
14
|
import {
|
|
16
15
|
detectPlatforms,
|
|
17
16
|
} from '../platform.js';
|
|
17
|
+
import { cleanupLegacyArtifacts } from '../cleanup.js';
|
|
18
18
|
import {
|
|
19
19
|
installSkills,
|
|
20
20
|
installAgents,
|
|
21
|
-
installAgentsTemplate,
|
|
22
21
|
getLocalRepoDir,
|
|
23
22
|
} from '../installer.js';
|
|
23
|
+
import { agentsCommand } from './agents.js';
|
|
24
24
|
import {
|
|
25
25
|
downloadRepoArchive,
|
|
26
26
|
checkForUpdate,
|
|
27
27
|
} from '../downloader.js';
|
|
28
28
|
import { createSkillSymlinks } from '../symlink.js';
|
|
29
|
-
import { formatList } from '../utils.js';
|
|
29
|
+
import { formatList, isTitaniumProject } from '../utils.js';
|
|
30
|
+
import { getAgentsSkillsDir } from '../config.js';
|
|
30
31
|
import { mkdtemp } from 'fs/promises';
|
|
31
|
-
import {
|
|
32
|
+
import { existsSync } from 'fs';
|
|
33
|
+
import { join, resolve } from 'path';
|
|
32
34
|
import { tmpdir } from 'os';
|
|
33
35
|
|
|
34
36
|
/**
|
|
35
37
|
* Update command handler
|
|
38
|
+
* @param {Object} options - Command options
|
|
36
39
|
*/
|
|
37
|
-
export async function updateCommand() {
|
|
40
|
+
export async function updateCommand(options) {
|
|
38
41
|
console.log('');
|
|
39
42
|
console.log(chalk.bold.blue('Titanium SDK Skills Updater'));
|
|
40
43
|
console.log('');
|
|
41
44
|
|
|
42
45
|
const spinner = ora();
|
|
43
46
|
|
|
47
|
+
// Determine base directory
|
|
48
|
+
let baseDir = options.local ? process.cwd() : undefined;
|
|
49
|
+
const hasSkillsAt = (dir) =>
|
|
50
|
+
SKILLS.some((skill) => existsSync(join(getAgentsSkillsDir(dir), skill)));
|
|
51
|
+
|
|
52
|
+
// If not explicitly local, check if local skills exist to ask user
|
|
53
|
+
if (!options.local) {
|
|
54
|
+
const projectDir = process.cwd();
|
|
55
|
+
const isProject = isTitaniumProject(projectDir);
|
|
56
|
+
const localPlatforms = detectPlatforms(projectDir);
|
|
57
|
+
const hasLocalSkills = isProject && hasSkillsAt(projectDir);
|
|
58
|
+
const hasGlobalSkills = hasSkillsAt(undefined);
|
|
59
|
+
if (hasLocalSkills && !hasGlobalSkills) {
|
|
60
|
+
baseDir = projectDir;
|
|
61
|
+
} else if (isProject && localPlatforms.length > 0) {
|
|
62
|
+
try {
|
|
63
|
+
const scope = await select({
|
|
64
|
+
message: 'Local installation detected. What do you want to update:',
|
|
65
|
+
choices: [
|
|
66
|
+
{ name: 'Global skills (user home)', value: 'global' },
|
|
67
|
+
{ name: 'Local skills (current project)', value: 'local' },
|
|
68
|
+
],
|
|
69
|
+
theme: {
|
|
70
|
+
style: {
|
|
71
|
+
answer: () => '',
|
|
72
|
+
prefix: () => chalk.cyan('?'),
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
if (scope === 'cancel') {
|
|
77
|
+
console.log('Cancelled.');
|
|
78
|
+
process.exit(0);
|
|
79
|
+
}
|
|
80
|
+
if (scope === 'local') {
|
|
81
|
+
baseDir = process.cwd();
|
|
82
|
+
}
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.log('\nCancelled.');
|
|
85
|
+
process.exit(0);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (baseDir) {
|
|
91
|
+
console.log(chalk.cyan('Mode: Local update (current project)'));
|
|
92
|
+
} else {
|
|
93
|
+
console.log(chalk.cyan('Mode: Global update (user home)'));
|
|
94
|
+
}
|
|
95
|
+
console.log('');
|
|
96
|
+
|
|
97
|
+
const skillsDir = getAgentsSkillsDir(baseDir);
|
|
98
|
+
const hasSkillsInstalled = skillsDir && SKILLS.some((skill) => existsSync(join(skillsDir, skill)));
|
|
99
|
+
if (!hasSkillsInstalled) {
|
|
100
|
+
console.log(chalk.yellow('No skills installed at this location.'));
|
|
101
|
+
console.log('Install them first with:');
|
|
102
|
+
console.log(' titools install');
|
|
103
|
+
console.log('');
|
|
104
|
+
console.log('Looked for skills in:');
|
|
105
|
+
console.log(` ${baseDir ? 'Local' : 'Global'}: ${skillsDir}`);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
44
109
|
// Check for updates
|
|
45
110
|
spinner.start('Checking for updates...');
|
|
46
111
|
|
|
@@ -49,8 +114,17 @@ export async function updateCommand() {
|
|
|
49
114
|
|
|
50
115
|
if (!hasUpdate) {
|
|
51
116
|
spinner.info(`Already up to date (v${PACKAGE_VERSION})`);
|
|
117
|
+
cleanupLegacyArtifacts(baseDir);
|
|
52
118
|
console.log('');
|
|
53
119
|
console.log(chalk.green('✓'), 'Skills and agents are already at the latest version');
|
|
120
|
+
const projectDir = resolve(process.cwd());
|
|
121
|
+
if (isTitaniumProject(projectDir)) {
|
|
122
|
+
const aiFiles = ['AGENTS.md', 'CLAUDE.md', 'GEMINI.md'];
|
|
123
|
+
const hasAnyAiFile = aiFiles.some((file) => existsSync(join(projectDir, file)));
|
|
124
|
+
if (hasAnyAiFile) {
|
|
125
|
+
await agentsCommand(projectDir, { onlyExisting: true, force: true });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
54
128
|
console.log('');
|
|
55
129
|
return;
|
|
56
130
|
}
|
|
@@ -61,12 +135,16 @@ export async function updateCommand() {
|
|
|
61
135
|
console.log(chalk.gray(`Latest: (from GitHub)`));
|
|
62
136
|
console.log('');
|
|
63
137
|
|
|
64
|
-
// Detect installed platforms
|
|
65
|
-
const detectedPlatforms = detectPlatforms();
|
|
138
|
+
// Detect installed platforms at target
|
|
139
|
+
const detectedPlatforms = detectPlatforms(baseDir);
|
|
66
140
|
|
|
67
141
|
if (detectedPlatforms.length === 0) {
|
|
68
142
|
console.log(chalk.yellow('No AI coding assistants detected.'));
|
|
69
|
-
|
|
143
|
+
if (baseDir) {
|
|
144
|
+
console.log('Update will install skills to ./.agents/skills/');
|
|
145
|
+
} else {
|
|
146
|
+
console.log('Update will install skills to ~/.agents/skills/');
|
|
147
|
+
}
|
|
70
148
|
console.log('');
|
|
71
149
|
} else {
|
|
72
150
|
for (const platform of detectedPlatforms) {
|
|
@@ -91,14 +169,14 @@ export async function updateCommand() {
|
|
|
91
169
|
try {
|
|
92
170
|
// Install skills
|
|
93
171
|
spinner.start('Updating skills...');
|
|
94
|
-
const skillsResult = await installSkills(repoDir);
|
|
172
|
+
const skillsResult = await installSkills(repoDir, baseDir);
|
|
95
173
|
spinner.succeed(
|
|
96
174
|
`Skills: ${formatList(skillsResult.installed)}`
|
|
97
175
|
);
|
|
98
176
|
|
|
99
177
|
// Install agents
|
|
100
178
|
spinner.start('Updating agents...');
|
|
101
|
-
const agentsResult = await installAgents(repoDir);
|
|
179
|
+
const agentsResult = await installAgents(repoDir, baseDir);
|
|
102
180
|
if (agentsResult.installed.length > 0) {
|
|
103
181
|
spinner.succeed(
|
|
104
182
|
`Agents: ${formatList(agentsResult.installed)}`
|
|
@@ -107,21 +185,15 @@ export async function updateCommand() {
|
|
|
107
185
|
spinner.info('No agents to update');
|
|
108
186
|
}
|
|
109
187
|
|
|
110
|
-
|
|
111
|
-
spinner.start('Updating AGENTS-TEMPLATE.md...');
|
|
112
|
-
const templateInstalled = await installAgentsTemplate(repoDir);
|
|
113
|
-
if (templateInstalled) {
|
|
114
|
-
spinner.succeed('AGENTS-TEMPLATE.md updated');
|
|
115
|
-
} else {
|
|
116
|
-
spinner.warn('AGENTS-TEMPLATE.md not found');
|
|
117
|
-
}
|
|
188
|
+
cleanupLegacyArtifacts(baseDir);
|
|
118
189
|
|
|
119
190
|
// Update symlinks for detected platforms
|
|
120
191
|
for (const platform of detectedPlatforms) {
|
|
121
192
|
spinner.start(`Updating ${platform.displayName} symlinks...`);
|
|
122
193
|
const symlinkResult = await createSkillSymlinks(
|
|
123
194
|
platform.skillsDir,
|
|
124
|
-
SKILLS
|
|
195
|
+
SKILLS,
|
|
196
|
+
baseDir
|
|
125
197
|
);
|
|
126
198
|
if (symlinkResult.linked.length === SKILLS.length) {
|
|
127
199
|
spinner.succeed(`${platform.displayName} linked`);
|
|
@@ -136,7 +208,18 @@ export async function updateCommand() {
|
|
|
136
208
|
console.log('');
|
|
137
209
|
console.log(chalk.green('✓ Update complete!'));
|
|
138
210
|
console.log('');
|
|
139
|
-
|
|
211
|
+
const projectDir = resolve(process.cwd());
|
|
212
|
+
if (isTitaniumProject(projectDir)) {
|
|
213
|
+
const aiFiles = ['AGENTS.md', 'CLAUDE.md', 'GEMINI.md'];
|
|
214
|
+
const hasAnyAiFile = aiFiles.some((file) => existsSync(join(projectDir, file)));
|
|
215
|
+
if (hasAnyAiFile) {
|
|
216
|
+
await agentsCommand(projectDir, { onlyExisting: true, force: true });
|
|
217
|
+
} else {
|
|
218
|
+
console.log(chalk.bold('▸'), 'Run in the Titanium project:', chalk.cyan('titools sync'));
|
|
219
|
+
}
|
|
220
|
+
} else {
|
|
221
|
+
console.log(chalk.bold('▸'), 'Run in the Titanium project:', chalk.cyan('titools sync'));
|
|
222
|
+
}
|
|
140
223
|
console.log('');
|
|
141
224
|
|
|
142
225
|
} finally {
|