showpane 0.2.0 → 0.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/README.md +2 -1
- package/dist/index.js +53 -4
- 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
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { createInterface } from "readline";
|
|
5
5
|
import { execSync, spawn, exec } from "child_process";
|
|
6
|
-
import
|
|
6
|
+
import fs from "fs";
|
|
7
7
|
import { randomBytes } from "crypto";
|
|
8
8
|
import { createServer } from "net";
|
|
9
|
-
import
|
|
10
|
-
import
|
|
9
|
+
import path from "path";
|
|
10
|
+
import os from "os";
|
|
11
11
|
import { fileURLToPath } from "url";
|
|
12
|
+
var { mkdirSync, readFileSync, writeFileSync } = fs;
|
|
13
|
+
var { resolve, dirname, join } = path;
|
|
14
|
+
var { homedir } = os;
|
|
12
15
|
var RESET = "\x1B[0m";
|
|
13
16
|
var BOLD = "\x1B[1m";
|
|
14
17
|
var DIM = "\x1B[2m";
|
|
@@ -129,17 +132,63 @@ AUTH_SECRET="${authSecret}"
|
|
|
129
132
|
} catch {
|
|
130
133
|
blue("Skipped example portal (seed failed \u2014 not a problem)");
|
|
131
134
|
}
|
|
135
|
+
const skillsSource = path.resolve(process.cwd(), dirName, "skills");
|
|
136
|
+
const skillsTarget = path.join(os.homedir(), ".claude", "skills");
|
|
137
|
+
const oldSymlink = path.join(skillsTarget, "showpane");
|
|
138
|
+
try {
|
|
139
|
+
const stat = fs.lstatSync(oldSymlink);
|
|
140
|
+
if (stat.isSymbolicLink()) fs.unlinkSync(oldSymlink);
|
|
141
|
+
} catch {
|
|
142
|
+
}
|
|
143
|
+
fs.mkdirSync(skillsTarget, { recursive: true });
|
|
144
|
+
const skillDirs = fs.readdirSync(skillsSource, { withFileTypes: true }).filter((d) => d.isDirectory() && d.name.startsWith("portal-"));
|
|
145
|
+
const installedSkills = [];
|
|
146
|
+
for (const dir of skillDirs) {
|
|
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
|
+
}
|
|
158
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
159
|
+
const skillFile = path.join(targetDir, "SKILL.md");
|
|
160
|
+
try {
|
|
161
|
+
fs.unlinkSync(skillFile);
|
|
162
|
+
} catch {
|
|
163
|
+
}
|
|
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
|
+
}
|
|
176
|
+
}
|
|
177
|
+
green(`${installedSkills.length} Claude Code skills installed`);
|
|
132
178
|
const port = await findFreePort(3e3);
|
|
133
179
|
green(`Server starting on port ${port}`);
|
|
134
180
|
const url = `http://localhost:${port}`;
|
|
135
181
|
blue(`Opening ${url}`);
|
|
136
182
|
console.log();
|
|
137
|
-
console.log(` ${GREEN}Ready!${RESET}
|
|
183
|
+
console.log(` ${GREEN}Ready!${RESET} ${installedSkills.length} Claude Code skills installed.`);
|
|
138
184
|
console.log();
|
|
185
|
+
console.log(` Open Claude Code and create your first portal:`);
|
|
139
186
|
console.log(` ${DIM}cd ${dirName}/app${RESET}`);
|
|
140
187
|
console.log(` ${BOLD}claude${RESET}`);
|
|
141
188
|
console.log(` ${DIM}> Create a portal for my call with [client name]${RESET}`);
|
|
142
189
|
console.log();
|
|
190
|
+
console.log(` Available skills: /portal-create, /portal-deploy, /portal-list, ...`);
|
|
191
|
+
console.log();
|
|
143
192
|
console.log(` ${DIM}Don't have Claude Code? Install from https://claude.ai/code${RESET}`);
|
|
144
193
|
console.log();
|
|
145
194
|
const devServer = spawn("npm", ["run", "dev"], {
|