taketomarket 2.0.0 → 2.1.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/.claude-plugin/plugin.json +1 -1
- package/install.js +98 -86
- package/package.json +1 -1
- package/skills/ttm-update/SKILL.md +29 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "taketomarket",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Marketing operating system for Claude Code. Spec-driven campaigns with positioning-as-invariant enforcement, quality gate walls, and compound learnings.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "takeToMarket"
|
package/install.js
CHANGED
|
@@ -56,44 +56,34 @@ function parseRuntimeChoices(input) {
|
|
|
56
56
|
/**
|
|
57
57
|
* Build the install target map for all known runtimes.
|
|
58
58
|
* @param {string} [homeDir] - Home directory (injectable for tests)
|
|
59
|
-
* @returns {Object.<string, {label,
|
|
59
|
+
* @returns {Object.<string, {label, skillsDir, parentDir}>}
|
|
60
60
|
*/
|
|
61
61
|
function buildRuntimeTargets(homeDir = os.homedir()) {
|
|
62
62
|
return {
|
|
63
63
|
claude: {
|
|
64
64
|
label: 'Claude Code',
|
|
65
|
-
|
|
65
|
+
skillsDir: path.join(homeDir, '.claude', 'skills'),
|
|
66
66
|
parentDir: path.join(homeDir, '.claude'),
|
|
67
|
-
register: true,
|
|
68
|
-
partial: false,
|
|
69
67
|
},
|
|
70
68
|
codex: {
|
|
71
69
|
label: 'Codex (OpenAI)',
|
|
72
|
-
|
|
70
|
+
skillsDir: path.join(homeDir, '.codex', 'skills'),
|
|
73
71
|
parentDir: path.join(homeDir, '.codex'),
|
|
74
|
-
register: false,
|
|
75
|
-
partial: true,
|
|
76
72
|
},
|
|
77
73
|
cursor: {
|
|
78
74
|
label: 'Cursor',
|
|
79
|
-
|
|
75
|
+
skillsDir: path.join(homeDir, '.cursor', 'skills'),
|
|
80
76
|
parentDir: path.join(homeDir, '.cursor'),
|
|
81
|
-
register: false,
|
|
82
|
-
partial: true,
|
|
83
77
|
},
|
|
84
78
|
windsurf: {
|
|
85
79
|
label: 'Windsurf',
|
|
86
|
-
|
|
80
|
+
skillsDir: path.join(homeDir, '.codeium', 'windsurf', 'skills'),
|
|
87
81
|
parentDir: path.join(homeDir, '.codeium'),
|
|
88
|
-
register: false,
|
|
89
|
-
partial: true,
|
|
90
82
|
},
|
|
91
83
|
gemini: {
|
|
92
84
|
label: 'Gemini CLI',
|
|
93
|
-
|
|
85
|
+
skillsDir: path.join(homeDir, '.gemini', 'skills'),
|
|
94
86
|
parentDir: path.join(homeDir, '.gemini'),
|
|
95
|
-
register: false,
|
|
96
|
-
partial: true,
|
|
97
87
|
},
|
|
98
88
|
};
|
|
99
89
|
}
|
|
@@ -183,7 +173,7 @@ async function promptRuntimeSelection(args, homeDir = os.homedir()) {
|
|
|
183
173
|
const result = [];
|
|
184
174
|
for (const name of choices) {
|
|
185
175
|
if (name === 'custom') {
|
|
186
|
-
result.push({ label: 'Custom',
|
|
176
|
+
result.push({ label: 'Custom', skillsDir: customPath, parentDir: null });
|
|
187
177
|
} else {
|
|
188
178
|
result.push(allTargets[name]);
|
|
189
179
|
}
|
|
@@ -280,6 +270,68 @@ function copyDirSync(src, dest) {
|
|
|
280
270
|
}
|
|
281
271
|
}
|
|
282
272
|
|
|
273
|
+
// ── Package Base & Per-Runtime Skill Install ──────────────────────────────────
|
|
274
|
+
|
|
275
|
+
const PACKAGE_BASE_DIRS = ['workflows', 'templates', 'references', 'playbooks', 'gates', 'bin', 'agents'];
|
|
276
|
+
const PACKAGE_BASE_FILES = ['settings.json', 'package.json'];
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Copy non-skill package files to ~/.taketomarket/ (shared across all runtimes).
|
|
280
|
+
* @param {string} packageRoot - Source npm package root
|
|
281
|
+
* @param {string} [homeDir]
|
|
282
|
+
*/
|
|
283
|
+
function copyPackageBase(packageRoot, homeDir = os.homedir()) {
|
|
284
|
+
const dest = path.join(homeDir, '.taketomarket');
|
|
285
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
286
|
+
|
|
287
|
+
for (const dir of PACKAGE_BASE_DIRS) {
|
|
288
|
+
const src = path.join(packageRoot, dir);
|
|
289
|
+
if (dirExists(src)) {
|
|
290
|
+
copyDirSync(src, path.join(dest, dir));
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
for (const file of PACKAGE_BASE_FILES) {
|
|
295
|
+
const src = path.join(packageRoot, file);
|
|
296
|
+
if (fileExists(src)) {
|
|
297
|
+
fs.copyFileSync(src, path.join(dest, file));
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Install individual skills into a runtime's skills directory.
|
|
304
|
+
* Replaces ${CLAUDE_PLUGIN_ROOT} in SKILL.md with absolute path to ~/.taketomarket.
|
|
305
|
+
* @param {string} skillsDir - Runtime's skills base dir (e.g. ~/.claude/skills/)
|
|
306
|
+
* @param {string} packageRoot - Source npm package root
|
|
307
|
+
* @param {string} [homeDir]
|
|
308
|
+
* @returns {number} Number of skills installed
|
|
309
|
+
*/
|
|
310
|
+
function installSkillsForRuntime(skillsDir, packageRoot, homeDir = os.homedir()) {
|
|
311
|
+
const packageBase = path.join(homeDir, '.taketomarket');
|
|
312
|
+
const srcSkillsDir = path.join(packageRoot, 'skills');
|
|
313
|
+
if (!dirExists(srcSkillsDir)) return 0;
|
|
314
|
+
|
|
315
|
+
fs.mkdirSync(skillsDir, { recursive: true });
|
|
316
|
+
|
|
317
|
+
let count = 0;
|
|
318
|
+
const entries = fs.readdirSync(srcSkillsDir, { withFileTypes: true });
|
|
319
|
+
for (const entry of entries) {
|
|
320
|
+
if (!entry.isDirectory()) continue;
|
|
321
|
+
const skillMdSrc = path.join(srcSkillsDir, entry.name, 'SKILL.md');
|
|
322
|
+
if (!fileExists(skillMdSrc)) continue;
|
|
323
|
+
|
|
324
|
+
let content = fs.readFileSync(skillMdSrc, 'utf8');
|
|
325
|
+
content = content.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, packageBase);
|
|
326
|
+
|
|
327
|
+
const destSkillDir = path.join(skillsDir, entry.name);
|
|
328
|
+
fs.mkdirSync(destSkillDir, { recursive: true });
|
|
329
|
+
fs.writeFileSync(path.join(destSkillDir, 'SKILL.md'), content, 'utf8');
|
|
330
|
+
count++;
|
|
331
|
+
}
|
|
332
|
+
return count;
|
|
333
|
+
}
|
|
334
|
+
|
|
283
335
|
// ── Plugin Registration ───────────────────────────────────────────────────────
|
|
284
336
|
|
|
285
337
|
/**
|
|
@@ -411,33 +463,22 @@ function shouldProceed(yesFlag) {
|
|
|
411
463
|
/**
|
|
412
464
|
* Read Claude Code install status for the checkStatus output.
|
|
413
465
|
* @param {string} [homeDir]
|
|
414
|
-
* @returns {{ installed: boolean,
|
|
466
|
+
* @returns {{ installed: boolean, skillCount: number, dir: string }}
|
|
415
467
|
*/
|
|
416
468
|
function getClaudeStatus(homeDir = os.homedir()) {
|
|
417
|
-
const
|
|
418
|
-
const
|
|
419
|
-
|
|
469
|
+
const skillsDir = path.join(homeDir, '.claude', 'skills');
|
|
470
|
+
const probeSkill = path.join(skillsDir, 'ttm-init', 'SKILL.md');
|
|
471
|
+
const installed = fileExists(probeSkill);
|
|
472
|
+
if (!installed) return { installed: false, skillCount: 0, dir: skillsDir };
|
|
420
473
|
|
|
421
|
-
const skillsDir = path.join(pluginDir, 'skills');
|
|
422
474
|
let skillCount = 0;
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
} catch { /* ignore */ }
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
const registryPath = path.join(homeDir, '.claude', 'plugins', 'installed_plugins.json');
|
|
432
|
-
let registered = false;
|
|
433
|
-
if (fileExists(registryPath)) {
|
|
434
|
-
try {
|
|
435
|
-
const reg = JSON.parse(fs.readFileSync(registryPath, 'utf8'));
|
|
436
|
-
registered = !!(reg.plugins && reg.plugins['taketomarket@npm']);
|
|
437
|
-
} catch { /* ignore */ }
|
|
438
|
-
}
|
|
475
|
+
try {
|
|
476
|
+
skillCount = fs.readdirSync(skillsDir, { withFileTypes: true })
|
|
477
|
+
.filter(e => e.isDirectory() && e.name.startsWith('ttm-') && fileExists(path.join(skillsDir, e.name, 'SKILL.md')))
|
|
478
|
+
.length;
|
|
479
|
+
} catch { /* ignore */ }
|
|
439
480
|
|
|
440
|
-
return { installed: true,
|
|
481
|
+
return { installed: true, skillCount, dir: skillsDir };
|
|
441
482
|
}
|
|
442
483
|
|
|
443
484
|
/**
|
|
@@ -453,8 +494,7 @@ function checkStatus(version, homeDir = os.homedir()) {
|
|
|
453
494
|
|
|
454
495
|
const claude = getClaudeStatus(homeDir);
|
|
455
496
|
if (claude.installed) {
|
|
456
|
-
console.log(`Claude Code: INSTALLED (${claude.skillCount} skills
|
|
457
|
-
console.log(` registered: ${claude.registered ? 'yes (installed_plugins.json)' : 'NO — slash commands will not appear'}`);
|
|
497
|
+
console.log(`Claude Code: INSTALLED (${claude.skillCount} skills at ${claude.dir.replace(homeDir, '~')})`);
|
|
458
498
|
} else {
|
|
459
499
|
console.log('Claude Code: NOT INSTALLED');
|
|
460
500
|
}
|
|
@@ -462,8 +502,8 @@ function checkStatus(version, homeDir = os.homedir()) {
|
|
|
462
502
|
for (const name of ['codex', 'cursor', 'windsurf', 'gemini']) {
|
|
463
503
|
const t = targets[name];
|
|
464
504
|
const label = t.label.padEnd(12);
|
|
465
|
-
if (t.
|
|
466
|
-
console.log(`${label} INSTALLED (${t.
|
|
505
|
+
if (t.skillsDir && dirExists(t.skillsDir)) {
|
|
506
|
+
console.log(`${label} INSTALLED (${t.skillsDir.replace(homeDir, '~')})`);
|
|
467
507
|
} else {
|
|
468
508
|
console.log(`${label} NOT INSTALLED`);
|
|
469
509
|
}
|
|
@@ -493,7 +533,7 @@ async function confirmInstall(targets, version, yesFlag) {
|
|
|
493
533
|
console.log('');
|
|
494
534
|
console.log('This will install to:');
|
|
495
535
|
for (const t of targets) {
|
|
496
|
-
const shortDir = t.
|
|
536
|
+
const shortDir = t.skillsDir.replace(os.homedir(), '~');
|
|
497
537
|
console.log(` ${shortDir.padEnd(45)} (${t.label})`);
|
|
498
538
|
}
|
|
499
539
|
console.log('');
|
|
@@ -619,57 +659,25 @@ Options:
|
|
|
619
659
|
// Confirmation
|
|
620
660
|
await confirmInstall(targets, VERSION, yesFlag);
|
|
621
661
|
|
|
662
|
+
// Copy shared package files once
|
|
663
|
+
console.log('');
|
|
664
|
+
console.log('Copying package files to ~/.taketomarket/...');
|
|
665
|
+
copyPackageBase(PACKAGE_ROOT);
|
|
666
|
+
|
|
622
667
|
// Install loop
|
|
623
668
|
const results = [];
|
|
624
669
|
for (const target of targets) {
|
|
625
670
|
console.log('');
|
|
626
|
-
console.log(`Installing to ${target.label}...`);
|
|
671
|
+
console.log(`Installing skills to ${target.label}...`);
|
|
627
672
|
|
|
628
673
|
if (target.parentDir && !dirExists(target.parentDir)) {
|
|
629
|
-
console.warn(` Warning: ${target.label}
|
|
630
|
-
console.warn(' Installing anyway — files will be ready when you install the runtime.');
|
|
674
|
+
console.warn(` Warning: ${target.label} not detected (${target.parentDir} not found). Installing anyway.`);
|
|
631
675
|
}
|
|
632
676
|
|
|
633
677
|
try {
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
for (const dir of DIRS_TO_COPY) {
|
|
640
|
-
const srcDir = path.join(PACKAGE_ROOT, dir);
|
|
641
|
-
if (dirExists(srcDir)) {
|
|
642
|
-
console.log(` Copying ${dir}/`);
|
|
643
|
-
copyDirSync(srcDir, path.join(target.dir, dir));
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
for (const file of FILES_TO_COPY) {
|
|
648
|
-
const srcFile = path.join(PACKAGE_ROOT, file);
|
|
649
|
-
if (fileExists(srcFile)) {
|
|
650
|
-
console.log(` Copying ${file}`);
|
|
651
|
-
const destFile = path.join(target.dir, file);
|
|
652
|
-
fs.mkdirSync(path.dirname(destFile), { recursive: true });
|
|
653
|
-
fs.copyFileSync(srcFile, destFile);
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
if (target.register) {
|
|
658
|
-
registerPlugin(target.dir, VERSION);
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
const validation = validateInstall(target.dir);
|
|
662
|
-
printResults(validation);
|
|
663
|
-
const failures = validation.filter(r => r.status === 'fail');
|
|
664
|
-
|
|
665
|
-
if (failures.length > 0) {
|
|
666
|
-
results.push({ target, success: false, reason: 'validation failed' });
|
|
667
|
-
} else {
|
|
668
|
-
if (target.partial) {
|
|
669
|
-
console.log(` [PARTIAL] ${target.label}: files copied — slash command registration coming in a future update`);
|
|
670
|
-
}
|
|
671
|
-
results.push({ target, success: true });
|
|
672
|
-
}
|
|
678
|
+
const count = installSkillsForRuntime(target.skillsDir, PACKAGE_ROOT);
|
|
679
|
+
console.log(` Installed ${count} skills → ${target.skillsDir.replace(os.homedir(), '~')}`);
|
|
680
|
+
results.push({ target, success: true });
|
|
673
681
|
} catch (err) {
|
|
674
682
|
console.error(` Error: ${err.message}`);
|
|
675
683
|
results.push({ target, success: false, reason: err.message });
|
|
@@ -726,6 +734,8 @@ module.exports = {
|
|
|
726
734
|
printResults,
|
|
727
735
|
DIRS_TO_COPY,
|
|
728
736
|
FILES_TO_COPY,
|
|
737
|
+
PACKAGE_BASE_DIRS,
|
|
738
|
+
PACKAGE_BASE_FILES,
|
|
729
739
|
registerPlugin,
|
|
730
740
|
parseRuntimeChoices,
|
|
731
741
|
buildRuntimeTargets,
|
|
@@ -736,5 +746,7 @@ module.exports = {
|
|
|
736
746
|
checkStatus,
|
|
737
747
|
confirmInstall,
|
|
738
748
|
printInstallSummary,
|
|
749
|
+
copyPackageBase,
|
|
750
|
+
installSkillsForRuntime,
|
|
739
751
|
PACKAGE_ROOT,
|
|
740
752
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "taketomarket",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Marketing operating system for Claude Code. Spec-driven campaigns with positioning-as-invariant enforcement, quality gate walls, and compound learnings.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ttm-update
|
|
3
|
+
description: >
|
|
4
|
+
Check for takeToMarket updates and upgrade to the latest version. Compares
|
|
5
|
+
installed version against npm registry and runs installer if newer version found.
|
|
6
|
+
disable-model-invocation: false
|
|
7
|
+
allowed-tools: Bash Read
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# /ttm-update
|
|
11
|
+
|
|
12
|
+
Check if takeToMarket needs updating and upgrade if available.
|
|
13
|
+
|
|
14
|
+
1. Get current installed version:
|
|
15
|
+
```bash
|
|
16
|
+
cat $HOME/.taketomarket/package.json 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin).get('version','unknown'))" 2>/dev/null || echo "unknown"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
2. Get latest version from npm:
|
|
20
|
+
```bash
|
|
21
|
+
npm show taketomarket version 2>/dev/null || echo "unknown"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
3. Compare versions. If a newer version is available (latest > installed), run:
|
|
25
|
+
```bash
|
|
26
|
+
npx taketomarket@latest --yes
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
4. If already up to date, confirm: "takeToMarket vX.X.X is up to date."
|