@maccesar/titools 3.2.0 → 4.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/README.md +27 -61
- package/lib/cleanup.js +29 -0
- package/lib/commands/agents.js +8 -7
- package/lib/commands/skills.js +118 -23
- package/lib/config.js +13 -15
- package/lib/installer.js +5 -3
- package/lib/utils.js +36 -0
- package/package.json +1 -1
- package/skills/alloy-guides/SKILL.md +188 -0
- package/skills/alloy-guides/references/CLI_TASKS.md +233 -0
- package/skills/alloy-guides/references/CONCEPTS.md +171 -0
- package/skills/alloy-guides/references/CONTROLLERS.md +279 -0
- package/skills/alloy-guides/references/MODELS.md +742 -0
- package/skills/alloy-guides/references/MODELS_ADVANCED.md +482 -0
- package/skills/alloy-guides/references/PURGETSS.md +57 -0
- package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +235 -0
- package/skills/alloy-guides/references/VIEWS_STYLES.md +375 -0
- package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +102 -0
- package/skills/alloy-guides/references/VIEWS_XML.md +581 -0
- package/skills/alloy-guides/references/WIDGETS.md +160 -0
- package/skills/alloy-howtos/SKILL.md +179 -0
- package/skills/alloy-howtos/references/best_practices.md +121 -0
- package/skills/alloy-howtos/references/cli_reference.md +230 -0
- package/skills/alloy-howtos/references/config_files.md +158 -0
- package/skills/alloy-howtos/references/custom_tags.md +148 -0
- package/skills/alloy-howtos/references/debugging_troubleshooting.md +78 -0
- package/skills/alloy-howtos/references/samples.md +156 -0
- package/skills/purgetss/SKILL.md +184 -181
- package/skills/purgetss/references/EXAMPLES.md +8 -6
- package/skills/purgetss/references/app-branding.md +5 -0
- package/skills/purgetss/references/apply-directive.md +1 -1
- package/skills/purgetss/references/class-categories.md +1 -1
- package/skills/purgetss/references/class-index-properties.md +618 -0
- package/skills/purgetss/references/class-index.md +4 -610
- package/skills/purgetss/references/cli-commands.md +41 -410
- package/skills/purgetss/references/custom-fonts.md +292 -0
- package/skills/purgetss/references/custom-rules.md +1 -1
- package/skills/purgetss/references/customization-deep-dive.md +64 -1
- package/skills/purgetss/references/icon-fonts.md +208 -118
- package/skills/purgetss/references/installation-setup.md +4 -4
- package/skills/purgetss/references/migration-guide.md +53 -1
- package/skills/purgetss/references/multi-density-images.md +53 -2
- package/skills/purgetss/references/svg-pipeline.md +249 -0
- package/skills/purgetss/references/tikit-components.md +2 -2
- package/skills/purgetss/references/titanium-resets.md +2 -2
- package/skills/purgetss/references/ui-ux-design.md +7 -5
- package/skills/purgetss/references/version-history.md +71 -82
- package/skills/ti-api/SKILL.md +128 -0
- package/skills/ti-api/references/api-android.md +675 -0
- package/skills/ti-api/references/api-app-platform.md +636 -0
- package/skills/ti-api/references/api-core.md +764 -0
- package/skills/ti-api/references/api-data-network.md +641 -0
- package/skills/ti-api/references/api-media.md +655 -0
- package/skills/ti-api/references/api-modules-ble-bluetooth.md +657 -0
- package/skills/ti-api/references/api-modules-coremotion-urlsession.md +411 -0
- package/skills/ti-api/references/api-modules-map.md +632 -0
- package/skills/ti-api/references/api-modules-nfc.md +725 -0
- package/skills/ti-api/references/api-modules-social-misc.md +526 -0
- package/skills/ti-api/references/api-services.md +700 -0
- package/skills/ti-api/references/api-ui-android.md +499 -0
- package/skills/ti-api/references/api-ui-extras.md +702 -0
- package/skills/ti-api/references/api-ui-ios-animator.md +378 -0
- package/skills/ti-api/references/api-ui-ios.md +756 -0
- package/skills/ti-api/references/api-ui-lists.md +581 -0
- package/skills/ti-api/references/api-ui-text-input.md +607 -0
- package/skills/ti-api/references/api-ui-views.md +572 -0
- package/skills/ti-api/references/api-ui-windows-navigation.md +676 -0
- package/skills/ti-api/references/api-xml-global.md +743 -0
- package/skills/ti-guides/SKILL.md +82 -0
- package/skills/ti-guides/references/advanced-data-and-images.md +155 -0
- package/skills/ti-guides/references/android-manifest.md +97 -0
- package/skills/ti-guides/references/app-distribution.md +373 -0
- package/skills/ti-guides/references/application-frameworks.md +366 -0
- package/skills/ti-guides/references/cli-reference.md +700 -0
- package/skills/ti-guides/references/coding-best-practices.md +150 -0
- package/skills/ti-guides/references/commonjs-advanced.md +279 -0
- package/skills/ti-guides/references/hello-world.md +99 -0
- package/skills/ti-guides/references/hyperloop-native-access.md +458 -0
- package/skills/ti-guides/references/javascript-primer.md +402 -0
- package/skills/ti-guides/references/reserved-words.md +36 -0
- package/skills/ti-guides/references/resources.md +172 -0
- package/skills/ti-guides/references/style-and-conventions.md +104 -0
- package/skills/ti-guides/references/tiapp-config.md +655 -0
- package/skills/ti-howtos/SKILL.md +131 -0
- package/skills/ti-howtos/references/android-platform-deep-dives.md +609 -0
- package/skills/ti-howtos/references/automation-fastlane-appium.md +96 -0
- package/skills/ti-howtos/references/buffer-codec-streams.md +162 -0
- package/skills/ti-howtos/references/cross-platform-development.md +358 -0
- package/skills/ti-howtos/references/debugging-profiling.md +473 -0
- package/skills/ti-howtos/references/extending-titanium.md +684 -0
- package/skills/ti-howtos/references/google-maps-v2.md +172 -0
- package/skills/ti-howtos/references/ios-map-kit.md +149 -0
- package/skills/ti-howtos/references/ios-platform-deep-dives.md +595 -0
- package/skills/ti-howtos/references/local-data-sources.md +310 -0
- package/skills/ti-howtos/references/location-and-maps.md +267 -0
- package/skills/ti-howtos/references/media-apis.md +268 -0
- package/skills/ti-howtos/references/notification-services.md +539 -0
- package/skills/ti-howtos/references/remote-data-sources.md +339 -0
- package/skills/ti-howtos/references/tutorials.md +552 -0
- package/skills/ti-howtos/references/using-modules.md +182 -0
- package/skills/ti-howtos/references/web-content-integration.md +288 -0
- package/skills/ti-howtos/references/webpack-build-pipeline.md +125 -0
package/README.md
CHANGED
|
@@ -8,14 +8,12 @@
|
|
|
8
8
|
|
|
9
9
|
</div>
|
|
10
10
|
|
|
11
|
-
TiTools is a Titanium SDK toolkit for AI coding assistants. It ships 3 opinionated
|
|
11
|
+
TiTools is a Titanium SDK toolkit for AI coding assistants. It ships 8 skills — 3 opinionated (`ti-expert`, `purgetss`, `ti-ui`) plus 5 documentation-mirror skills (`ti-api`, `ti-guides`, `ti-howtos`, `alloy-guides`, `alloy-howtos`) — a research agent, and reference files covering Titanium architecture, API reference, native how-tos, Alloy MVC, PurgeTSS styling, and UI/UX patterns.
|
|
12
12
|
|
|
13
13
|
The reference files are maintained against official documentation whenever an official source exists, so the assistant can retrieve current framework behavior instead of guessing from generic training data.
|
|
14
14
|
|
|
15
15
|
Without TiTools, assistants rely on general training data. That data can be outdated or too generic for Titanium work. With TiTools, the assistant can look up Alloy architecture, memory cleanup patterns, PurgeTSS utility classes, and platform-specific APIs.
|
|
16
16
|
|
|
17
|
-
> **v3.0.0 — doc-based skills moved to `tidev/skills`.** Five documentation-only skills (`ti-api`, `ti-guides`, `ti-howtos`, `alloy-guides`, `alloy-howtos`) are now maintained in the official [`tidev/skills`](https://github.com/tidev/skills) repository alongside the rest of the TiDev community tooling. TiTools now focuses on the three opinionated skills above. See [Doc-based skills moved to tidev/skills](#doc-based-skills-moved-to-tidevskills) below for upgrade notes.
|
|
18
|
-
|
|
19
17
|
Vercel's AGENTS.md evaluation reports a 100% pass rate for the knowledge index approach, compared to 53-79% using skills alone.
|
|
20
18
|
|
|
21
19
|
---
|
|
@@ -74,9 +72,9 @@ claude # or gemini, or codex
|
|
|
74
72
|
```
|
|
75
73
|
|
|
76
74
|
What gets installed:
|
|
77
|
-
- The
|
|
75
|
+
- The 8 TiTools skills to `~/.agents/skills/`
|
|
78
76
|
- ti-pro agent for Claude Code
|
|
79
|
-
- Platform symlinks for Claude Code
|
|
77
|
+
- Platform symlinks for Claude Code (Gemini CLI and Codex CLI auto-discover from `~/.agents/skills/` — no symlinks needed)
|
|
80
78
|
- Knowledge index in your project's `AGENTS.md`/`CLAUDE.md`/`GEMINI.md`
|
|
81
79
|
- Claude Code SessionStart hook for auto-updates
|
|
82
80
|
|
|
@@ -101,47 +99,15 @@ Use **Option A** if you only use Claude Code. Use **Option B** if you use multip
|
|
|
101
99
|
|
|
102
100
|
---
|
|
103
101
|
|
|
104
|
-
## Doc-based skills moved to tidev/skills
|
|
105
|
-
|
|
106
|
-
Starting with **v3.0.0**, five documentation-only skills migrated to the official [`tidev/skills`](https://github.com/tidev/skills) repository:
|
|
107
|
-
|
|
108
|
-
- `ti-api` — Complete Titanium API reference
|
|
109
|
-
- `ti-guides` — SDK fundamentals (Hyperloop, distribution, tiapp.xml)
|
|
110
|
-
- `ti-howtos` — Native feature integration (location, push, media, platform-specific APIs)
|
|
111
|
-
- `alloy-guides` — Alloy MVC framework reference
|
|
112
|
-
- `alloy-howtos` — Alloy CLI, configuration, debugging
|
|
113
|
-
|
|
114
|
-
**Why the move?** These skills are pure documentation mirrors of official Titanium and Alloy docs, so they belong in the community-maintained TiDev repository alongside the SDK source itself. Hansemann ([@hansemannn](https://github.com/hansemannn)) — TiDev maintainer — accepted the first batch in [tidev/skills#1](https://github.com/tidev/skills/pull/1) and `ti-howtos` followed in [tidev/skills#2](https://github.com/tidev/skills/pull/2).
|
|
115
|
-
|
|
116
|
-
**What stays in TiTools:** the three *opinionated* skills that reflect personal Titanium conventions and toolchain choices (PurgeTSS-first styling, specific architecture patterns).
|
|
117
|
-
|
|
118
|
-
### Upgrading from v2.x
|
|
119
|
-
|
|
120
|
-
If you have v2.x installed, the five migrated skills will be **auto-removed** the next time you run `titools update` (they're listed in `LEGACY_SKILLS`). To get them back, install from `tidev/skills` directly:
|
|
121
|
-
|
|
122
|
-
```bash
|
|
123
|
-
git clone https://github.com/tidev/skills.git ~/Developer/git-clones/tidev-skills
|
|
124
|
-
# Then symlink the five skills into ~/.agents/skills/ or your AI assistant's skills dir
|
|
125
|
-
ln -s ~/Developer/git-clones/tidev-skills/skills/ti-api ~/.agents/skills/ti-api
|
|
126
|
-
ln -s ~/Developer/git-clones/tidev-skills/skills/ti-guides ~/.agents/skills/ti-guides
|
|
127
|
-
ln -s ~/Developer/git-clones/tidev-skills/skills/ti-howtos ~/.agents/skills/ti-howtos
|
|
128
|
-
ln -s ~/Developer/git-clones/tidev-skills/skills/alloy-guides ~/.agents/skills/alloy-guides
|
|
129
|
-
ln -s ~/Developer/git-clones/tidev-skills/skills/alloy-howtos ~/.agents/skills/alloy-howtos
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
Refer to the [`tidev/skills` README](https://github.com/tidev/skills#readme) for the canonical install instructions, which may evolve independently of TiTools.
|
|
133
|
-
|
|
134
|
-
---
|
|
135
|
-
|
|
136
102
|
## Compatible platforms
|
|
137
103
|
|
|
138
|
-
| Platform | Status |
|
|
139
|
-
| --------------------------------------------------------- | ---------------- |
|
|
140
|
-
| [Claude Code](https://claude.ai/claude-code) | Fully Compatible | `~/.claude/skills/` |
|
|
141
|
-
| [Gemini CLI](https://github.com/google-gemini/gemini-cli) | Fully Compatible | `~/.
|
|
104
|
+
| Platform | Status | Skills Path |
|
|
105
|
+
| --------------------------------------------------------- | ---------------- | ------------------------------------- |
|
|
106
|
+
| [Claude Code](https://claude.ai/claude-code) | Fully Compatible | `~/.claude/skills/` (symlinked) |
|
|
107
|
+
| [Gemini CLI](https://github.com/google-gemini/gemini-cli) | Fully Compatible | `~/.agents/skills/` (auto-discovered) |
|
|
142
108
|
| [Codex CLI](https://developers.openai.com/codex/cli/) | Fully Compatible | `~/.agents/skills/` (auto-discovered) |
|
|
143
109
|
|
|
144
|
-
All three platforms use the Agent Skills open standard: a `SKILL.md` file with YAML frontmatter.
|
|
110
|
+
All three platforms use the Agent Skills open standard: a `SKILL.md` file with YAML frontmatter. Gemini CLI and Codex CLI auto-discover skills from `~/.agents/skills/` per [agentskills.io](https://agentskills.io), so TiTools does not create redundant platform-specific symlinks for them.
|
|
145
111
|
|
|
146
112
|
---
|
|
147
113
|
|
|
@@ -194,7 +160,7 @@ Together they work like this:
|
|
|
194
160
|
| ------------------------------- | ------------------------------- | ----------------------------- |
|
|
195
161
|
| "Create a login screen" | Context about project structure | `ti-expert`, `ti-ui` |
|
|
196
162
|
| "Optimize ListView performance" | Points to docs location | `ti-ui` reads specific files |
|
|
197
|
-
| "Implement push notifications" | API reference paths | `ti-howtos`
|
|
163
|
+
| "Implement push notifications" | API reference paths | `ti-howtos` |
|
|
198
164
|
|
|
199
165
|
You do not need to explicitly invoke skills. The AI detects when to use them based on your question.
|
|
200
166
|
|
|
@@ -206,16 +172,21 @@ The knowledge index is based on the latest Titanium SDK documentation. If your p
|
|
|
206
172
|
|
|
207
173
|
## Skills overview
|
|
208
174
|
|
|
209
|
-
| Skill
|
|
210
|
-
|
|
|
211
|
-
| ti-expert
|
|
212
|
-
| purgetss
|
|
213
|
-
| ti-ui
|
|
175
|
+
| Skill | Purpose | Best For |
|
|
176
|
+
| ------------ | ----------------------------------- | --------------------------------------- |
|
|
177
|
+
| ti-expert | Architecture and implementation | Starting point for most tasks |
|
|
178
|
+
| purgetss | Utility-first styling | UI styling and animations |
|
|
179
|
+
| ti-ui | UI/UX patterns | Complex layouts, ListViews, platform UI |
|
|
180
|
+
| ti-api | Complete Titanium API reference | Looking up properties, methods, events |
|
|
181
|
+
| ti-guides | SDK fundamentals | tiapp.xml, Hyperloop, distribution |
|
|
182
|
+
| ti-howtos | Native feature integration | Location, push, media, platform APIs |
|
|
183
|
+
| alloy-guides | Alloy MVC framework reference | Controllers, models, views, widgets |
|
|
184
|
+
| alloy-howtos | Alloy CLI, configuration, debugging | alloy.jmk, config.json, custom XML tags |
|
|
214
185
|
|
|
215
186
|
Notes:
|
|
216
|
-
-
|
|
217
|
-
-
|
|
218
|
-
-
|
|
187
|
+
- The first three (`ti-expert`, `purgetss`, `ti-ui`) are opinionated workflow skills reflecting TiTools' Titanium conventions.
|
|
188
|
+
- The latter five are documentation-mirror skills sourced from the official Titanium SDK docs (`tidev/titanium-docs`) and audited against them via the internal `titools-skill-auditor`.
|
|
189
|
+
- `purgetss` reference files are audited against the official PurgeTSS documentation, but its workflow conventions are opinionated.
|
|
219
190
|
|
|
220
191
|
---
|
|
221
192
|
|
|
@@ -441,10 +412,6 @@ Key rules:
|
|
|
441
412
|
|
|
442
413
|
---
|
|
443
414
|
|
|
444
|
-
> **Looking for `ti-api`, `ti-guides`, `ti-howtos`, `alloy-guides`, or `alloy-howtos`?** Those five documentation-only skills now live in [`tidev/skills`](https://github.com/tidev/skills). See [Doc-based skills moved to tidev/skills](#doc-based-skills-moved-to-tidevskills) for install instructions.
|
|
445
|
-
|
|
446
|
-
---
|
|
447
|
-
|
|
448
415
|
## Usage examples and best practices
|
|
449
416
|
|
|
450
417
|
### Example prompts
|
|
@@ -540,13 +507,12 @@ Behavior depends on where you run it:
|
|
|
540
507
|
| With `--local` flag | Installs skills locally to `./.agents/skills/` in the current project |
|
|
541
508
|
|
|
542
509
|
What it does:
|
|
543
|
-
- Installs the
|
|
510
|
+
- Installs the 8 TiTools skills (global or local depending on context)
|
|
544
511
|
- Installs ti-pro agent for Claude Code
|
|
545
|
-
- Detects installed AI platforms and lets you choose which to link
|
|
546
|
-
- Creates symlinks from
|
|
547
|
-
- Cleans up legacy artifacts (`alloy-expert` skill, `ti-researcher` agent)
|
|
512
|
+
- Detects installed AI platforms and lets you choose which to link (only Claude Code needs platform symlinks; Gemini CLI and Codex CLI auto-discover from `~/.agents/skills/`)
|
|
513
|
+
- Creates symlinks from `~/.claude/skills/` to the central `~/.agents/skills/`
|
|
514
|
+
- Cleans up legacy artifacts (`alloy-expert` skill, `ti-researcher` agent, redundant Gemini/Codex symlinks)
|
|
548
515
|
- If run inside a Titanium project, prompts to run `titools sync` afterward
|
|
549
|
-
- Warns Gemini users if local skills override existing global Gemini skills
|
|
550
516
|
- Installs Claude Code SessionStart hook for auto-updates
|
|
551
517
|
|
|
552
518
|
### titools auto-update
|
|
@@ -736,7 +702,7 @@ This pattern is documented across three TiTools skills: `ti-ui`, `ti-expert`, an
|
|
|
736
702
|
| Skill | SKILL.md | References |
|
|
737
703
|
| --------- | ----------------------------- | ----------------------------------------------------- |
|
|
738
704
|
| ti-expert | Architecture + Implementation | 21 files (patterns, testing, security, etc.) |
|
|
739
|
-
| purgetss | Setup + Critical Rules |
|
|
705
|
+
| purgetss | Setup + Critical Rules | 33 files (grid, animations, icons, class-index, SVG pipeline, etc.) |
|
|
740
706
|
| ti-ui | UI Rules + Platform Diffs | 14 files (layouts, lists, gestures, etc.) |
|
|
741
707
|
|
|
742
708
|
---
|
package/lib/cleanup.js
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
getAgentsSkillsDir,
|
|
11
11
|
getClaudeAgentsDir,
|
|
12
12
|
getCodexSkillsDir,
|
|
13
|
+
getGeminiSkillsDir,
|
|
13
14
|
} from './config.js';
|
|
14
15
|
import { detectPlatforms } from './platform.js';
|
|
15
16
|
import { existsSync, lstatSync, rmSync } from 'fs';
|
|
@@ -54,6 +55,20 @@ export function removeLegacySkillSymlinks(platformSkillsDir) {
|
|
|
54
55
|
return removeSkillSymlinks(platformSkillsDir, { legacyOnly: true });
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
// When the user de-selects some skills during an install, anything previously
|
|
59
|
+
// installed for those skills (in ~/.agents/skills/ and as platform symlinks)
|
|
60
|
+
// must be cleaned up so the on-disk state matches the user's selection.
|
|
61
|
+
export function removeUnselectedSkills(baseDir, selectedSkills) {
|
|
62
|
+
const skillsDir = getAgentsSkillsDir(baseDir);
|
|
63
|
+
const unselected = SKILLS.filter((s) => !selectedSkills.includes(s));
|
|
64
|
+
return removeEntriesAtDir(skillsDir, unselected, { recursive: true });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function removeUnselectedSymlinks(platformSkillsDir, selectedSkills) {
|
|
68
|
+
const unselected = SKILLS.filter((s) => !selectedSkills.includes(s));
|
|
69
|
+
return removeEntriesAtDir(platformSkillsDir, unselected, { recursive: true });
|
|
70
|
+
}
|
|
71
|
+
|
|
57
72
|
// Codex reads skills from the canonical ~/.agents/skills/, so any TiTools-managed
|
|
58
73
|
// symlinks at ~/.codex/skills/ from earlier versions are redundant and should be
|
|
59
74
|
// cleaned up. Targets both active and legacy skill names.
|
|
@@ -62,6 +77,15 @@ export function removeCodexRedundantSymlinks(baseDir) {
|
|
|
62
77
|
return removeSkillSymlinks(codexSkillsDir);
|
|
63
78
|
}
|
|
64
79
|
|
|
80
|
+
// Gemini CLI also auto-discovers skills from ~/.agents/skills/ per the
|
|
81
|
+
// agentskills.io standard. Symlinks at ~/.gemini/skills/ from v3.x and
|
|
82
|
+
// earlier produce "Skill conflict detected" warnings on Gemini startup
|
|
83
|
+
// because the same skill is found in both locations.
|
|
84
|
+
export function removeGeminiRedundantSymlinks(baseDir) {
|
|
85
|
+
const geminiSkillsDir = getGeminiSkillsDir(baseDir);
|
|
86
|
+
return removeSkillSymlinks(geminiSkillsDir);
|
|
87
|
+
}
|
|
88
|
+
|
|
65
89
|
export function removeSkills(baseDir, options = {}) {
|
|
66
90
|
const skillsDir = getAgentsSkillsDir(baseDir);
|
|
67
91
|
const skillList = getSkillList(options);
|
|
@@ -84,6 +108,7 @@ export function cleanupLegacyArtifacts(baseDir) {
|
|
|
84
108
|
}
|
|
85
109
|
|
|
86
110
|
removeCodexRedundantSymlinks(baseDir);
|
|
111
|
+
removeGeminiRedundantSymlinks(baseDir);
|
|
87
112
|
|
|
88
113
|
if (baseDir) {
|
|
89
114
|
removeSkills(undefined, { legacyOnly: true });
|
|
@@ -93,6 +118,7 @@ export function cleanupLegacyArtifacts(baseDir) {
|
|
|
93
118
|
removeLegacySkillSymlinks(platform.skillsDir);
|
|
94
119
|
}
|
|
95
120
|
removeCodexRedundantSymlinks(undefined);
|
|
121
|
+
removeGeminiRedundantSymlinks(undefined);
|
|
96
122
|
}
|
|
97
123
|
}
|
|
98
124
|
|
|
@@ -102,6 +128,9 @@ export default {
|
|
|
102
128
|
removeSkillSymlinks,
|
|
103
129
|
removeLegacySkillSymlinks,
|
|
104
130
|
removeCodexRedundantSymlinks,
|
|
131
|
+
removeGeminiRedundantSymlinks,
|
|
132
|
+
removeUnselectedSkills,
|
|
133
|
+
removeUnselectedSymlinks,
|
|
105
134
|
removeSkills,
|
|
106
135
|
removeAgents,
|
|
107
136
|
cleanupLegacyArtifacts,
|
package/lib/commands/agents.js
CHANGED
|
@@ -43,10 +43,12 @@ export async function agentsCommand(projectPath, options) {
|
|
|
43
43
|
console.log('Run this command from the project root.');
|
|
44
44
|
process.exit(1);
|
|
45
45
|
}
|
|
46
|
-
// Check for local vs global skills
|
|
46
|
+
// Check for local vs global skills.
|
|
47
|
+
// Gemini CLI auto-discovers from ./.agents/skills/ (agentskills.io standard),
|
|
48
|
+
// so it shares the same local path as AGENTS.md.
|
|
47
49
|
const localSkillsPaths = {
|
|
48
50
|
'CLAUDE.md': join(projectDir, '.claude', 'skills'),
|
|
49
|
-
'GEMINI.md': join(projectDir, '.
|
|
51
|
+
'GEMINI.md': join(projectDir, '.agents', 'skills'),
|
|
50
52
|
'AGENTS.md': join(projectDir, '.agents', 'skills'),
|
|
51
53
|
};
|
|
52
54
|
|
|
@@ -63,7 +65,7 @@ export async function agentsCommand(projectPath, options) {
|
|
|
63
65
|
if (options?.verbose) {
|
|
64
66
|
console.log(
|
|
65
67
|
chalk.gray(
|
|
66
|
-
`Searched: ${agentsSkillsDir} | ./.agents/skills, ./.claude/skills
|
|
68
|
+
`Searched: ${agentsSkillsDir} | ./.agents/skills, ./.claude/skills`
|
|
67
69
|
)
|
|
68
70
|
);
|
|
69
71
|
}
|
|
@@ -158,10 +160,9 @@ export async function agentsCommand(projectPath, options) {
|
|
|
158
160
|
let rootPath = '~/.agents/skills';
|
|
159
161
|
const localPath = localSkillsPaths[filename];
|
|
160
162
|
if (localPath && existsSync(localPath)) {
|
|
161
|
-
rootPath =
|
|
162
|
-
} else {
|
|
163
|
-
|
|
164
|
-
if (filename === 'GEMINI.md') rootPath = '~/.gemini/skills';
|
|
163
|
+
rootPath = filename === 'CLAUDE.md' ? './.claude/skills' : './.agents/skills';
|
|
164
|
+
} else if (filename === 'CLAUDE.md') {
|
|
165
|
+
rootPath = '~/.claude/skills';
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
addOrUpdateBlock(filePath, rootPath);
|
package/lib/commands/skills.js
CHANGED
|
@@ -22,6 +22,9 @@ import {
|
|
|
22
22
|
removeLegacySkillSymlinks,
|
|
23
23
|
removeSkills,
|
|
24
24
|
removeAgents,
|
|
25
|
+
removeUnselectedSkills,
|
|
26
|
+
removeUnselectedSymlinks,
|
|
27
|
+
cleanupLegacyArtifacts,
|
|
25
28
|
} from '../cleanup.js';
|
|
26
29
|
import {
|
|
27
30
|
installSkills,
|
|
@@ -32,7 +35,12 @@ import { agentsCommand } from './agents.js';
|
|
|
32
35
|
import { downloadRepoArchive } from '../downloader.js';
|
|
33
36
|
import { createSkillSymlinks } from '../symlink.js';
|
|
34
37
|
import { installHook } from '../hooks.js';
|
|
35
|
-
import {
|
|
38
|
+
import {
|
|
39
|
+
formatList,
|
|
40
|
+
isTitaniumProject,
|
|
41
|
+
readSkillDescription,
|
|
42
|
+
shortenSkillDescription,
|
|
43
|
+
} from '../utils.js';
|
|
36
44
|
import { mkdtemp } from 'fs/promises';
|
|
37
45
|
import { existsSync } from 'fs';
|
|
38
46
|
import { join, resolve } from 'path';
|
|
@@ -98,6 +106,22 @@ export async function skillsCommand(options) {
|
|
|
98
106
|
} else {
|
|
99
107
|
console.log(chalk.cyan('Mode: Global installation (user home)'));
|
|
100
108
|
}
|
|
109
|
+
const skillsLocation = isLocal
|
|
110
|
+
? './.agents/skills/'
|
|
111
|
+
: (customPath ? `${baseDir}/.agents/skills/` : '~/.agents/skills/');
|
|
112
|
+
console.log('');
|
|
113
|
+
console.log(
|
|
114
|
+
chalk.yellow('▸'),
|
|
115
|
+
'Skills install to',
|
|
116
|
+
chalk.cyan.bold(skillsLocation),
|
|
117
|
+
chalk.dim('(agentskills.io standard)')
|
|
118
|
+
);
|
|
119
|
+
console.log(
|
|
120
|
+
' ' + chalk.dim('Read directly by Gemini, Codex, Cursor, Cline, Amp, GitHub Copilot, +more.')
|
|
121
|
+
);
|
|
122
|
+
console.log(
|
|
123
|
+
' ' + chalk.dim('Below: extra symlink mirrors for Claude Code.')
|
|
124
|
+
);
|
|
101
125
|
console.log('');
|
|
102
126
|
|
|
103
127
|
// Detect installed platforms at the target base directory
|
|
@@ -119,9 +143,9 @@ export async function skillsCommand(options) {
|
|
|
119
143
|
}
|
|
120
144
|
|
|
121
145
|
if (detectedPlatforms.length === 0 && !options.path && !isLocal) {
|
|
122
|
-
console.log(chalk.yellow('No AI coding assistants detected globally.'));
|
|
123
|
-
console.log('Install
|
|
124
|
-
console.log('(
|
|
146
|
+
console.log(chalk.yellow('No AI coding assistants detected globally that need platform symlinks.'));
|
|
147
|
+
console.log('Install Claude Code if you want TiTools to create skill symlinks for it.');
|
|
148
|
+
console.log('(Gemini CLI and Codex CLI auto-discover skills from ~/.agents/skills/ — no platform-specific symlink needed.)');
|
|
125
149
|
console.log('Or use: titools install --local');
|
|
126
150
|
process.exit(1);
|
|
127
151
|
}
|
|
@@ -186,12 +210,6 @@ export async function skillsCommand(options) {
|
|
|
186
210
|
if (removeOnly) {
|
|
187
211
|
console.log(chalk.yellow('No platforms selected. Removing all platform symlinks and agents.'));
|
|
188
212
|
}
|
|
189
|
-
const showGeminiWarning = (() => {
|
|
190
|
-
if (removeOnly || !isLocal) return false;
|
|
191
|
-
const globalGemini = globalPlatforms.find((platform) => platform.name === 'gemini');
|
|
192
|
-
const geminiSelected = selectedPlatforms.some((platform) => platform.name === 'gemini');
|
|
193
|
-
return !!(geminiSelected && globalGemini && hasAnySkillSymlink(globalGemini.skillsDir));
|
|
194
|
-
})();
|
|
195
213
|
|
|
196
214
|
// Get repository directory (local or download)
|
|
197
215
|
const spinner = ora();
|
|
@@ -218,6 +236,52 @@ export async function skillsCommand(options) {
|
|
|
218
236
|
}
|
|
219
237
|
}
|
|
220
238
|
|
|
239
|
+
// Skill selection prompt — pre-checks all skills; the user can uncheck the
|
|
240
|
+
// ones they don't want. Skipped under --all (CI/automation) and removeOnly.
|
|
241
|
+
// Each line shows the skill name + a one-liner hint in dim gray, like
|
|
242
|
+
// skills.sh, so the rendered row height stays constant and the list does
|
|
243
|
+
// not "jump" when the cursor moves between skills with different-length
|
|
244
|
+
// descriptions.
|
|
245
|
+
let skillsToInstall = SKILLS;
|
|
246
|
+
if (!removeOnly && !options.all && !options.path) {
|
|
247
|
+
const skillChoices = SKILLS.map((name) => {
|
|
248
|
+
const fullDescription = readSkillDescription(repoDir, name);
|
|
249
|
+
const hint = shortenSkillDescription(fullDescription);
|
|
250
|
+
const label = hint
|
|
251
|
+
? `${name} ${chalk.dim(`(${hint})`)}`
|
|
252
|
+
: name;
|
|
253
|
+
return { name: label, value: name, short: name, checked: true };
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
try {
|
|
257
|
+
const selected = await checkbox({
|
|
258
|
+
message: 'Select skills to install:',
|
|
259
|
+
choices: [...skillChoices, new Separator(' ')],
|
|
260
|
+
theme: {
|
|
261
|
+
style: {
|
|
262
|
+
renderSelectedChoices: () => '',
|
|
263
|
+
prefix: () => chalk.cyan('?'),
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
if (selected.includes('cancel')) {
|
|
269
|
+
console.log('Cancelled.');
|
|
270
|
+
process.exit(0);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
skillsToInstall = SKILLS.filter((s) => selected.includes(s));
|
|
274
|
+
} catch (error) {
|
|
275
|
+
console.log('\nCancelled.');
|
|
276
|
+
process.exit(0);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (skillsToInstall.length === 0) {
|
|
280
|
+
console.log(chalk.yellow('No skills selected. Nothing to install.'));
|
|
281
|
+
process.exit(0);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
221
285
|
const selectedPlatformNames = new Set(selectedPlatforms.map((platform) => platform.name));
|
|
222
286
|
const removedPlatformNames = [];
|
|
223
287
|
const claudeSelected = selectedPlatformNames.has('claude');
|
|
@@ -226,8 +290,21 @@ export async function skillsCommand(options) {
|
|
|
226
290
|
if (!removeOnly) {
|
|
227
291
|
// Install skills
|
|
228
292
|
spinner.start('Installing skills...');
|
|
229
|
-
const skillsResult = await installSkills(repoDir, baseDir);
|
|
230
|
-
spinner.succeed(`${
|
|
293
|
+
const skillsResult = await installSkills(repoDir, baseDir, skillsToInstall);
|
|
294
|
+
spinner.succeed(`${skillsToInstall.length} skill${skillsToInstall.length !== 1 ? 's' : ''} installed`);
|
|
295
|
+
|
|
296
|
+
// If the user deselected some skills, sweep any previously-installed
|
|
297
|
+
// copies and their platform symlinks so on-disk state matches selection.
|
|
298
|
+
if (skillsToInstall.length !== SKILLS.length) {
|
|
299
|
+
removeUnselectedSkills(baseDir, skillsToInstall);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Sweep legacy skills, legacy agents, and redundant symlinks at platforms
|
|
303
|
+
// that no longer need TiTools-managed mirrors (Gemini, Codex). Without
|
|
304
|
+
// this, users that ran older TiTools versions keep stale symlinks at
|
|
305
|
+
// ~/.gemini/skills/ and ~/.codex/skills/ that Gemini reports as "Skill
|
|
306
|
+
// conflict detected" warnings on startup.
|
|
307
|
+
cleanupLegacyArtifacts(baseDir);
|
|
231
308
|
|
|
232
309
|
if (claudeSelected) {
|
|
233
310
|
// Install agents
|
|
@@ -251,19 +328,22 @@ export async function skillsCommand(options) {
|
|
|
251
328
|
// Create symlinks for selected platforms
|
|
252
329
|
for (const platform of selectedPlatforms) {
|
|
253
330
|
removeLegacySkillSymlinks(platform.skillsDir);
|
|
331
|
+
if (skillsToInstall.length !== SKILLS.length) {
|
|
332
|
+
removeUnselectedSymlinks(platform.skillsDir, skillsToInstall);
|
|
333
|
+
}
|
|
254
334
|
spinner.start(`Linking ${platform.displayName}...`);
|
|
255
335
|
const symlinkResult = await createSkillSymlinks(
|
|
256
336
|
platform.skillsDir,
|
|
257
|
-
|
|
337
|
+
skillsToInstall,
|
|
258
338
|
baseDir
|
|
259
339
|
);
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
340
|
+
if (symlinkResult.linked.length === skillsToInstall.length) {
|
|
341
|
+
spinner.succeed(`${platform.displayName}: Skills linked`);
|
|
342
|
+
} else {
|
|
343
|
+
spinner.warn(
|
|
344
|
+
`${platform.displayName}: ${symlinkResult.linked.length}/${skillsToInstall.length} skills linked`
|
|
345
|
+
);
|
|
346
|
+
}
|
|
267
347
|
}
|
|
268
348
|
|
|
269
349
|
// Install Claude Code auto-update hook
|
|
@@ -323,12 +403,27 @@ export async function skillsCommand(options) {
|
|
|
323
403
|
}
|
|
324
404
|
}
|
|
325
405
|
|
|
326
|
-
// Summary
|
|
406
|
+
// Summary — show where the skills landed and which agents read them.
|
|
407
|
+
// This is the "did it actually work" confirmation the user needs.
|
|
327
408
|
console.log('');
|
|
328
409
|
console.log(chalk.green('✓ skills sync complete!'));
|
|
329
|
-
if (
|
|
410
|
+
if (!removeOnly) {
|
|
330
411
|
console.log('');
|
|
331
|
-
console.log(
|
|
412
|
+
console.log(
|
|
413
|
+
' ' + chalk.bold(skillsLocation) + chalk.dim(' (') +
|
|
414
|
+
chalk.dim(skillsToInstall.length + ' skill' + (skillsToInstall.length !== 1 ? 's' : '')) +
|
|
415
|
+
chalk.dim(')')
|
|
416
|
+
);
|
|
417
|
+
console.log(
|
|
418
|
+
' ' + chalk.dim('• universal: ') +
|
|
419
|
+
'Gemini, Codex, Cursor, Cline, Amp, GitHub Copilot ' + chalk.dim('+more')
|
|
420
|
+
);
|
|
421
|
+
if (claudeSelected) {
|
|
422
|
+
console.log(
|
|
423
|
+
' ' + chalk.dim('• symlinked: ') +
|
|
424
|
+
'Claude Code ' + chalk.dim('(~/.claude/skills/)')
|
|
425
|
+
);
|
|
426
|
+
}
|
|
332
427
|
}
|
|
333
428
|
console.log('');
|
|
334
429
|
const isProjectDir = isTitaniumProject(process.cwd());
|
package/lib/config.js
CHANGED
|
@@ -33,18 +33,17 @@ export const SKILLS = [
|
|
|
33
33
|
'ti-expert',
|
|
34
34
|
'purgetss',
|
|
35
35
|
'ti-ui',
|
|
36
|
-
];
|
|
37
|
-
// Legacy skills to remove during updates/uninstall
|
|
38
|
-
// ti-api, ti-guides, ti-howtos, alloy-guides, alloy-howtos moved to https://github.com/tidev/skills in v3.0.0
|
|
39
|
-
export const LEGACY_SKILLS = [
|
|
40
|
-
'alloy-expert',
|
|
41
|
-
'ti-branding',
|
|
42
36
|
'ti-api',
|
|
43
37
|
'ti-guides',
|
|
44
38
|
'ti-howtos',
|
|
45
39
|
'alloy-guides',
|
|
46
40
|
'alloy-howtos',
|
|
47
41
|
];
|
|
42
|
+
// Legacy skills to remove during updates/uninstall
|
|
43
|
+
export const LEGACY_SKILLS = [
|
|
44
|
+
'alloy-expert',
|
|
45
|
+
'ti-branding',
|
|
46
|
+
];
|
|
48
47
|
|
|
49
48
|
// Agents to install
|
|
50
49
|
export const AGENTS = [
|
|
@@ -65,6 +64,14 @@ export const getCodexSkillsDir = (baseDir = os.homedir()) => path.join(baseDir,
|
|
|
65
64
|
export const getConfigDir = () => path.join(os.homedir(), '.titools');
|
|
66
65
|
|
|
67
66
|
// AI platform detection
|
|
67
|
+
//
|
|
68
|
+
// Only platforms that need TiTools-managed symlinks appear here.
|
|
69
|
+
// Gemini CLI and Codex CLI auto-discover skills from the canonical
|
|
70
|
+
// ~/.agents/skills/ per the agentskills.io standard, so creating
|
|
71
|
+
// platform-specific symlinks at ~/.gemini/skills/ or ~/.codex/skills/
|
|
72
|
+
// would be redundant — and in Gemini's case actively harmful, since it
|
|
73
|
+
// reads both locations and reports "Skill conflict detected" warnings
|
|
74
|
+
// when the same skill exists in both.
|
|
68
75
|
export const getPlatforms = (baseDir = os.homedir()) => [
|
|
69
76
|
{
|
|
70
77
|
name: 'claude',
|
|
@@ -72,15 +79,6 @@ export const getPlatforms = (baseDir = os.homedir()) => [
|
|
|
72
79
|
skillsDir: getClaudeSkillsDir(baseDir),
|
|
73
80
|
configDir: path.join(baseDir, '.claude'),
|
|
74
81
|
},
|
|
75
|
-
{
|
|
76
|
-
name: 'gemini',
|
|
77
|
-
displayName: 'Gemini CLI',
|
|
78
|
-
skillsDir: getGeminiSkillsDir(baseDir),
|
|
79
|
-
configDir: path.join(baseDir, '.gemini'),
|
|
80
|
-
},
|
|
81
|
-
// Codex CLI is intentionally omitted: it auto-discovers skills from the
|
|
82
|
-
// canonical ~/.agents/skills/ per the agentskills.io standard, so a
|
|
83
|
-
// platform-specific symlink at ~/.codex/skills/ would be redundant.
|
|
84
82
|
];
|
|
85
83
|
|
|
86
84
|
// Files to install
|
package/lib/installer.js
CHANGED
|
@@ -69,12 +69,14 @@ export async function installSkill(repoDir, skillName, baseDir = os.homedir()) {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
|
-
* Install
|
|
72
|
+
* Install skills to the agents skills directory
|
|
73
73
|
* @param {string} repoDir - Repository directory
|
|
74
74
|
* @param {string} baseDir - Base directory for installation
|
|
75
|
+
* @param {string[]} [skillsToInstall] - Subset of skills to install (defaults to all SKILLS)
|
|
75
76
|
* @returns {Promise<Object>} Results object with success/failure counts
|
|
76
77
|
*/
|
|
77
|
-
export async function installSkills(repoDir, baseDir = os.homedir()) {
|
|
78
|
+
export async function installSkills(repoDir, baseDir = os.homedir(), skillsToInstall) {
|
|
79
|
+
const list = skillsToInstall || SKILLS;
|
|
78
80
|
const results = {
|
|
79
81
|
installed: [],
|
|
80
82
|
failed: [],
|
|
@@ -91,7 +93,7 @@ export async function installSkills(repoDir, baseDir = os.homedir()) {
|
|
|
91
93
|
results.failed.push(...legacyGlobal.failed);
|
|
92
94
|
}
|
|
93
95
|
|
|
94
|
-
for (const skill of
|
|
96
|
+
for (const skill of list) {
|
|
95
97
|
if (await installSkill(repoDir, skill, baseDir)) {
|
|
96
98
|
results.installed.push(skill);
|
|
97
99
|
} else {
|
package/lib/utils.js
CHANGED
|
@@ -14,6 +14,42 @@ const __dirname = dirname(__filename);
|
|
|
14
14
|
const packageRoot = resolve(__dirname, '..');
|
|
15
15
|
const packageSkillsDir = join(packageRoot, 'skills');
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Read the description field from a skill's SKILL.md frontmatter.
|
|
19
|
+
* @param {string} repoDir - Repository directory containing skills/
|
|
20
|
+
* @param {string} skillName - Skill name (directory under skills/)
|
|
21
|
+
* @returns {string} Description text, or empty string if not available.
|
|
22
|
+
*/
|
|
23
|
+
export function readSkillDescription(repoDir, skillName) {
|
|
24
|
+
try {
|
|
25
|
+
const skillPath = join(repoDir, 'skills', skillName, 'SKILL.md');
|
|
26
|
+
const content = readFileSync(skillPath, 'utf8');
|
|
27
|
+
const fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
28
|
+
if (!fmMatch) return '';
|
|
29
|
+
const descMatch = fmMatch[1].match(/^description:\s*["']?(.+?)["']?\s*$/m);
|
|
30
|
+
return descMatch ? descMatch[1].trim() : '';
|
|
31
|
+
} catch {
|
|
32
|
+
return '';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Compress a skill description to a one-line summary suitable for an inline
|
|
38
|
+
* checkbox preview. Picks the first segment of the description and trims it
|
|
39
|
+
* to `maxLen` characters, appending an ellipsis when the source is longer.
|
|
40
|
+
*
|
|
41
|
+
* @param {string} description - The full SKILL.md description.
|
|
42
|
+
* @param {number} maxLen - Maximum characters of the output (excluding ellipsis).
|
|
43
|
+
* @returns {string} Trimmed one-liner, or empty string if input was empty.
|
|
44
|
+
*/
|
|
45
|
+
export function shortenSkillDescription(description, maxLen = 60) {
|
|
46
|
+
if (!description) return '';
|
|
47
|
+
let firstSegment = description.split(/\s*[—.:;]\s*/)[0].trim();
|
|
48
|
+
firstSegment = firstSegment.replace(/\s+/g, ' ');
|
|
49
|
+
if (firstSegment.length <= maxLen) return firstSegment;
|
|
50
|
+
return firstSegment.slice(0, maxLen).trimEnd() + '…';
|
|
51
|
+
}
|
|
52
|
+
|
|
17
53
|
/**
|
|
18
54
|
* Check if Titanium knowledge block exists in a file
|
|
19
55
|
* @param {string} filePath - Path to the file
|