tcsetup 1.2.0 → 1.3.1
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 +25 -3
- package/bin/cli.js +34 -86
- package/package.json +2 -1
- package/src/installer.js +86 -0
- package/src/updater.js +116 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# tcsetup
|
|
2
2
|
|
|
3
|
-
Bootstrap a
|
|
3
|
+
Bootstrap and update a project with the full TC toolchain in one command.
|
|
4
4
|
|
|
5
5
|
## What it installs
|
|
6
6
|
|
|
@@ -9,21 +9,43 @@ Bootstrap a new project with the full TC toolchain in one command.
|
|
|
9
9
|
| 1 | [BMAD Method](https://github.com/bmad-code-org/BMAD-METHOD) | `npx bmad-method install` |
|
|
10
10
|
| 2 | [Spec Kit](https://github.com/github/spec-kit) | `specify init --here --ai claude` |
|
|
11
11
|
| 3 | [Agreement System](https://github.com/tcanaud/agreement-system) | `npx agreement-system init --yes` |
|
|
12
|
-
| 4 | [
|
|
12
|
+
| 4 | [ADR System](https://github.com/tcanaud/adr-system) | `npx adr-system init --yes` |
|
|
13
|
+
| 5 | [Mermaid Workbench](https://github.com/tcanaud/mermaid-workbench) | `npx mermaid-workbench init` |
|
|
14
|
+
| 6 | [Feature Lifecycle](https://github.com/tcanaud/feature-lifecycle) | `npx feature-lifecycle init --yes` |
|
|
13
15
|
|
|
14
16
|
## Usage
|
|
15
17
|
|
|
18
|
+
### Init (onboard a new project)
|
|
19
|
+
|
|
16
20
|
```bash
|
|
17
21
|
npx tcsetup
|
|
22
|
+
# or explicitly:
|
|
23
|
+
npx tcsetup init
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Update (refresh an existing project)
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx tcsetup update
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Detects which tools are installed (by marker directories), updates their npm packages to latest, runs each tool's update command to refresh commands/templates, and refreshes tcsetup's own Claude Code command files. User data is never touched.
|
|
33
|
+
|
|
34
|
+
### Help
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx tcsetup help
|
|
18
38
|
```
|
|
19
39
|
|
|
20
|
-
### Skip specific steps
|
|
40
|
+
### Skip specific steps (init only)
|
|
21
41
|
|
|
22
42
|
```bash
|
|
23
43
|
npx tcsetup --skip-bmad
|
|
24
44
|
npx tcsetup --skip-speckit
|
|
25
45
|
npx tcsetup --skip-agreements
|
|
46
|
+
npx tcsetup --skip-adr
|
|
26
47
|
npx tcsetup --skip-mermaid
|
|
48
|
+
npx tcsetup --skip-lifecycle
|
|
27
49
|
```
|
|
28
50
|
|
|
29
51
|
Multiple flags can be combined:
|
package/bin/cli.js
CHANGED
|
@@ -1,24 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { readFileSync, mkdirSync, copyFileSync, existsSync } from "node:fs";
|
|
3
|
+
import { argv, exit } from "node:process";
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
6
5
|
import { fileURLToPath } from "node:url";
|
|
7
6
|
import { dirname, join } from "node:path";
|
|
7
|
+
import { install } from "../src/installer.js";
|
|
8
|
+
import { update } from "../src/updater.js";
|
|
8
9
|
|
|
9
10
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
11
|
const { version } = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf8"));
|
|
11
12
|
|
|
12
|
-
const
|
|
13
|
+
const command = argv[2];
|
|
14
|
+
const flags = argv.slice(3);
|
|
13
15
|
|
|
14
16
|
const HELP = `
|
|
15
|
-
tcsetup — Bootstrap
|
|
17
|
+
tcsetup v${version} — Bootstrap and update the TC toolchain.
|
|
16
18
|
|
|
17
19
|
Usage:
|
|
18
|
-
npx tcsetup Run all setup steps
|
|
20
|
+
npx tcsetup Run all setup steps (same as init)
|
|
21
|
+
npx tcsetup init Install the full TC toolchain
|
|
22
|
+
npx tcsetup update Update all installed TC tools to latest
|
|
19
23
|
npx tcsetup help Show this help message
|
|
20
24
|
|
|
21
|
-
Options:
|
|
25
|
+
Options (init):
|
|
22
26
|
--skip-bmad Skip BMAD Method install
|
|
23
27
|
--skip-speckit Skip Spec Kit init
|
|
24
28
|
--skip-agreements Skip Agreement System init
|
|
@@ -27,84 +31,28 @@ Options:
|
|
|
27
31
|
--skip-lifecycle Skip Feature Lifecycle Tracker init
|
|
28
32
|
`;
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
flag: "--skip-adr",
|
|
54
|
-
cmd: "npx adr-system init --yes",
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
name: "Mermaid Workbench",
|
|
58
|
-
flag: "--skip-mermaid",
|
|
59
|
-
cmd: "npx mermaid-workbench init",
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
name: "Feature Lifecycle Tracker",
|
|
63
|
-
flag: "--skip-lifecycle",
|
|
64
|
-
cmd: "npx feature-lifecycle init --yes",
|
|
65
|
-
},
|
|
66
|
-
];
|
|
67
|
-
|
|
68
|
-
console.log(`\n tcsetup v${version}\n`);
|
|
69
|
-
|
|
70
|
-
let current = 0;
|
|
71
|
-
const total = steps.filter((s) => !flags.includes(s.flag)).length;
|
|
72
|
-
|
|
73
|
-
for (const step of steps) {
|
|
74
|
-
if (flags.includes(step.flag)) {
|
|
75
|
-
console.log(` [skip] ${step.name} (${step.flag})\n`);
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
current++;
|
|
80
|
-
console.log(` [${current}/${total}] ${step.name}`);
|
|
81
|
-
console.log(` > ${step.cmd}\n`);
|
|
82
|
-
|
|
83
|
-
try {
|
|
84
|
-
execSync(step.cmd, { stdio: "inherit" });
|
|
85
|
-
console.log();
|
|
86
|
-
} catch (err) {
|
|
87
|
-
console.error(`\n ⚠ ${step.name} failed (exit code ${err.status}).`);
|
|
88
|
-
console.error(` Continuing with remaining steps...\n`);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// ── Install Claude Code commands ──────────────────────
|
|
93
|
-
const commandsSource = join(__dirname, "..", "commands");
|
|
94
|
-
const commandsDest = join(process.cwd(), ".claude", "commands");
|
|
95
|
-
|
|
96
|
-
if (existsSync(commandsSource)) {
|
|
97
|
-
const commandFiles = ["tcsetup.onboard.md", "feature.workflow.md"];
|
|
98
|
-
mkdirSync(commandsDest, { recursive: true });
|
|
99
|
-
for (const file of commandFiles) {
|
|
100
|
-
const src = join(commandsSource, file);
|
|
101
|
-
const dest = join(commandsDest, file);
|
|
102
|
-
if (existsSync(src)) {
|
|
103
|
-
copyFileSync(src, dest);
|
|
104
|
-
console.log(` [cmd] Installed .claude/commands/${file}`);
|
|
34
|
+
switch (command) {
|
|
35
|
+
case "init":
|
|
36
|
+
install(flags);
|
|
37
|
+
break;
|
|
38
|
+
case "update":
|
|
39
|
+
update(flags);
|
|
40
|
+
break;
|
|
41
|
+
case "help":
|
|
42
|
+
case "--help":
|
|
43
|
+
case "-h":
|
|
44
|
+
console.log(HELP);
|
|
45
|
+
break;
|
|
46
|
+
case undefined:
|
|
47
|
+
install([]);
|
|
48
|
+
break;
|
|
49
|
+
default:
|
|
50
|
+
// Flags without subcommand (e.g., npx tcsetup --skip-bmad) → treat as init
|
|
51
|
+
if (command.startsWith("-")) {
|
|
52
|
+
install(argv.slice(2));
|
|
53
|
+
} else {
|
|
54
|
+
console.error(` Unknown command: ${command}\n`);
|
|
55
|
+
console.log(HELP);
|
|
56
|
+
exit(1);
|
|
105
57
|
}
|
|
106
|
-
}
|
|
107
|
-
console.log();
|
|
108
58
|
}
|
|
109
|
-
|
|
110
|
-
console.log(" Done! Project setup complete.\n");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tcsetup",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Bootstrap a new project with BMAD, Spec Kit, Agreement System, and Mermaid Workbench in one command.",
|
|
6
6
|
"bin": {
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
24
|
"bin/",
|
|
25
|
+
"src/",
|
|
25
26
|
"commands/"
|
|
26
27
|
],
|
|
27
28
|
"engines": {
|
package/src/installer.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { readFileSync, mkdirSync, copyFileSync, existsSync } from "node:fs";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const { version } = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf8"));
|
|
8
|
+
|
|
9
|
+
const steps = [
|
|
10
|
+
{
|
|
11
|
+
name: "BMAD Method",
|
|
12
|
+
flag: "--skip-bmad",
|
|
13
|
+
cmd: "npx bmad-method install",
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: "Spec Kit",
|
|
17
|
+
flag: "--skip-speckit",
|
|
18
|
+
cmd: "specify init --here --ai claude",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: "Agreement System",
|
|
22
|
+
flag: "--skip-agreements",
|
|
23
|
+
cmd: "npx agreement-system init --yes",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: "ADR System",
|
|
27
|
+
flag: "--skip-adr",
|
|
28
|
+
cmd: "npx adr-system init --yes",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "Mermaid Workbench",
|
|
32
|
+
flag: "--skip-mermaid",
|
|
33
|
+
cmd: "npx mermaid-workbench init",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "Feature Lifecycle Tracker",
|
|
37
|
+
flag: "--skip-lifecycle",
|
|
38
|
+
cmd: "npx feature-lifecycle init --yes",
|
|
39
|
+
},
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
export function install(flags = []) {
|
|
43
|
+
console.log(`\n tcsetup v${version}\n`);
|
|
44
|
+
|
|
45
|
+
let current = 0;
|
|
46
|
+
const total = steps.filter((s) => !flags.includes(s.flag)).length;
|
|
47
|
+
|
|
48
|
+
for (const step of steps) {
|
|
49
|
+
if (flags.includes(step.flag)) {
|
|
50
|
+
console.log(` [skip] ${step.name} (${step.flag})\n`);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
current++;
|
|
55
|
+
console.log(` [${current}/${total}] ${step.name}`);
|
|
56
|
+
console.log(` > ${step.cmd}\n`);
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
execSync(step.cmd, { stdio: "inherit" });
|
|
60
|
+
console.log();
|
|
61
|
+
} catch (err) {
|
|
62
|
+
console.error(`\n ⚠ ${step.name} failed (exit code ${err.status}).`);
|
|
63
|
+
console.error(` Continuing with remaining steps...\n`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ── Install Claude Code commands ──────────────────────
|
|
68
|
+
const commandsSource = join(__dirname, "..", "commands");
|
|
69
|
+
const commandsDest = join(process.cwd(), ".claude", "commands");
|
|
70
|
+
|
|
71
|
+
if (existsSync(commandsSource)) {
|
|
72
|
+
const commandFiles = ["tcsetup.onboard.md", "feature.workflow.md"];
|
|
73
|
+
mkdirSync(commandsDest, { recursive: true });
|
|
74
|
+
for (const file of commandFiles) {
|
|
75
|
+
const src = join(commandsSource, file);
|
|
76
|
+
const dest = join(commandsDest, file);
|
|
77
|
+
if (existsSync(src)) {
|
|
78
|
+
copyFileSync(src, dest);
|
|
79
|
+
console.log(` [cmd] Installed .claude/commands/${file}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
console.log();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
console.log(" Done! Project setup complete.\n");
|
|
86
|
+
}
|
package/src/updater.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { existsSync, mkdirSync, copyFileSync, readFileSync } from "node:fs";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const { version } = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf8"));
|
|
8
|
+
|
|
9
|
+
const TOOLS = [
|
|
10
|
+
{
|
|
11
|
+
name: "ADR System",
|
|
12
|
+
marker: ".adr",
|
|
13
|
+
pkg: "adr-system",
|
|
14
|
+
cmd: "npx adr-system update",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: "Agreement System",
|
|
18
|
+
marker: ".agreements",
|
|
19
|
+
pkg: "agreement-system",
|
|
20
|
+
cmd: "npx agreement-system update",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "Feature Lifecycle",
|
|
24
|
+
marker: ".features",
|
|
25
|
+
pkg: "feature-lifecycle",
|
|
26
|
+
cmd: "npx feature-lifecycle update",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "Mermaid Workbench",
|
|
30
|
+
marker: ["_bmad/modules/mermaid-workbench", ".bmad/modules/mermaid-workbench"],
|
|
31
|
+
pkg: "mermaid-workbench",
|
|
32
|
+
cmd: "npx mermaid-workbench init",
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
const COMMAND_FILES = ["tcsetup.onboard.md", "feature.workflow.md"];
|
|
37
|
+
|
|
38
|
+
function isInstalled(marker, projectRoot) {
|
|
39
|
+
if (Array.isArray(marker)) {
|
|
40
|
+
return marker.some((m) => existsSync(join(projectRoot, m)));
|
|
41
|
+
}
|
|
42
|
+
return existsSync(join(projectRoot, marker));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function update(flags = []) {
|
|
46
|
+
const projectRoot = process.cwd();
|
|
47
|
+
|
|
48
|
+
console.log(`\n tcsetup update v${version}\n`);
|
|
49
|
+
|
|
50
|
+
// ── Detect installed tools ────────────────────────────
|
|
51
|
+
console.log(" Detecting installed tools...\n");
|
|
52
|
+
|
|
53
|
+
const detected = TOOLS.filter((tool) => isInstalled(tool.marker, projectRoot));
|
|
54
|
+
|
|
55
|
+
if (detected.length === 0) {
|
|
56
|
+
console.log(" No TC tools detected. Run `npx tcsetup` to onboard first.\n");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
for (const tool of detected) {
|
|
61
|
+
console.log(` ✓ ${tool.name}`);
|
|
62
|
+
}
|
|
63
|
+
console.log();
|
|
64
|
+
|
|
65
|
+
// ── Update npm packages ───────────────────────────────
|
|
66
|
+
const pkgs = detected.map((t) => `${t.pkg}@latest`).join(" ");
|
|
67
|
+
console.log(` [1/3] Updating npm packages...`);
|
|
68
|
+
console.log(` > npm install ${pkgs}\n`);
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
execSync(`npm install ${pkgs}`, { stdio: "inherit" });
|
|
72
|
+
console.log();
|
|
73
|
+
} catch (err) {
|
|
74
|
+
console.error(`\n ⚠ npm install failed (exit code ${err.status}).`);
|
|
75
|
+
console.error(` Continuing with sub-tool updates...\n`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ── Call sub-tool updates ─────────────────────────────
|
|
79
|
+
console.log(` [2/3] Running sub-tool updates...\n`);
|
|
80
|
+
|
|
81
|
+
for (const tool of detected) {
|
|
82
|
+
console.log(` > ${tool.cmd}`);
|
|
83
|
+
try {
|
|
84
|
+
execSync(tool.cmd, { stdio: "inherit" });
|
|
85
|
+
console.log();
|
|
86
|
+
} catch (err) {
|
|
87
|
+
console.error(`\n ⚠ ${tool.name} update failed (exit code ${err.status}).`);
|
|
88
|
+
console.error(` Continuing with remaining tools...\n`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ── Refresh tcsetup commands ──────────────────────────
|
|
93
|
+
console.log(` [3/3] Refreshing tcsetup commands...\n`);
|
|
94
|
+
|
|
95
|
+
const commandsSource = join(__dirname, "..", "commands");
|
|
96
|
+
const commandsDest = join(projectRoot, ".claude", "commands");
|
|
97
|
+
|
|
98
|
+
mkdirSync(commandsDest, { recursive: true });
|
|
99
|
+
|
|
100
|
+
for (const file of COMMAND_FILES) {
|
|
101
|
+
const src = join(commandsSource, file);
|
|
102
|
+
const dest = join(commandsDest, file);
|
|
103
|
+
if (existsSync(src)) {
|
|
104
|
+
copyFileSync(src, dest);
|
|
105
|
+
console.log(` update .claude/commands/${file}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
console.log();
|
|
109
|
+
|
|
110
|
+
// ── Summary ───────────────────────────────────────────
|
|
111
|
+
console.log(` Done! Updated ${detected.length} tool${detected.length === 1 ? "" : "s"}:`);
|
|
112
|
+
for (const tool of detected) {
|
|
113
|
+
console.log(` - ${tool.name}`);
|
|
114
|
+
}
|
|
115
|
+
console.log();
|
|
116
|
+
}
|