showpane 0.2.1 → 0.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 +2 -1
- package/dist/index.js +27 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,8 @@ npx showpane
|
|
|
14
14
|
Scaffold a new Showpane portal project. Sets up Next.js, Prisma, and example portal.
|
|
15
15
|
|
|
16
16
|
### `showpane login`
|
|
17
|
-
Authenticate with Showpane Cloud for portal deployment.
|
|
17
|
+
Authenticate with Showpane Cloud for hosted portal deployment.
|
|
18
|
+
This is auth only — org creation and billing happen in the Showpane Cloud web app.
|
|
18
19
|
|
|
19
20
|
## Requirements
|
|
20
21
|
|
package/dist/index.js
CHANGED
|
@@ -132,7 +132,7 @@ AUTH_SECRET="${authSecret}"
|
|
|
132
132
|
} catch {
|
|
133
133
|
blue("Skipped example portal (seed failed \u2014 not a problem)");
|
|
134
134
|
}
|
|
135
|
-
const skillsSource = path.
|
|
135
|
+
const skillsSource = path.resolve(process.cwd(), dirName, "skills");
|
|
136
136
|
const skillsTarget = path.join(os.homedir(), ".claude", "skills");
|
|
137
137
|
const oldSymlink = path.join(skillsTarget, "showpane");
|
|
138
138
|
try {
|
|
@@ -142,26 +142,45 @@ AUTH_SECRET="${authSecret}"
|
|
|
142
142
|
}
|
|
143
143
|
fs.mkdirSync(skillsTarget, { recursive: true });
|
|
144
144
|
const skillDirs = fs.readdirSync(skillsSource, { withFileTypes: true }).filter((d) => d.isDirectory() && d.name.startsWith("portal-"));
|
|
145
|
+
const installedSkills = [];
|
|
145
146
|
for (const dir of skillDirs) {
|
|
146
|
-
const
|
|
147
|
+
const skillMdPath = path.join(skillsSource, dir.name, "SKILL.md");
|
|
148
|
+
if (!fs.existsSync(skillMdPath)) continue;
|
|
149
|
+
const skillContent = fs.readFileSync(skillMdPath, "utf-8");
|
|
150
|
+
const nameMatch = skillContent.match(/^name:\s*(.+)$/m);
|
|
151
|
+
const skillName = nameMatch?.[1]?.trim() || dir.name;
|
|
152
|
+
const targetDir = path.join(skillsTarget, skillName);
|
|
153
|
+
try {
|
|
154
|
+
const stat = fs.lstatSync(targetDir);
|
|
155
|
+
if (stat.isSymbolicLink()) fs.unlinkSync(targetDir);
|
|
156
|
+
} catch {
|
|
157
|
+
}
|
|
147
158
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
148
159
|
const skillFile = path.join(targetDir, "SKILL.md");
|
|
149
160
|
try {
|
|
150
161
|
fs.unlinkSync(skillFile);
|
|
151
162
|
} catch {
|
|
152
163
|
}
|
|
153
|
-
fs.symlinkSync(
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
164
|
+
fs.symlinkSync(skillMdPath, skillFile);
|
|
165
|
+
installedSkills.push(skillName);
|
|
166
|
+
const prefixedDir = path.join(skillsTarget, `showpane-${skillName}`);
|
|
167
|
+
try {
|
|
168
|
+
if (fs.existsSync(prefixedDir) && fs.lstatSync(path.join(prefixedDir, "SKILL.md")).isSymbolicLink()) {
|
|
169
|
+
const linkDest = fs.readlinkSync(path.join(prefixedDir, "SKILL.md"));
|
|
170
|
+
if (linkDest.includes("showpane") || linkDest.includes("portal")) {
|
|
171
|
+
fs.rmSync(prefixedDir, { recursive: true });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
} catch {
|
|
175
|
+
}
|
|
157
176
|
}
|
|
158
|
-
green(`${
|
|
177
|
+
green(`${installedSkills.length} Claude Code skills installed`);
|
|
159
178
|
const port = await findFreePort(3e3);
|
|
160
179
|
green(`Server starting on port ${port}`);
|
|
161
180
|
const url = `http://localhost:${port}`;
|
|
162
181
|
blue(`Opening ${url}`);
|
|
163
182
|
console.log();
|
|
164
|
-
console.log(` ${GREEN}Ready!${RESET} ${
|
|
183
|
+
console.log(` ${GREEN}Ready!${RESET} ${installedSkills.length} Claude Code skills installed.`);
|
|
165
184
|
console.log();
|
|
166
185
|
console.log(` Open Claude Code and create your first portal:`);
|
|
167
186
|
console.log(` ${DIM}cd ${dirName}/app${RESET}`);
|