@stackable-labs/cli-app-extension 1.92.1 → 1.93.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.
Files changed (2) hide show
  1. package/dist/index.js +88 -1
  2. 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: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackable-labs/cli-app-extension",
3
- "version": "1.92.1",
3
+ "version": "1.93.0",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "bin": {