@stackable-labs/cli-app-extension 1.92.1 → 1.93.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/dist/index.js +88 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
|
10
10
|
import TextInput from 'ink-text-input';
|
|
11
11
|
import { SURFACE_TARGET } from '@stackable-labs/sdk-extension-contracts';
|
|
12
12
|
import { homedir } from 'os';
|
|
13
|
-
import { execFile, spawn } from 'child_process';
|
|
13
|
+
import { execFile, spawn, execSync } from 'child_process';
|
|
14
14
|
import { promisify } from 'util';
|
|
15
15
|
import { installDependencies } from 'nypm';
|
|
16
16
|
import { downloadTemplate } from 'giget';
|
|
@@ -3355,11 +3355,79 @@ var downloadAndExtractAiDocs = async (targetDir, version2, filter) => {
|
|
|
3355
3355
|
return { files: extractedFiles.sort() };
|
|
3356
3356
|
};
|
|
3357
3357
|
var downloadAndExtractMcpConfig = async (targetDir, version2) => downloadAndExtractAiDocs(targetDir, version2, (name) => MCP_FILE_PATTERN.test(name));
|
|
3358
|
+
var isClaudeCodeEnvironment = () => {
|
|
3359
|
+
if (process.env.CLAUDE_CODE) {
|
|
3360
|
+
return true;
|
|
3361
|
+
}
|
|
3362
|
+
try {
|
|
3363
|
+
execSync("which claude", { stdio: "ignore" });
|
|
3364
|
+
return true;
|
|
3365
|
+
} catch {
|
|
3366
|
+
return false;
|
|
3367
|
+
}
|
|
3368
|
+
};
|
|
3369
|
+
var PLUGIN_SETTINGS = {
|
|
3370
|
+
extraKnownMarketplaces: {
|
|
3371
|
+
"stackable-claude-plugins": {
|
|
3372
|
+
source: { source: "github", repo: "stackable-labs/claude-plugins" }
|
|
3373
|
+
}
|
|
3374
|
+
},
|
|
3375
|
+
enabledPlugins: {
|
|
3376
|
+
"stackable-extension-dev@stackable-claude-plugins": true
|
|
3377
|
+
}
|
|
3378
|
+
};
|
|
3379
|
+
var writePluginSettings = async (targetDir) => {
|
|
3380
|
+
const settingsDir = join(targetDir, ".claude");
|
|
3381
|
+
const settingsPath = join(settingsDir, "settings.json");
|
|
3382
|
+
await mkdir(settingsDir, { recursive: true });
|
|
3383
|
+
await writeFile(settingsPath, JSON.stringify(PLUGIN_SETTINGS, null, 2) + "\n");
|
|
3384
|
+
return [".claude/settings.json"];
|
|
3385
|
+
};
|
|
3386
|
+
var MODE_OPTIONS = [
|
|
3387
|
+
{ value: "plugin", label: "Plugin (recommended)", description: "Install via Claude Code plugin \u2014 always up to date, no local files" },
|
|
3388
|
+
{ value: "local", label: "Local files", description: "Extract AI editor configs into project (same as non-Claude editors)" }
|
|
3389
|
+
];
|
|
3358
3390
|
var AIScaffold = ({ version: version2 }) => {
|
|
3359
3391
|
const { exit } = useApp();
|
|
3360
3392
|
const [state, setState] = useState("validating");
|
|
3361
3393
|
const [files, setFiles] = useState([]);
|
|
3362
3394
|
const [errorMessage, setErrorMessage] = useState("");
|
|
3395
|
+
const [cursor, setCursor] = useState(0);
|
|
3396
|
+
const handleMode = async (mode) => {
|
|
3397
|
+
const projectDir = process.cwd();
|
|
3398
|
+
try {
|
|
3399
|
+
if (mode === "plugin") {
|
|
3400
|
+
const result = await writePluginSettings(projectDir);
|
|
3401
|
+
setFiles(result);
|
|
3402
|
+
} else {
|
|
3403
|
+
const result = await downloadAndExtractAiDocs(projectDir, version2);
|
|
3404
|
+
setFiles(result.files);
|
|
3405
|
+
}
|
|
3406
|
+
setState("done");
|
|
3407
|
+
} catch (err) {
|
|
3408
|
+
setErrorMessage(err instanceof Error ? err.message : String(err));
|
|
3409
|
+
setState("error");
|
|
3410
|
+
}
|
|
3411
|
+
exit();
|
|
3412
|
+
};
|
|
3413
|
+
useInput((_input, key) => {
|
|
3414
|
+
if (state !== "choosing") {
|
|
3415
|
+
return;
|
|
3416
|
+
}
|
|
3417
|
+
if (key.upArrow) {
|
|
3418
|
+
setCursor((c) => Math.max(0, c - 1));
|
|
3419
|
+
return;
|
|
3420
|
+
}
|
|
3421
|
+
if (key.downArrow) {
|
|
3422
|
+
setCursor((c) => Math.min(MODE_OPTIONS.length - 1, c + 1));
|
|
3423
|
+
return;
|
|
3424
|
+
}
|
|
3425
|
+
if (key.return) {
|
|
3426
|
+
const mode = MODE_OPTIONS[cursor].value;
|
|
3427
|
+
setState("downloading");
|
|
3428
|
+
void handleMode(mode);
|
|
3429
|
+
}
|
|
3430
|
+
});
|
|
3363
3431
|
useEffect(() => {
|
|
3364
3432
|
const run = async () => {
|
|
3365
3433
|
const projectDir = process.cwd();
|
|
@@ -3370,6 +3438,10 @@ var AIScaffold = ({ version: version2 }) => {
|
|
|
3370
3438
|
exit();
|
|
3371
3439
|
return;
|
|
3372
3440
|
}
|
|
3441
|
+
if (isClaudeCodeEnvironment()) {
|
|
3442
|
+
setState("choosing");
|
|
3443
|
+
return;
|
|
3444
|
+
}
|
|
3373
3445
|
setState("downloading");
|
|
3374
3446
|
try {
|
|
3375
3447
|
const result = await downloadAndExtractAiDocs(projectDir, version2);
|
|
@@ -3390,6 +3462,21 @@ var AIScaffold = ({ version: version2 }) => {
|
|
|
3390
3462
|
/* @__PURE__ */ jsx(Text, { color: "cyan", children: /* @__PURE__ */ jsx(Spinner5, { type: "dots" }) }),
|
|
3391
3463
|
/* @__PURE__ */ jsx(Text, { children: "Checking project..." })
|
|
3392
3464
|
] }),
|
|
3465
|
+
state === "choosing" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
3466
|
+
/* @__PURE__ */ jsx(Text, { children: "Claude Code detected \u2014 choose how to set up AI assistance:" }),
|
|
3467
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", gap: 1, children: MODE_OPTIONS.map((opt, i) => {
|
|
3468
|
+
const isCursor = i === cursor;
|
|
3469
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
3470
|
+
/* @__PURE__ */ jsx(Text, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
|
|
3471
|
+
/* @__PURE__ */ jsx(Text, { color: isCursor ? "green" : void 0, children: isCursor ? "\u25C9" : "\u25CB" }),
|
|
3472
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3473
|
+
/* @__PURE__ */ jsx(Text, { bold: isCursor, children: opt.label }),
|
|
3474
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: opt.description })
|
|
3475
|
+
] })
|
|
3476
|
+
] }, opt.value);
|
|
3477
|
+
}) }),
|
|
3478
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 to navigate, Enter to select" })
|
|
3479
|
+
] }),
|
|
3393
3480
|
state === "downloading" && /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
3394
3481
|
/* @__PURE__ */ jsx(Text, { color: "cyan", children: /* @__PURE__ */ jsx(Spinner5, { type: "dots" }) }),
|
|
3395
3482
|
/* @__PURE__ */ jsxs(Text, { children: [
|