tcsetup 1.2.0 → 1.3.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/bin/cli.js CHANGED
@@ -1,24 +1,28 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { execSync } from "node:child_process";
4
- import { argv } from "node:process";
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 flags = argv.slice(2);
13
+ const command = argv[2];
14
+ const flags = argv.slice(3);
13
15
 
14
16
  const HELP = `
15
- tcsetup — Bootstrap a project with the full TC toolchain.
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
- if (flags.includes("help") || flags.includes("--help") || flags.includes("-h")) {
31
- console.log(HELP);
32
- process.exit(0);
33
- }
34
-
35
- const steps = [
36
- {
37
- name: "BMAD Method",
38
- flag: "--skip-bmad",
39
- cmd: "npx bmad-method install",
40
- },
41
- {
42
- name: "Spec Kit",
43
- flag: "--skip-speckit",
44
- cmd: "specify init --here --ai claude",
45
- },
46
- {
47
- name: "Agreement System",
48
- flag: "--skip-agreements",
49
- cmd: "npx agreement-system init --yes",
50
- },
51
- {
52
- name: "ADR System",
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.2.0",
3
+ "version": "1.3.0",
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": {
@@ -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
+ }