@altotyler/alto-rootstock-cli 1.0.0 → 1.0.2
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 +30 -62
- package/package.json +1 -1
- package/src/commands/install.js +1 -87
- package/src/commands/new.js +1 -13
- package/src/lib/config.js +1 -14
- package/src/lib/fetcher.js +4 -7
package/README.md
CHANGED
|
@@ -27,38 +27,6 @@ Once a project is open, `Ctrl+Shift+P` → **"Tasks: Run Task"** exposes:
|
|
|
27
27
|
|
|
28
28
|
---
|
|
29
29
|
|
|
30
|
-
## Deploying and packaging
|
|
31
|
-
|
|
32
|
-
### 1. Create the GitHub repo
|
|
33
|
-
|
|
34
|
-
Create a **private** repo: `github.com/alto-tyler/alto-rootstock-cli`
|
|
35
|
-
|
|
36
|
-
This repo is separate from `rootstock-agent-distribution` — it's the CLI source code only.
|
|
37
|
-
|
|
38
|
-
### 2. Push the code
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
cd alto-rootstock-cli
|
|
42
|
-
git init
|
|
43
|
-
git add .
|
|
44
|
-
git commit -m "Initial release"
|
|
45
|
-
git remote add origin git@github.com:alto-tyler/alto-rootstock-cli.git
|
|
46
|
-
git push -u origin main
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### 3. Publish a version
|
|
50
|
-
|
|
51
|
-
Tag a release — GitHub Actions publishes it automatically to GitHub Packages:
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
git tag v1.0.0
|
|
55
|
-
git push origin v1.0.0
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
The workflow in `.github/workflows/publish.yml` runs `npm publish` to npmjs.com using the `NPM_TOKEN` secret (add this in the repo Settings → Secrets → Actions).
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
30
|
## How users install it
|
|
63
31
|
|
|
64
32
|
No auth required — the package is public on npmjs.com:
|
|
@@ -69,11 +37,11 @@ npm install -g @altotyler/alto-rootstock-cli
|
|
|
69
37
|
|
|
70
38
|
After install, run `altors install` once to save your GitHub token for fetching skill files from the private distribution repo.
|
|
71
39
|
|
|
72
|
-
|
|
40
|
+
Updates are one command:
|
|
73
41
|
|
|
74
42
|
```bash
|
|
75
43
|
npm update -g @altotyler/alto-rootstock-cli
|
|
76
|
-
altors install #
|
|
44
|
+
altors install # re-fetches latest global VS Code agent files
|
|
77
45
|
```
|
|
78
46
|
|
|
79
47
|
---
|
|
@@ -85,11 +53,11 @@ Every time `altors` runs any command, it fetches `version.json` from the distrib
|
|
|
85
53
|
```
|
|
86
54
|
┌──────────────────────────────────────────────────────┐
|
|
87
55
|
│ Update available: 1.0.0 → 1.2.0 │
|
|
88
|
-
│ Run: npm update -g @altotyler/alto-rootstock-cli
|
|
56
|
+
│ Run: npm update -g @altotyler/alto-rootstock-cli │
|
|
89
57
|
└──────────────────────────────────────────────────────┘
|
|
90
58
|
```
|
|
91
59
|
|
|
92
|
-
To
|
|
60
|
+
To trigger update notices, bump `cliVersion` in `rootstock-agent-distribution/version.json`:
|
|
93
61
|
|
|
94
62
|
```json
|
|
95
63
|
{
|
|
@@ -100,41 +68,41 @@ To support this, keep `version.json` in `rootstock-agent-distribution` updated w
|
|
|
100
68
|
|
|
101
69
|
---
|
|
102
70
|
|
|
71
|
+
## Releasing a new CLI version
|
|
72
|
+
|
|
73
|
+
1. Update `version` in `package.json`
|
|
74
|
+
2. Commit and tag: `git tag v1.x.x && git push origin v1.x.x`
|
|
75
|
+
3. GitHub Actions publishes to npmjs.com automatically (requires `NPM_TOKEN` secret in repo Settings → Secrets → Actions)
|
|
76
|
+
4. Update `cliVersion` in `rootstock-agent-distribution/version.json`
|
|
77
|
+
5. Users see the update prompt on their next `altors` command
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
103
81
|
## Repository layout
|
|
104
82
|
|
|
105
83
|
```
|
|
106
|
-
alto-rootstock-cli/
|
|
107
|
-
├── bin/altors.js
|
|
84
|
+
alto-rootstock-cli/ ← this repo (CLI source, published to npmjs.com)
|
|
85
|
+
├── bin/altors.js ← entry point + update notification
|
|
108
86
|
├── src/
|
|
109
|
-
│ ├── commands/new.js
|
|
110
|
-
│ ├── commands/update.js
|
|
111
|
-
│ ├── commands/install.js
|
|
87
|
+
│ ├── commands/new.js ← prompts, runs sf project generate, injects skills
|
|
88
|
+
│ ├── commands/update.js ← updates skill files in current project
|
|
89
|
+
│ ├── commands/install.js ← installs global VS Code agent + saves GitHub token
|
|
112
90
|
│ └── lib/
|
|
113
|
-
│ ├── config.js
|
|
114
|
-
│ ├── fetcher.js
|
|
115
|
-
│ ├── scaffold.js
|
|
116
|
-
│ └── updater.js
|
|
117
|
-
├── project-template/
|
|
118
|
-
│ └── vscode/tasks.json
|
|
119
|
-
└── .github/workflows/publish.yml
|
|
120
|
-
|
|
121
|
-
rootstock-agent-distribution/
|
|
122
|
-
├── version.json
|
|
91
|
+
│ ├── config.js ← ~/.alto-rootstock/config.json token storage
|
|
92
|
+
│ ├── fetcher.js ← GitHub raw file fetcher (auth-aware)
|
|
93
|
+
│ ├── scaffold.js ← file manifest + writer
|
|
94
|
+
│ └── updater.js ← background version check
|
|
95
|
+
├── project-template/
|
|
96
|
+
│ └── vscode/tasks.json ← injected into new projects for command palette tasks
|
|
97
|
+
└── .github/workflows/publish.yml ← auto-publishes to npmjs.com on git tag push
|
|
98
|
+
|
|
99
|
+
rootstock-agent-distribution/ ← separate private repo (skill files + version manifest)
|
|
100
|
+
├── version.json ← bump cliVersion here to trigger update notices
|
|
123
101
|
└── project-template/
|
|
124
102
|
├── claude/CLAUDE.md
|
|
125
|
-
├── claude/skills
|
|
103
|
+
├── claude/skills/ ← 10 Rootstock skill files
|
|
126
104
|
├── cursor/rules/rootstock.mdc
|
|
127
105
|
├── github/agents/Rootstock Agent.agent.md
|
|
128
106
|
├── github/copilot-instructions.md
|
|
129
107
|
└── vscode/mcp.json + tasks.json
|
|
130
108
|
```
|
|
131
|
-
|
|
132
|
-
---
|
|
133
|
-
|
|
134
|
-
## Releasing a new version
|
|
135
|
-
|
|
136
|
-
1. Update `version` in `package.json`
|
|
137
|
-
2. Commit and tag: `git tag v1.x.x && git push origin v1.x.x`
|
|
138
|
-
3. GitHub Actions publishes to GitHub Packages
|
|
139
|
-
4. Update `cliVersion` in `rootstock-agent-distribution/version.json`
|
|
140
|
-
5. Users see the update prompt on their next `altors` command
|
package/package.json
CHANGED
package/src/commands/install.js
CHANGED
|
@@ -4,11 +4,8 @@ const fs = require('fs');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const os = require('os');
|
|
6
6
|
const chalk = require('chalk');
|
|
7
|
-
const prompts = require('prompts');
|
|
8
7
|
const { fetchRemoteFile } = require('../lib/fetcher');
|
|
9
|
-
const { getToken, saveToken } = require('../lib/config');
|
|
10
8
|
|
|
11
|
-
// VS Code Copilot global agent directory by platform
|
|
12
9
|
function getVsCodeAgentDir() {
|
|
13
10
|
switch (process.platform) {
|
|
14
11
|
case 'win32':
|
|
@@ -20,11 +17,6 @@ function getVsCodeAgentDir() {
|
|
|
20
17
|
}
|
|
21
18
|
}
|
|
22
19
|
|
|
23
|
-
// Global Claude Code commands directory
|
|
24
|
-
function getClaudeCommandsDir() {
|
|
25
|
-
return path.join(os.homedir(), '.claude', 'commands');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
20
|
const GLOBAL_FILES = [
|
|
29
21
|
{
|
|
30
22
|
remote: 'project-template/github/agents/Rootstock Agent.agent.md',
|
|
@@ -33,90 +25,12 @@ const GLOBAL_FILES = [
|
|
|
33
25
|
},
|
|
34
26
|
];
|
|
35
27
|
|
|
36
|
-
async function promptForToken() {
|
|
37
|
-
console.log();
|
|
38
|
-
console.log(chalk.yellow(' No GitHub token found.'));
|
|
39
|
-
console.log(chalk.dim(' A token with read:packages scope is required to access the private distribution repo.'));
|
|
40
|
-
console.log();
|
|
41
|
-
|
|
42
|
-
const { token } = await prompts(
|
|
43
|
-
{
|
|
44
|
-
type: 'password',
|
|
45
|
-
name: 'token',
|
|
46
|
-
message: 'GitHub Personal Access Token (read:packages)',
|
|
47
|
-
},
|
|
48
|
-
{ onCancel: () => process.exit(0) }
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
if (!token) return null;
|
|
52
|
-
|
|
53
|
-
const { save } = await prompts(
|
|
54
|
-
{
|
|
55
|
-
type: 'confirm',
|
|
56
|
-
name: 'save',
|
|
57
|
-
message: 'Save token to ~/.alto-rootstock/config.json for future use?',
|
|
58
|
-
initial: true,
|
|
59
|
-
},
|
|
60
|
-
{ onCancel: () => {} }
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
if (save) {
|
|
64
|
-
saveToken(token);
|
|
65
|
-
console.log(` ${chalk.green('✓')} Token saved to ~/.alto-rootstock/config.json`);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Also write to ~/.npmrc so npm update works without re-entering the token
|
|
69
|
-
const npmrcPath = path.join(os.homedir(), '.npmrc');
|
|
70
|
-
const npmrcLine = `//npm.pkg.github.com/:_authToken=${token}`;
|
|
71
|
-
const npmrcScope = '@alto-tyler:registry=https://npm.pkg.github.com';
|
|
72
|
-
|
|
73
|
-
let npmrcContent = '';
|
|
74
|
-
if (fs.existsSync(npmrcPath)) {
|
|
75
|
-
npmrcContent = fs.readFileSync(npmrcPath, 'utf8');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
let updated = false;
|
|
79
|
-
if (!npmrcContent.includes('//npm.pkg.github.com/:_authToken=')) {
|
|
80
|
-
npmrcContent += `\n${npmrcLine}\n`;
|
|
81
|
-
updated = true;
|
|
82
|
-
} else {
|
|
83
|
-
// Replace existing token line
|
|
84
|
-
npmrcContent = npmrcContent.replace(/\/\/npm\.pkg\.github\.com\/:_authToken=.*/g, npmrcLine);
|
|
85
|
-
updated = true;
|
|
86
|
-
}
|
|
87
|
-
if (!npmrcContent.includes('@alto-tyler:registry=')) {
|
|
88
|
-
npmrcContent += `${npmrcScope}\n`;
|
|
89
|
-
updated = true;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (updated) {
|
|
93
|
-
fs.writeFileSync(npmrcPath, npmrcContent.trimStart(), 'utf8');
|
|
94
|
-
console.log(` ${chalk.green('✓')} ~/.npmrc updated — ${chalk.cyan('npm update -g @altotyler/alto-rootstock-cli')} will work without re-entering a token`);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
process.env.GITHUB_TOKEN = token;
|
|
98
|
-
return token;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
28
|
async function run() {
|
|
102
29
|
console.log();
|
|
103
30
|
console.log(chalk.bold(' Rootstock: Global Install / Update'));
|
|
104
31
|
console.log(chalk.dim(' ─────────────────────────────────────────────────'));
|
|
105
32
|
console.log();
|
|
106
33
|
|
|
107
|
-
let token = getToken();
|
|
108
|
-
if (!token) {
|
|
109
|
-
token = await promptForToken();
|
|
110
|
-
if (!token) {
|
|
111
|
-
console.error(chalk.red(' ✗ No token provided. Cannot access private distribution repo.'));
|
|
112
|
-
process.exit(1);
|
|
113
|
-
}
|
|
114
|
-
} else {
|
|
115
|
-
console.log(` ${chalk.green('✓')} GitHub token found`);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
console.log();
|
|
119
|
-
|
|
120
34
|
for (const entry of GLOBAL_FILES) {
|
|
121
35
|
const target = entry.getTarget();
|
|
122
36
|
const dir = path.dirname(target);
|
|
@@ -143,7 +57,7 @@ async function run() {
|
|
|
143
57
|
console.log(chalk.dim(' 3. For project-level skills: run altors new or altors update in your project'));
|
|
144
58
|
console.log();
|
|
145
59
|
console.log(chalk.bold(' To update in future:'));
|
|
146
|
-
console.log(chalk.cyan(' npm update -g @altotyler/
|
|
60
|
+
console.log(chalk.cyan(' npm update -g @altotyler/rootstock-cli'));
|
|
147
61
|
console.log(chalk.cyan(' altors install'));
|
|
148
62
|
console.log();
|
|
149
63
|
}
|
package/src/commands/new.js
CHANGED
|
@@ -6,7 +6,7 @@ const fs = require('fs');
|
|
|
6
6
|
const chalk = require('chalk');
|
|
7
7
|
const prompts = require('prompts');
|
|
8
8
|
const { injectScaffolding } = require('../lib/scaffold');
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
|
|
11
11
|
function banner() {
|
|
12
12
|
console.log();
|
|
@@ -28,17 +28,6 @@ function checkSfCli() {
|
|
|
28
28
|
console.log(` ${chalk.green('✓')} Salesforce CLI detected ${chalk.dim(`(${version})`)}`);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
function checkGithubToken() {
|
|
32
|
-
const token = getToken();
|
|
33
|
-
if (!token) {
|
|
34
|
-
console.log();
|
|
35
|
-
console.log(chalk.yellow(' ⚠ No GitHub token found.'));
|
|
36
|
-
console.log(chalk.dim(' Skill files are hosted on a private repo.'));
|
|
37
|
-
console.log(chalk.dim(' Set GITHUB_TOKEN or run:') + chalk.cyan(' altors install --save-token'));
|
|
38
|
-
console.log();
|
|
39
|
-
}
|
|
40
|
-
return token;
|
|
41
|
-
}
|
|
42
31
|
|
|
43
32
|
async function promptProjectDetails() {
|
|
44
33
|
console.log();
|
|
@@ -93,7 +82,6 @@ function runSfProjectGenerate(projectName, outputDir) {
|
|
|
93
82
|
async function run() {
|
|
94
83
|
banner();
|
|
95
84
|
checkSfCli();
|
|
96
|
-
checkGithubToken();
|
|
97
85
|
|
|
98
86
|
const { projectName, outputDir } = await promptProjectDetails();
|
|
99
87
|
|
package/src/lib/config.js
CHANGED
|
@@ -20,17 +20,4 @@ function load() {
|
|
|
20
20
|
return { ...DEFAULTS };
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
if (!fs.existsSync(CONFIG_DIR)) fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
25
|
-
fs.writeFileSync(CONFIG_FILE, JSON.stringify(data, null, 2), 'utf8');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function getToken() {
|
|
29
|
-
return process.env.GITHUB_TOKEN || load().token || null;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function saveToken(token) {
|
|
33
|
-
save({ ...load(), token });
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
module.exports = { load, save, getToken, saveToken, CONFIG_FILE };
|
|
23
|
+
module.exports = { load, CONFIG_FILE };
|
package/src/lib/fetcher.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const https = require('https');
|
|
4
|
-
const { load
|
|
4
|
+
const { load } = require('./config');
|
|
5
5
|
|
|
6
|
-
function fetchUrl(url
|
|
6
|
+
function fetchUrl(url) {
|
|
7
7
|
return new Promise((resolve, reject) => {
|
|
8
8
|
const opts = new URL(url);
|
|
9
9
|
const headers = { 'User-Agent': 'alto-rootstock-cli' };
|
|
10
|
-
if (token) headers['Authorization'] = `Bearer ${token}`;
|
|
11
10
|
|
|
12
11
|
https.get({ hostname: opts.hostname, path: opts.pathname + opts.search, headers }, (res) => {
|
|
13
12
|
if (res.statusCode === 302 || res.statusCode === 301) {
|
|
14
|
-
return fetchUrl(res.headers.location
|
|
13
|
+
return fetchUrl(res.headers.location).then(resolve).catch(reject);
|
|
15
14
|
}
|
|
16
15
|
if (res.statusCode !== 200) {
|
|
17
16
|
res.resume();
|
|
@@ -27,9 +26,7 @@ function fetchUrl(url, token) {
|
|
|
27
26
|
|
|
28
27
|
async function fetchRemoteFile(remotePath) {
|
|
29
28
|
const { baseUrl } = load();
|
|
30
|
-
|
|
31
|
-
const url = `${baseUrl}/${remotePath}`;
|
|
32
|
-
return fetchUrl(url, token);
|
|
29
|
+
return fetchUrl(`${baseUrl}/${remotePath}`);
|
|
33
30
|
}
|
|
34
31
|
|
|
35
32
|
async function fetchRemoteJson(remotePath) {
|