@solidactions/cli 1.5.0 → 1.7.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 +22 -16
- package/dist/commands/ai-init.js +16 -47
- package/dist/commands/init.js +70 -190
- package/dist/commands/login.js +215 -0
- package/dist/index.js +18 -8
- package/dist/utils/skills.js +21 -33
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,10 +11,11 @@ npm install -g @solidactions/cli
|
|
|
11
11
|
## Quick Start
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
solidactions
|
|
15
|
-
solidactions init
|
|
16
|
-
|
|
17
|
-
solidactions
|
|
14
|
+
solidactions login <api-key> # Authenticate (prompts for workspace)
|
|
15
|
+
solidactions init my-project # Scaffold a new project (files + AI skills)
|
|
16
|
+
cd my-project
|
|
17
|
+
solidactions project deploy my-project -e production # Deploy it
|
|
18
|
+
solidactions run start my-project <workflow> # Trigger a workflow
|
|
18
19
|
solidactions run view <run-id> # Inspect a run
|
|
19
20
|
```
|
|
20
21
|
|
|
@@ -35,13 +36,13 @@ For each field (`host`, `apiKey`, `workspaceId`), the CLI resolves independently
|
|
|
35
36
|
|
|
36
37
|
You can mix: e.g., set only `SOLIDACTIONS_WORKSPACE_ID` in the environment while letting `host` and `apiKey` come from a file.
|
|
37
38
|
|
|
38
|
-
### `solidactions
|
|
39
|
+
### `solidactions login` flags
|
|
39
40
|
|
|
40
41
|
- `--local` — write config to `./.solidactions/config.json` in the current folder.
|
|
41
42
|
- `--global` — write config to `~/.solidactions/config.json` (today's default).
|
|
42
43
|
- `--gitignore` — with `--local`, auto-add `.solidactions/` to `.gitignore` without prompting.
|
|
43
44
|
|
|
44
|
-
In interactive shells, `
|
|
45
|
+
In interactive shells, `login` without `--local`/`--global` prompts for a location. In non-interactive contexts, one of the flags is required.
|
|
45
46
|
|
|
46
47
|
### `solidactions logout` flags
|
|
47
48
|
|
|
@@ -57,7 +58,7 @@ Set `SOLIDACTIONS_DEBUG=1` on any command to print the resolved configuration an
|
|
|
57
58
|
|
|
58
59
|
If you run multiple AI coding agents in different project folders simultaneously, either:
|
|
59
60
|
|
|
60
|
-
- Run `solidactions
|
|
61
|
+
- Run `solidactions login <key> --local` in each folder so each has its own config, or
|
|
61
62
|
- Set `SOLIDACTIONS_API_KEY` / `SOLIDACTIONS_WORKSPACE_ID` in the environment each agent uses (no files to share or stomp).
|
|
62
63
|
|
|
63
64
|
## Commands
|
|
@@ -68,9 +69,10 @@ Use `solidactions <command> --help` for full flag details on any command.
|
|
|
68
69
|
|
|
69
70
|
| Command | Description |
|
|
70
71
|
|---------|-------------|
|
|
71
|
-
| `
|
|
72
|
+
| `login <api-key>` | Authenticate CLI with API key |
|
|
72
73
|
| `logout` | Remove saved credentials |
|
|
73
74
|
| `whoami` | Show current configuration |
|
|
75
|
+
| `init [directory]` | Scaffold a new project (files + AI skills) |
|
|
74
76
|
| `dev <file>` | Run a workflow locally (no deploy needed) |
|
|
75
77
|
|
|
76
78
|
### project
|
|
@@ -127,16 +129,20 @@ Use `solidactions <command> --help` for full flag details on any command.
|
|
|
127
129
|
|
|
128
130
|
| Command | Key Flags | Description |
|
|
129
131
|
|---------|-----------|-------------|
|
|
130
|
-
| `ai init` | `--claude`, `--agents
|
|
132
|
+
| `ai init` | `--claude`, `--agents` | Install AI skills and SDK reference into an **existing** project (use `init` for new projects) |
|
|
131
133
|
| `ai examples [names...]` | `--all`, `--overwrite` | Install example workflows |
|
|
132
134
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
135
|
+
`ai init` installs three auto-activating SolidActions skills and a
|
|
136
|
+
full SDK reference into your project:
|
|
137
|
+
|
|
138
|
+
- Skills go to `.claude/skills/` (for `--claude` / Claude Code) or
|
|
139
|
+
`.agents/skills/` (for `--agents` / Codex, Cursor, Gemini, Windsurf).
|
|
140
|
+
Codex auto-discovers the `.agents/skills/` path — see
|
|
141
|
+
https://developers.openai.com/codex/skills.
|
|
142
|
+
- The SDK reference is saved to `.solidactions/sdk-reference.md`.
|
|
143
|
+
- A slim pointer section is injected into `CLAUDE.md` or `AGENTS.md`
|
|
144
|
+
listing the skills and inlining the highest-cost hard rules
|
|
145
|
+
(determinism, step discipline, messaging) as a safety net.
|
|
140
146
|
|
|
141
147
|
## Development
|
|
142
148
|
|
package/dist/commands/ai-init.js
CHANGED
|
@@ -14,7 +14,7 @@ const markers_1 = require("../utils/markers");
|
|
|
14
14
|
const skills_1 = require("../utils/skills");
|
|
15
15
|
async function aiInit(options = {}) {
|
|
16
16
|
try {
|
|
17
|
-
// Determine target file
|
|
17
|
+
// Determine target file.
|
|
18
18
|
let targetFile;
|
|
19
19
|
if (options.claude && options.agents) {
|
|
20
20
|
console.error(chalk_1.default.red('Please specify only one of --claude or --agents'));
|
|
@@ -32,8 +32,8 @@ async function aiInit(options = {}) {
|
|
|
32
32
|
name: 'file',
|
|
33
33
|
message: 'Which AI helper file?',
|
|
34
34
|
choices: [
|
|
35
|
-
{ title: 'CLAUDE.md', value: 'CLAUDE.md' },
|
|
36
|
-
{ title: 'AGENTS.md', value: 'AGENTS.md' },
|
|
35
|
+
{ title: 'CLAUDE.md (Claude Code)', value: 'CLAUDE.md' },
|
|
36
|
+
{ title: 'AGENTS.md (Codex, Cursor, Gemini, etc.)', value: 'AGENTS.md' },
|
|
37
37
|
],
|
|
38
38
|
});
|
|
39
39
|
if (!response.file) {
|
|
@@ -42,58 +42,27 @@ async function aiInit(options = {}) {
|
|
|
42
42
|
}
|
|
43
43
|
targetFile = response.file;
|
|
44
44
|
}
|
|
45
|
-
// Decide whether to install skills (default true; --no-skills opts out)
|
|
46
|
-
const installSkillsEnabled = options.skills !== false;
|
|
47
|
-
// Determine skill targets if installing.
|
|
48
|
-
// Skills are Claude Code-specific (.claude/skills/) and not meaningful for other AI tools.
|
|
49
|
-
let skillTargets = [];
|
|
50
|
-
if (installSkillsEnabled && targetFile === 'CLAUDE.md') {
|
|
51
|
-
skillTargets = (0, skills_1.detectSkillTargets)();
|
|
52
|
-
if (skillTargets.length === 0) {
|
|
53
|
-
const resp = await (0, prompts_1.default)({
|
|
54
|
-
type: 'confirm',
|
|
55
|
-
name: 'create',
|
|
56
|
-
message: 'No `.claude/` directory found. Create `.claude/skills/` for SolidActions skills?',
|
|
57
|
-
initial: true,
|
|
58
|
-
});
|
|
59
|
-
if (resp.create === undefined) {
|
|
60
|
-
// User cancelled (Ctrl+C) — treat as abort, not decline
|
|
61
|
-
console.log(chalk_1.default.yellow('Cancelled.'));
|
|
62
|
-
process.exit(0);
|
|
63
|
-
}
|
|
64
|
-
else if (resp.create) {
|
|
65
|
-
skillTargets = [path_1.default.join(process.cwd(), '.claude', 'skills')];
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
console.log(chalk_1.default.yellow('Skipping skill install. Run with --no-skills to silence this prompt.'));
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
45
|
console.log(chalk_1.default.blue('Fetching AI helper content...'));
|
|
73
|
-
// Fetch
|
|
74
|
-
const aiContent = await (0, skills_1.
|
|
75
|
-
// Fetch SDK reference (always)
|
|
46
|
+
// Fetch slim helper content for the chosen target.
|
|
47
|
+
const aiContent = await (0, skills_1.fetchAiHelperContent)(targetFile);
|
|
48
|
+
// Fetch SDK reference (always).
|
|
76
49
|
const sdkContent = await (0, github_1.fetchRawFile)('SolidActions', 'solidactions-ts-sdk', 'docs/sdk-reference.md');
|
|
77
|
-
// Save SDK reference to .solidactions/sdk-reference.md
|
|
50
|
+
// Save SDK reference to .solidactions/sdk-reference.md.
|
|
78
51
|
fs_extra_1.default.ensureDirSync('.solidactions');
|
|
79
52
|
fs_1.default.writeFileSync('.solidactions/sdk-reference.md', sdkContent, 'utf8');
|
|
80
53
|
console.log(chalk_1.default.green('✓ SDK reference saved to .solidactions/sdk-reference.md'));
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
54
|
+
// Always install skills — no prompt. The user chose `ai init <target>`,
|
|
55
|
+
// so they want AI tooling set up.
|
|
56
|
+
const targetDir = (0, skills_1.skillTargetDir)(targetFile);
|
|
57
|
+
console.log(chalk_1.default.blue(`Installing SolidActions skills to ${path_1.default.relative(process.cwd(), targetDir)}/ ...`));
|
|
58
|
+
const { written } = await (0, skills_1.installSkills)(targetDir);
|
|
59
|
+
for (const f of written) {
|
|
60
|
+
console.log(chalk_1.default.green(`✓ ${path_1.default.relative(process.cwd(), f)}`));
|
|
88
61
|
}
|
|
89
|
-
// Upsert
|
|
62
|
+
// Upsert the AI helper marker section.
|
|
90
63
|
(0, markers_1.upsertMarkerSection)(targetFile, 'SolidActions', aiContent);
|
|
91
|
-
// Upsert SDK reference pointer section
|
|
92
|
-
const sdkReferenceNote = `## SolidActions SDK Reference
|
|
93
|
-
|
|
94
|
-
The full SDK API reference is available at \`.solidactions/sdk-reference.md\`. Refer to it for detailed function signatures, error classes, retry configuration, and advanced patterns like forking, streaming, and signal URLs.`;
|
|
95
|
-
(0, markers_1.upsertMarkerSection)(targetFile, 'SolidActions SDK Reference', sdkReferenceNote);
|
|
96
64
|
console.log(chalk_1.default.green(`✓ AI helper installed to ${targetFile}`));
|
|
65
|
+
console.log(chalk_1.default.gray(' Existing files may still contain a separate "SolidActions SDK Reference" marker block from older CLI versions. That content is now redundant and can be deleted manually.'));
|
|
97
66
|
}
|
|
98
67
|
catch (error) {
|
|
99
68
|
if (error.message?.includes('rate limit')) {
|
package/dist/commands/init.js
CHANGED
|
@@ -3,209 +3,89 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getConfig = getConfig;
|
|
7
|
-
exports.saveConfig = saveConfig;
|
|
8
|
-
exports.clearConfig = clearConfig;
|
|
9
6
|
exports.init = init;
|
|
10
|
-
exports.logout = logout;
|
|
11
|
-
exports.whoami = whoami;
|
|
12
7
|
const fs_1 = __importDefault(require("fs"));
|
|
13
8
|
const path_1 = __importDefault(require("path"));
|
|
14
|
-
const readline_1 = __importDefault(require("readline"));
|
|
15
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
10
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
11
|
+
const github_1 = require("../utils/github");
|
|
12
|
+
const ai_init_1 = require("./ai-init");
|
|
13
|
+
const EXAMPLES_OWNER = 'SolidActions';
|
|
14
|
+
const EXAMPLES_REPO = 'solidactions-examples';
|
|
15
|
+
const TEMPLATE_PREFIX = 'templates/minimal';
|
|
16
|
+
// Tuples of [remote-path-suffix-under-template-prefix, local-path-relative-to-target].
|
|
17
|
+
const TEMPLATE_FILES = [
|
|
18
|
+
['package.json', 'package.json'],
|
|
19
|
+
['tsconfig.json', 'tsconfig.json'],
|
|
20
|
+
['solidactions.yaml', 'solidactions.yaml'],
|
|
21
|
+
['.env.example', '.env.example'],
|
|
22
|
+
['src/hello.ts', 'src/hello.ts'],
|
|
23
|
+
];
|
|
24
|
+
function firstNonDotEntry(target) {
|
|
25
|
+
if (!fs_1.default.existsSync(target))
|
|
26
|
+
return null;
|
|
27
|
+
const entries = fs_1.default.readdirSync(target);
|
|
28
|
+
for (const entry of entries) {
|
|
29
|
+
if (entry.startsWith('.'))
|
|
30
|
+
continue;
|
|
31
|
+
return entry;
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
22
34
|
}
|
|
23
|
-
function
|
|
24
|
-
const resolved = (0, config_1.resolveConfig)();
|
|
25
|
-
const targetPath = resolved ? resolved.activePath : (0, config_1.getGlobalConfigPath)();
|
|
26
|
-
(0, config_1.writeConfigFile)(targetPath, config);
|
|
27
|
-
}
|
|
28
|
-
function clearConfig() {
|
|
29
|
-
(0, config_1.removeConfigFile)((0, config_1.getGlobalConfigPath)());
|
|
30
|
-
}
|
|
31
|
-
async function promptLocation() {
|
|
32
|
-
const rl = readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
35
|
+
async function init(directory, options = {}) {
|
|
33
36
|
try {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return 'global';
|
|
41
|
-
if (normalized === 'local' || normalized === 'l')
|
|
42
|
-
return 'local';
|
|
43
|
-
console.log(chalk_1.default.yellow("Please answer 'local' or 'global' (or press Enter for global)."));
|
|
37
|
+
const cwd = process.cwd();
|
|
38
|
+
const installSkills = options.skills !== false; // default true
|
|
39
|
+
const targetDir = directory ? path_1.default.resolve(cwd, directory) : cwd;
|
|
40
|
+
const projectName = path_1.default.basename(targetDir);
|
|
41
|
+
if (directory) {
|
|
42
|
+
fs_extra_1.default.ensureDirSync(targetDir);
|
|
44
43
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
async function ensureGitignoreCovers(targetDir, auto) {
|
|
51
|
-
const gitignorePath = path_1.default.join(targetDir, '.gitignore');
|
|
52
|
-
const patternToAdd = '.solidactions/';
|
|
53
|
-
let existing = '';
|
|
54
|
-
if (fs_1.default.existsSync(gitignorePath)) {
|
|
55
|
-
existing = fs_1.default.readFileSync(gitignorePath, 'utf-8');
|
|
56
|
-
const lines = existing.split('\n').map((l) => l.trim());
|
|
57
|
-
const isCovered = lines.some((line) => {
|
|
58
|
-
const normalized = line
|
|
59
|
-
.replace(/^\*\*\//, '')
|
|
60
|
-
.replace(/^\//, '')
|
|
61
|
-
.replace(/\/(\*\*|\*)?$/, '');
|
|
62
|
-
return normalized === '.solidactions';
|
|
63
|
-
});
|
|
64
|
-
if (isCovered) {
|
|
65
|
-
return; // already covered
|
|
44
|
+
const offender = firstNonDotEntry(targetDir);
|
|
45
|
+
if (offender) {
|
|
46
|
+
console.error(chalk_1.default.red(`Target directory "${targetDir}" is not empty (contains "${offender}").`));
|
|
47
|
+
console.error(chalk_1.default.gray('Run in a fresh directory, or use `solidactions ai init` to add AI tooling to an existing project.'));
|
|
48
|
+
process.exit(1);
|
|
66
49
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
console.log(
|
|
50
|
+
console.log(chalk_1.default.blue(`Scaffolding "${projectName}" in ${targetDir}...`));
|
|
51
|
+
for (const [remoteSuffix, localSuffix] of TEMPLATE_FILES) {
|
|
52
|
+
const remotePath = `${TEMPLATE_PREFIX}/${remoteSuffix}`;
|
|
53
|
+
let content = await (0, github_1.fetchRawFile)(EXAMPLES_OWNER, EXAMPLES_REPO, remotePath);
|
|
54
|
+
content = content.replace(/__PROJECT_NAME__/g, projectName);
|
|
55
|
+
const outPath = path_1.default.join(targetDir, localSuffix);
|
|
56
|
+
fs_extra_1.default.ensureDirSync(path_1.default.dirname(outPath));
|
|
57
|
+
fs_1.default.writeFileSync(outPath, content, 'utf8');
|
|
58
|
+
console.log(chalk_1.default.green(`✓ ${path_1.default.relative(cwd, outPath)}`));
|
|
59
|
+
}
|
|
60
|
+
if (installSkills) {
|
|
61
|
+
console.log('');
|
|
62
|
+
process.chdir(targetDir);
|
|
63
|
+
await (0, ai_init_1.aiInit)({ claude: options.claude, agents: options.agents });
|
|
64
|
+
}
|
|
65
|
+
console.log('');
|
|
66
|
+
console.log(chalk_1.default.green(`✓ Project "${projectName}" scaffolded.`));
|
|
67
|
+
console.log('');
|
|
68
|
+
console.log(chalk_1.default.blue('Next steps:'));
|
|
69
|
+
if (directory) {
|
|
70
|
+
console.log(chalk_1.default.gray(` cd ${directory}`));
|
|
71
|
+
}
|
|
72
|
+
console.log(chalk_1.default.gray(` # Fill in WEBHOOK_SECRET and any other env vars in solidactions.yaml:`));
|
|
73
|
+
console.log(chalk_1.default.gray(` solidactions env set ${projectName} WEBHOOK_SECRET <your-secret> -e production`));
|
|
74
|
+
console.log(chalk_1.default.gray(` solidactions project deploy ${projectName} -e production`));
|
|
85
75
|
}
|
|
86
76
|
catch (err) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
async function init(apiKey, options) {
|
|
91
|
-
let host;
|
|
92
|
-
if (options.host) {
|
|
93
|
-
host = options.host;
|
|
94
|
-
}
|
|
95
|
-
else if (options.dev) {
|
|
96
|
-
host = 'http://localhost:8000';
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
host = 'https://app.solidactions.com';
|
|
100
|
-
}
|
|
101
|
-
if (!apiKey || apiKey.trim().length === 0) {
|
|
102
|
-
console.error(chalk_1.default.red('Error: API key is required.'));
|
|
103
|
-
console.log(chalk_1.default.gray('Generate an API key at: ') + chalk_1.default.blue(`${host}/settings/api-keys`));
|
|
104
|
-
process.exit(1);
|
|
105
|
-
}
|
|
106
|
-
// Determine target location.
|
|
107
|
-
let target;
|
|
108
|
-
if (options.local && options.global) {
|
|
109
|
-
console.error(chalk_1.default.red('Error: --local and --global are mutually exclusive.'));
|
|
110
|
-
process.exit(1);
|
|
111
|
-
}
|
|
112
|
-
else if (options.local) {
|
|
113
|
-
target = 'local';
|
|
114
|
-
}
|
|
115
|
-
else if (options.global) {
|
|
116
|
-
target = 'global';
|
|
117
|
-
}
|
|
118
|
-
else if (process.stdin.isTTY) {
|
|
119
|
-
target = await promptLocation();
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
console.error(chalk_1.default.red('Refusing to init non-interactively. Pass --local or --global.'));
|
|
123
|
-
process.exit(1);
|
|
124
|
-
}
|
|
125
|
-
const targetPath = target === 'local' ? (0, config_1.getLocalConfigPath)() : (0, config_1.getGlobalConfigPath)();
|
|
126
|
-
console.log(chalk_1.default.blue(`Initializing SolidActions CLI...`));
|
|
127
|
-
console.log(chalk_1.default.gray(`Host: ${host}`));
|
|
128
|
-
if ((0, config_1.readConfigFile)(targetPath)) {
|
|
129
|
-
console.log(chalk_1.default.yellow(`Existing config at ${targetPath} will be overwritten.`));
|
|
130
|
-
}
|
|
131
|
-
const config = {
|
|
132
|
-
host,
|
|
133
|
-
apiKey: apiKey.trim(),
|
|
134
|
-
};
|
|
135
|
-
(0, config_1.writeConfigFile)(targetPath, config);
|
|
136
|
-
if (target === 'local') {
|
|
137
|
-
await ensureGitignoreCovers(process.cwd(), !!options.gitignore);
|
|
138
|
-
}
|
|
139
|
-
console.log(chalk_1.default.green('CLI initialized successfully!'));
|
|
140
|
-
console.log(chalk_1.default.gray(`Configuration saved to ${targetPath}`));
|
|
141
|
-
console.log('');
|
|
142
|
-
// Workspace selection — ensureWorkspaceSelected writes to the right file via the resolver.
|
|
143
|
-
try {
|
|
144
|
-
if (options.workspace) {
|
|
145
|
-
await (0, workspaces_1.workspaceSet)(options.workspace);
|
|
77
|
+
if (err.message?.includes('rate limit')) {
|
|
78
|
+
console.error(chalk_1.default.red(err.message));
|
|
146
79
|
}
|
|
147
|
-
else {
|
|
148
|
-
|
|
80
|
+
else if (err.message?.includes('not found')) {
|
|
81
|
+
console.error(chalk_1.default.red(err.message));
|
|
149
82
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
console.log(chalk_1.default.blue('Quick start:'));
|
|
156
|
-
console.log(chalk_1.default.gray(' solidactions project deploy <name> Deploy current directory'));
|
|
157
|
-
console.log(chalk_1.default.gray(' solidactions run start <proj> <wf> Run a workflow'));
|
|
158
|
-
console.log(chalk_1.default.gray(' solidactions run list List recent runs'));
|
|
159
|
-
}
|
|
160
|
-
function logout(options = {}) {
|
|
161
|
-
if (options.local && options.global) {
|
|
162
|
-
console.error(chalk_1.default.red('Error: --local and --global are mutually exclusive.'));
|
|
163
|
-
process.exit(1);
|
|
164
|
-
}
|
|
165
|
-
const globalPath = (0, config_1.getGlobalConfigPath)();
|
|
166
|
-
const localPath = (0, config_1.findLocalConfigPath)(process.cwd());
|
|
167
|
-
let targetPath;
|
|
168
|
-
if (options.local) {
|
|
169
|
-
targetPath = localPath;
|
|
170
|
-
if (!targetPath) {
|
|
171
|
-
console.error(chalk_1.default.red(`No local config found in ${process.cwd()} or any parent directory.`));
|
|
172
|
-
process.exit(1);
|
|
83
|
+
else if (err.message?.includes('Failed to fetch')) {
|
|
84
|
+
console.error(chalk_1.default.red('Network error: Could not reach GitHub to fetch the template. Check your internet connection.'));
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
console.error(chalk_1.default.red('Error:'), err.message);
|
|
173
88
|
}
|
|
174
|
-
}
|
|
175
|
-
else if (options.global) {
|
|
176
|
-
targetPath = globalPath;
|
|
177
|
-
}
|
|
178
|
-
else {
|
|
179
|
-
targetPath = localPath ?? globalPath;
|
|
180
|
-
}
|
|
181
|
-
const removed = (0, config_1.removeConfigFile)(targetPath);
|
|
182
|
-
if (removed) {
|
|
183
|
-
console.log(chalk_1.default.green(`Logged out. Removed ${targetPath}`));
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
console.log(chalk_1.default.gray(`Not logged in (no config at ${targetPath}).`));
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
function whoami() {
|
|
190
|
-
const resolved = (0, config_1.resolveConfig)();
|
|
191
|
-
if (!resolved || !resolved.config.apiKey) {
|
|
192
|
-
console.log(chalk_1.default.yellow('Not initialized.'));
|
|
193
|
-
console.log(chalk_1.default.gray('Run "solidactions init <api-key>" to configure.'));
|
|
194
89
|
process.exit(1);
|
|
195
90
|
}
|
|
196
|
-
const { config, sources } = resolved;
|
|
197
|
-
const maskedKey = config.apiKey.length > 12
|
|
198
|
-
? `${config.apiKey.substring(0, 8)}...${config.apiKey.slice(-4)}`
|
|
199
|
-
: config.apiKey;
|
|
200
|
-
const fmt = (src) => {
|
|
201
|
-
if (src === 'env')
|
|
202
|
-
return chalk_1.default.gray('(from $SOLIDACTIONS_* env var)');
|
|
203
|
-
if (src === null)
|
|
204
|
-
return chalk_1.default.gray('(unset)');
|
|
205
|
-
return chalk_1.default.gray(`(from ${src})`);
|
|
206
|
-
};
|
|
207
|
-
console.log(chalk_1.default.blue('Current configuration:'));
|
|
208
|
-
console.log(` Host: ${config.host.padEnd(40)} ${fmt(sources.host)}`);
|
|
209
|
-
console.log(` API Key: ${maskedKey.padEnd(40)} ${fmt(sources.apiKey)}`);
|
|
210
|
-
console.log(` Workspace: ${(config.workspaceId ?? '').padEnd(40)} ${fmt(sources.workspaceId)}`);
|
|
211
91
|
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getConfig = getConfig;
|
|
7
|
+
exports.saveConfig = saveConfig;
|
|
8
|
+
exports.clearConfig = clearConfig;
|
|
9
|
+
exports.login = login;
|
|
10
|
+
exports.logout = logout;
|
|
11
|
+
exports.whoami = whoami;
|
|
12
|
+
const fs_1 = __importDefault(require("fs"));
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const readline_1 = __importDefault(require("readline"));
|
|
15
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
16
|
+
const api_1 = require("../utils/api");
|
|
17
|
+
const workspaces_1 = require("./workspaces");
|
|
18
|
+
const config_1 = require("../utils/config");
|
|
19
|
+
function getConfig() {
|
|
20
|
+
const resolved = (0, config_1.resolveConfig)();
|
|
21
|
+
return resolved ? resolved.config : null;
|
|
22
|
+
}
|
|
23
|
+
function saveConfig(config) {
|
|
24
|
+
const resolved = (0, config_1.resolveConfig)();
|
|
25
|
+
const targetPath = resolved ? resolved.activePath : (0, config_1.getGlobalConfigPath)();
|
|
26
|
+
(0, config_1.writeConfigFile)(targetPath, config);
|
|
27
|
+
}
|
|
28
|
+
function clearConfig() {
|
|
29
|
+
(0, config_1.removeConfigFile)((0, config_1.getGlobalConfigPath)());
|
|
30
|
+
}
|
|
31
|
+
async function promptLocation() {
|
|
32
|
+
const rl = readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
33
|
+
try {
|
|
34
|
+
while (true) {
|
|
35
|
+
const answer = await new Promise((resolve) => {
|
|
36
|
+
rl.question(chalk_1.default.blue('Save config locally (./.solidactions) or globally (~/.solidactions)? [global] '), resolve);
|
|
37
|
+
});
|
|
38
|
+
const normalized = answer.trim().toLowerCase();
|
|
39
|
+
if (normalized === '' || normalized === 'global' || normalized === 'g')
|
|
40
|
+
return 'global';
|
|
41
|
+
if (normalized === 'local' || normalized === 'l')
|
|
42
|
+
return 'local';
|
|
43
|
+
console.log(chalk_1.default.yellow("Please answer 'local' or 'global' (or press Enter for global)."));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
rl.close();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function ensureGitignoreCovers(targetDir, auto) {
|
|
51
|
+
const gitignorePath = path_1.default.join(targetDir, '.gitignore');
|
|
52
|
+
const patternToAdd = '.solidactions/';
|
|
53
|
+
let existing = '';
|
|
54
|
+
if (fs_1.default.existsSync(gitignorePath)) {
|
|
55
|
+
existing = fs_1.default.readFileSync(gitignorePath, 'utf-8');
|
|
56
|
+
const lines = existing.split('\n').map((l) => l.trim());
|
|
57
|
+
const isCovered = lines.some((line) => {
|
|
58
|
+
const normalized = line
|
|
59
|
+
.replace(/^\*\*\//, '')
|
|
60
|
+
.replace(/^\//, '')
|
|
61
|
+
.replace(/\/(\*\*|\*)?$/, '');
|
|
62
|
+
return normalized === '.solidactions';
|
|
63
|
+
});
|
|
64
|
+
if (isCovered) {
|
|
65
|
+
return; // already covered
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
let shouldAdd = auto;
|
|
69
|
+
if (!shouldAdd && process.stdin.isTTY) {
|
|
70
|
+
const rl = readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
71
|
+
const answer = await new Promise((resolve) => {
|
|
72
|
+
rl.question(chalk_1.default.yellow(`Local config contains an API key. Add \`.solidactions/\` to ${gitignorePath}? [Y/n] `), resolve);
|
|
73
|
+
});
|
|
74
|
+
rl.close();
|
|
75
|
+
shouldAdd = !(answer.trim().toLowerCase().startsWith('n'));
|
|
76
|
+
}
|
|
77
|
+
if (!shouldAdd) {
|
|
78
|
+
console.log(chalk_1.default.yellow(`Skipping .gitignore update. Remember: ${path_1.default.join(targetDir, '.solidactions', 'config.json')} contains your API key.`));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const prefix = existing.length > 0 && !existing.endsWith('\n') ? '\n' : '';
|
|
82
|
+
try {
|
|
83
|
+
fs_1.default.writeFileSync(gitignorePath, `${existing}${prefix}${patternToAdd}\n`);
|
|
84
|
+
console.log(chalk_1.default.green(`Added \`${patternToAdd}\` to ${gitignorePath}.`));
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
console.log(chalk_1.default.yellow(`Could not update ${gitignorePath}: ${err.message}. Add \`.solidactions/\` to it manually — ${path_1.default.join(targetDir, '.solidactions', 'config.json')} contains your API key.`));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async function login(apiKey, options) {
|
|
91
|
+
let host;
|
|
92
|
+
if (options.host) {
|
|
93
|
+
host = options.host;
|
|
94
|
+
}
|
|
95
|
+
else if (options.dev) {
|
|
96
|
+
host = 'http://localhost:8000';
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
host = 'https://app.solidactions.com';
|
|
100
|
+
}
|
|
101
|
+
if (!apiKey || apiKey.trim().length === 0) {
|
|
102
|
+
console.error(chalk_1.default.red('Error: API key is required.'));
|
|
103
|
+
console.log(chalk_1.default.gray('Generate an API key at: ') + chalk_1.default.blue(`${host}/settings/api-keys`));
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
// Determine target location.
|
|
107
|
+
let target;
|
|
108
|
+
if (options.local && options.global) {
|
|
109
|
+
console.error(chalk_1.default.red('Error: --local and --global are mutually exclusive.'));
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
else if (options.local) {
|
|
113
|
+
target = 'local';
|
|
114
|
+
}
|
|
115
|
+
else if (options.global) {
|
|
116
|
+
target = 'global';
|
|
117
|
+
}
|
|
118
|
+
else if (process.stdin.isTTY) {
|
|
119
|
+
target = await promptLocation();
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
console.error(chalk_1.default.red('Refusing to init non-interactively. Pass --local or --global.'));
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
const targetPath = target === 'local' ? (0, config_1.getLocalConfigPath)() : (0, config_1.getGlobalConfigPath)();
|
|
126
|
+
console.log(chalk_1.default.blue(`Initializing SolidActions CLI...`));
|
|
127
|
+
console.log(chalk_1.default.gray(`Host: ${host}`));
|
|
128
|
+
if ((0, config_1.readConfigFile)(targetPath)) {
|
|
129
|
+
console.log(chalk_1.default.yellow(`Existing config at ${targetPath} will be overwritten.`));
|
|
130
|
+
}
|
|
131
|
+
const config = {
|
|
132
|
+
host,
|
|
133
|
+
apiKey: apiKey.trim(),
|
|
134
|
+
};
|
|
135
|
+
(0, config_1.writeConfigFile)(targetPath, config);
|
|
136
|
+
if (target === 'local') {
|
|
137
|
+
await ensureGitignoreCovers(process.cwd(), !!options.gitignore);
|
|
138
|
+
}
|
|
139
|
+
console.log(chalk_1.default.green('Logged in successfully!'));
|
|
140
|
+
console.log(chalk_1.default.gray(`Configuration saved to ${targetPath}`));
|
|
141
|
+
console.log('');
|
|
142
|
+
// Workspace selection — ensureWorkspaceSelected writes to the right file via the resolver.
|
|
143
|
+
try {
|
|
144
|
+
if (options.workspace) {
|
|
145
|
+
await (0, workspaces_1.workspaceSet)(options.workspace);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
await (0, api_1.ensureWorkspaceSelected)(config);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
console.log(chalk_1.default.yellow('Could not set workspace. Run `solidactions workspace set` later.'));
|
|
153
|
+
}
|
|
154
|
+
console.log('');
|
|
155
|
+
console.log(chalk_1.default.blue('Next step — scaffold a new project (includes AI tooling):'));
|
|
156
|
+
console.log(chalk_1.default.gray(' solidactions init <project-name> Creates ./<project-name>/ with scaffold + AI skills'));
|
|
157
|
+
console.log(chalk_1.default.gray(' solidactions init Scaffolds in the current (empty) directory'));
|
|
158
|
+
console.log('');
|
|
159
|
+
console.log(chalk_1.default.blue('Quick start:'));
|
|
160
|
+
console.log(chalk_1.default.gray(' solidactions project deploy <name> Deploy current directory'));
|
|
161
|
+
console.log(chalk_1.default.gray(' solidactions run start <proj> <wf> Run a workflow'));
|
|
162
|
+
console.log(chalk_1.default.gray(' solidactions run list List recent runs'));
|
|
163
|
+
}
|
|
164
|
+
function logout(options = {}) {
|
|
165
|
+
if (options.local && options.global) {
|
|
166
|
+
console.error(chalk_1.default.red('Error: --local and --global are mutually exclusive.'));
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
const globalPath = (0, config_1.getGlobalConfigPath)();
|
|
170
|
+
const localPath = (0, config_1.findLocalConfigPath)(process.cwd());
|
|
171
|
+
let targetPath;
|
|
172
|
+
if (options.local) {
|
|
173
|
+
targetPath = localPath;
|
|
174
|
+
if (!targetPath) {
|
|
175
|
+
console.error(chalk_1.default.red(`No local config found in ${process.cwd()} or any parent directory.`));
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
else if (options.global) {
|
|
180
|
+
targetPath = globalPath;
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
targetPath = localPath ?? globalPath;
|
|
184
|
+
}
|
|
185
|
+
const removed = (0, config_1.removeConfigFile)(targetPath);
|
|
186
|
+
if (removed) {
|
|
187
|
+
console.log(chalk_1.default.green(`Logged out. Removed ${targetPath}`));
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
console.log(chalk_1.default.gray(`Not logged in (no config at ${targetPath}).`));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function whoami() {
|
|
194
|
+
const resolved = (0, config_1.resolveConfig)();
|
|
195
|
+
if (!resolved || !resolved.config.apiKey) {
|
|
196
|
+
console.log(chalk_1.default.yellow('Not initialized.'));
|
|
197
|
+
console.log(chalk_1.default.gray('Run "solidactions init <api-key>" to configure.'));
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
const { config, sources } = resolved;
|
|
201
|
+
const maskedKey = config.apiKey.length > 12
|
|
202
|
+
? `${config.apiKey.substring(0, 8)}...${config.apiKey.slice(-4)}`
|
|
203
|
+
: config.apiKey;
|
|
204
|
+
const fmt = (src) => {
|
|
205
|
+
if (src === 'env')
|
|
206
|
+
return chalk_1.default.gray('(from $SOLIDACTIONS_* env var)');
|
|
207
|
+
if (src === null)
|
|
208
|
+
return chalk_1.default.gray('(unset)');
|
|
209
|
+
return chalk_1.default.gray(`(from ${src})`);
|
|
210
|
+
};
|
|
211
|
+
console.log(chalk_1.default.blue('Current configuration:'));
|
|
212
|
+
console.log(` Host: ${config.host.padEnd(40)} ${fmt(sources.host)}`);
|
|
213
|
+
console.log(` API Key: ${maskedKey.padEnd(40)} ${fmt(sources.apiKey)}`);
|
|
214
|
+
console.log(` Workspace: ${(config.workspaceId ?? '').padEnd(40)} ${fmt(sources.workspaceId)}`);
|
|
215
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
8
|
const commander_1 = require("commander");
|
|
9
9
|
const deploy_1 = require("./commands/deploy");
|
|
10
|
+
const login_1 = require("./commands/login");
|
|
10
11
|
const init_1 = require("./commands/init");
|
|
11
12
|
const pull_1 = require("./commands/pull");
|
|
12
13
|
const project_list_1 = require("./commands/project-list");
|
|
@@ -61,8 +62,8 @@ program
|
|
|
61
62
|
// Top-level commands
|
|
62
63
|
// =============================================================================
|
|
63
64
|
program
|
|
64
|
-
.command('
|
|
65
|
-
.description('
|
|
65
|
+
.command('login')
|
|
66
|
+
.description('Authenticate the CLI with your API key')
|
|
66
67
|
.argument('<api-key>', 'Your SolidActions API key')
|
|
67
68
|
.option('--dev', 'Use local development server (http://localhost:8000)')
|
|
68
69
|
.option('--host <url>', 'Custom API host URL')
|
|
@@ -71,7 +72,17 @@ program
|
|
|
71
72
|
.option('--global', 'Save config to ~/.solidactions/config.json (default if prompted)')
|
|
72
73
|
.option('--gitignore', 'With --local, add .solidactions/ to .gitignore without prompting')
|
|
73
74
|
.action(async (apiKey, options) => {
|
|
74
|
-
await (0,
|
|
75
|
+
await (0, login_1.login)(apiKey, options);
|
|
76
|
+
});
|
|
77
|
+
program
|
|
78
|
+
.command('init')
|
|
79
|
+
.description('Scaffold a new SolidActions project (files + AI skills)')
|
|
80
|
+
.argument('[directory]', 'Directory to create (omit to scaffold in the current empty directory)')
|
|
81
|
+
.option('--no-skills', 'Skip AI skills/SDK reference install (scaffold files only)')
|
|
82
|
+
.option('--claude', 'Use CLAUDE.md for the AI helper file')
|
|
83
|
+
.option('--agents', 'Use AGENTS.md for the AI helper file (Codex, Cursor, Gemini, Windsurf)')
|
|
84
|
+
.action(async (directory, options) => {
|
|
85
|
+
await (0, init_1.init)(directory, options);
|
|
75
86
|
});
|
|
76
87
|
program
|
|
77
88
|
.command('logout')
|
|
@@ -79,13 +90,13 @@ program
|
|
|
79
90
|
.option('--local', 'Remove only the nearest local ./.solidactions/config.json')
|
|
80
91
|
.option('--global', 'Remove only ~/.solidactions/config.json')
|
|
81
92
|
.action((options) => {
|
|
82
|
-
(0,
|
|
93
|
+
(0, login_1.logout)(options);
|
|
83
94
|
});
|
|
84
95
|
program
|
|
85
96
|
.command('whoami')
|
|
86
97
|
.description('Show current configuration')
|
|
87
98
|
.action(() => {
|
|
88
|
-
(0,
|
|
99
|
+
(0, login_1.whoami)();
|
|
89
100
|
});
|
|
90
101
|
program
|
|
91
102
|
.command('dev')
|
|
@@ -311,10 +322,9 @@ workspace
|
|
|
311
322
|
const ai = program.command('ai').description('AI helper tools');
|
|
312
323
|
ai
|
|
313
324
|
.command('init')
|
|
314
|
-
.description('Install AI
|
|
325
|
+
.description('Install SolidActions AI skills and SDK reference for AI-assisted development')
|
|
315
326
|
.option('--claude', 'Use CLAUDE.md (for Claude Code)')
|
|
316
|
-
.option('--agents', 'Use AGENTS.md (for Cursor, Windsurf, etc.)')
|
|
317
|
-
.option('--no-skills', 'Skip installing SolidActions skill files (uses legacy full CLAUDE.md injection)')
|
|
327
|
+
.option('--agents', 'Use AGENTS.md (for Codex, Cursor, Gemini, Windsurf, etc.)')
|
|
318
328
|
.action((options) => { (0, ai_init_1.aiInit)(options); });
|
|
319
329
|
ai
|
|
320
330
|
.command('examples')
|
package/dist/utils/skills.js
CHANGED
|
@@ -3,9 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.skillTargetDir = skillTargetDir;
|
|
7
7
|
exports.installSkills = installSkills;
|
|
8
|
-
exports.
|
|
8
|
+
exports.fetchAiHelperContent = fetchAiHelperContent;
|
|
9
9
|
const fs_1 = __importDefault(require("fs"));
|
|
10
10
|
const path_1 = __importDefault(require("path"));
|
|
11
11
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
@@ -19,53 +19,41 @@ const EXAMPLES_OWNER = 'SolidActions';
|
|
|
19
19
|
const EXAMPLES_REPO = 'solidactions-examples';
|
|
20
20
|
const SKILLS_PATH_PREFIX = 'skills';
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
23
|
-
* Returns absolute paths to the target skills/ subdirectories.
|
|
22
|
+
* Resolve the skills directory for an AI helper target.
|
|
24
23
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
24
|
+
* - `CLAUDE.md` → `<cwd>/.claude/skills/` (Claude Code convention)
|
|
25
|
+
* - `AGENTS.md` → `<cwd>/.agents/skills/` (Codex auto-discovers this path;
|
|
26
|
+
* Cursor/Gemini read via AGENTS.md pointers)
|
|
28
27
|
*
|
|
29
|
-
*
|
|
30
|
-
* - If `.claude/` exists in cwd → include `.claude/skills/`
|
|
31
|
-
* - If neither exists → return empty (caller should prompt)
|
|
28
|
+
* The directory does not need to exist — the caller creates it.
|
|
32
29
|
*/
|
|
33
|
-
function
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
targets.push(path_1.default.join(cwd, '.claude', 'skills'));
|
|
30
|
+
function skillTargetDir(targetFile, cwd = process.cwd()) {
|
|
31
|
+
if (targetFile === 'CLAUDE.md') {
|
|
32
|
+
return path_1.default.join(cwd, '.claude', 'skills');
|
|
37
33
|
}
|
|
38
|
-
return
|
|
34
|
+
return path_1.default.join(cwd, '.agents', 'skills');
|
|
39
35
|
}
|
|
40
36
|
/**
|
|
41
37
|
* Fetch all SolidActions skill files from the examples repo and write
|
|
42
|
-
* them into
|
|
38
|
+
* them into the target directory. Overwrites existing files (skills
|
|
43
39
|
* are versioned upstream).
|
|
44
40
|
*/
|
|
45
|
-
async function installSkills(
|
|
41
|
+
async function installSkills(targetDir) {
|
|
46
42
|
const written = [];
|
|
47
|
-
|
|
48
|
-
fs_extra_1.default.ensureDirSync(dir);
|
|
49
|
-
}
|
|
43
|
+
fs_extra_1.default.ensureDirSync(targetDir);
|
|
50
44
|
for (const skillName of SKILL_NAMES) {
|
|
51
45
|
const remotePath = `${SKILLS_PATH_PREFIX}/${skillName}.md`;
|
|
52
46
|
const content = await (0, github_1.fetchRawFile)(EXAMPLES_OWNER, EXAMPLES_REPO, remotePath);
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
written.push(filePath);
|
|
57
|
-
}
|
|
47
|
+
const filePath = path_1.default.join(targetDir, `${skillName}.md`);
|
|
48
|
+
fs_1.default.writeFileSync(filePath, content, 'utf8');
|
|
49
|
+
written.push(filePath);
|
|
58
50
|
}
|
|
59
51
|
return { written };
|
|
60
52
|
}
|
|
61
53
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* - skillsInstalled = true → fetches CLAUDE-skills-pointer.md (slim)
|
|
66
|
-
* - skillsInstalled = false → fetches CLAUDE.md (full, legacy)
|
|
54
|
+
* Fetch the slim AI-helper content for the target file from the examples
|
|
55
|
+
* repo. Single source per target — no legacy fallback.
|
|
67
56
|
*/
|
|
68
|
-
async function
|
|
69
|
-
|
|
70
|
-
return (0, github_1.fetchRawFile)(EXAMPLES_OWNER, EXAMPLES_REPO, file);
|
|
57
|
+
async function fetchAiHelperContent(targetFile) {
|
|
58
|
+
return (0, github_1.fetchRawFile)(EXAMPLES_OWNER, EXAMPLES_REPO, targetFile);
|
|
71
59
|
}
|