nextclaw 0.9.11 → 0.9.12

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/cli/index.js +130 -16
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -26,7 +26,7 @@ import {
26
26
  resolvePluginChannelMessageToolHints as resolvePluginChannelMessageToolHints2,
27
27
  setPluginRuntimeBridge as setPluginRuntimeBridge2
28
28
  } from "@nextclaw/openclaw-compat";
29
- import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
29
+ import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
30
30
  import { join as join7, resolve as resolve9 } from "path";
31
31
  import { createInterface as createInterface2 } from "readline";
32
32
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -2252,7 +2252,7 @@ import {
2252
2252
  stopPluginChannelGateways
2253
2253
  } from "@nextclaw/openclaw-compat";
2254
2254
  import { startUiServer } from "@nextclaw/server";
2255
- import { appendFileSync, closeSync, cpSync, existsSync as existsSync8, mkdirSync as mkdirSync4, mkdtempSync, openSync, rmSync as rmSync3 } from "fs";
2255
+ import { appendFileSync, closeSync, cpSync, existsSync as existsSync8, mkdirSync as mkdirSync4, mkdtempSync, openSync, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
2256
2256
  import { dirname, isAbsolute as isAbsolute2, join as join5, relative, resolve as resolve7 } from "path";
2257
2257
  import { tmpdir } from "os";
2258
2258
  import { spawn as spawn2 } from "child_process";
@@ -4391,33 +4391,51 @@ var ServiceCommands = class {
4391
4391
  }
4392
4392
  async materializeMarketplaceGitSkillSource(params) {
4393
4393
  const parsed = this.parseMarketplaceGitSkillSource(params.source);
4394
- const gitPath = findExecutableOnPath("git");
4395
- if (!gitPath) {
4396
- throw new Error("git is required to install marketplace git skills");
4394
+ const gitPath = this.resolveGitExecutablePath();
4395
+ const fallbackNotes = [];
4396
+ if (gitPath) {
4397
+ try {
4398
+ return await this.materializeMarketplaceGitSkillViaGit({ gitPath, parsed });
4399
+ } catch (error) {
4400
+ fallbackNotes.push(`Git fast path failed: ${String(error)}`);
4401
+ }
4402
+ } else {
4403
+ fallbackNotes.push("Git fast path unavailable: git executable not found");
4397
4404
  }
4405
+ const httpResult = await this.materializeMarketplaceGitSkillViaGithubApi(parsed);
4406
+ return {
4407
+ ...httpResult,
4408
+ commandOutput: [...fallbackNotes, httpResult.commandOutput].filter(Boolean).join("\n")
4409
+ };
4410
+ }
4411
+ resolveGitExecutablePath() {
4412
+ return findExecutableOnPath("git");
4413
+ }
4414
+ async materializeMarketplaceGitSkillViaGit(params) {
4398
4415
  const tempRoot = mkdtempSync(join5(tmpdir(), "nextclaw-marketplace-skill-"));
4399
4416
  const repoDir = join5(tempRoot, "repo");
4400
4417
  try {
4401
4418
  const cloneArgs = ["clone", "--depth", "1", "--filter=blob:none", "--sparse"];
4402
- if (parsed.ref) {
4403
- cloneArgs.push("--branch", parsed.ref);
4419
+ if (params.parsed.ref) {
4420
+ cloneArgs.push("--branch", params.parsed.ref);
4404
4421
  }
4405
- cloneArgs.push(parsed.repoUrl, repoDir);
4406
- const cloneResult = await this.runCommand(gitPath, cloneArgs, {
4422
+ cloneArgs.push(params.parsed.repoUrl, repoDir);
4423
+ const cloneResult = await this.runCommand(params.gitPath, cloneArgs, {
4407
4424
  cwd: tempRoot,
4408
4425
  timeoutMs: 18e4
4409
4426
  });
4410
- const sparseResult = await this.runCommand(gitPath, ["-C", repoDir, "sparse-checkout", "set", parsed.skillPath], {
4427
+ const sparseResult = await this.runCommand(params.gitPath, ["-C", repoDir, "sparse-checkout", "set", params.parsed.skillPath], {
4411
4428
  cwd: tempRoot,
4412
4429
  timeoutMs: 6e4
4413
4430
  });
4414
- const skillDir = join5(repoDir, parsed.skillPath);
4431
+ const skillDir = join5(repoDir, params.parsed.skillPath);
4415
4432
  return {
4416
4433
  tempRoot,
4417
4434
  skillDir,
4418
4435
  commandOutput: [
4419
- `Git repository: ${parsed.repoUrl}`,
4420
- `Git path: ${parsed.skillPath}`,
4436
+ "Installer path: git-sparse",
4437
+ `Git repository: ${params.parsed.repoUrl}`,
4438
+ `Git path: ${params.parsed.skillPath}`,
4421
4439
  this.mergeCommandOutput(cloneResult.stdout, cloneResult.stderr),
4422
4440
  this.mergeCommandOutput(sparseResult.stdout, sparseResult.stderr)
4423
4441
  ].filter(Boolean).join("\n")
@@ -4427,6 +4445,98 @@ var ServiceCommands = class {
4427
4445
  throw error;
4428
4446
  }
4429
4447
  }
4448
+ async materializeMarketplaceGitSkillViaGithubApi(parsed) {
4449
+ const tempRoot = mkdtempSync(join5(tmpdir(), "nextclaw-marketplace-skill-"));
4450
+ const skillDir = join5(tempRoot, "skill");
4451
+ const downloadedFiles = [];
4452
+ try {
4453
+ mkdirSync4(skillDir, { recursive: true });
4454
+ await this.downloadGithubDirectoryToPath({
4455
+ parsed,
4456
+ remotePath: parsed.skillPath,
4457
+ localDir: skillDir,
4458
+ relativePrefix: "",
4459
+ downloadedFiles
4460
+ });
4461
+ return {
4462
+ tempRoot,
4463
+ skillDir,
4464
+ commandOutput: [
4465
+ "Installer path: github-http",
4466
+ `Git repository: ${parsed.repoUrl}`,
4467
+ `Git path: ${parsed.skillPath}`,
4468
+ `Downloaded files: ${downloadedFiles.length}`
4469
+ ].join("\n")
4470
+ };
4471
+ } catch (error) {
4472
+ rmSync3(tempRoot, { recursive: true, force: true });
4473
+ throw error;
4474
+ }
4475
+ }
4476
+ async downloadGithubDirectoryToPath(params) {
4477
+ const encodedPath = params.remotePath.split("/").filter(Boolean).map((segment) => encodeURIComponent(segment)).join("/");
4478
+ const apiUrl = new URL(`https://api.github.com/repos/${params.parsed.owner}/${params.parsed.repo}/contents/${encodedPath}`);
4479
+ if (params.parsed.ref) {
4480
+ apiUrl.searchParams.set("ref", params.parsed.ref);
4481
+ }
4482
+ const payload = await this.fetchJsonWithHeaders(apiUrl.toString(), {
4483
+ Accept: "application/vnd.github+json",
4484
+ "User-Agent": `${APP_NAME2}/${getPackageVersion()}`
4485
+ });
4486
+ if (!Array.isArray(payload)) {
4487
+ throw new Error(`GitHub path is not a directory: ${params.remotePath}`);
4488
+ }
4489
+ for (const entry of payload) {
4490
+ if (!entry || typeof entry !== "object") {
4491
+ continue;
4492
+ }
4493
+ const item = entry;
4494
+ const itemName = typeof item.name === "string" ? item.name.trim() : "";
4495
+ const itemPath = typeof item.path === "string" ? item.path.trim() : "";
4496
+ if (!itemName || !itemPath) {
4497
+ continue;
4498
+ }
4499
+ if (item.type === "dir") {
4500
+ const childLocalDir = join5(params.localDir, itemName);
4501
+ mkdirSync4(childLocalDir, { recursive: true });
4502
+ await this.downloadGithubDirectoryToPath({
4503
+ parsed: params.parsed,
4504
+ remotePath: itemPath,
4505
+ localDir: childLocalDir,
4506
+ relativePrefix: params.relativePrefix ? `${params.relativePrefix}/${itemName}` : itemName,
4507
+ downloadedFiles: params.downloadedFiles
4508
+ });
4509
+ continue;
4510
+ }
4511
+ if (item.type !== "file") {
4512
+ throw new Error(`Unsupported GitHub skill entry type: ${item.type ?? "unknown"}`);
4513
+ }
4514
+ if (!item.download_url) {
4515
+ throw new Error(`GitHub skill file missing download_url: ${itemPath}`);
4516
+ }
4517
+ const content = await this.fetchBinaryWithHeaders(item.download_url, {
4518
+ "User-Agent": `${APP_NAME2}/${getPackageVersion()}`
4519
+ });
4520
+ const localFile = join5(params.localDir, itemName);
4521
+ writeFileSync4(localFile, content);
4522
+ params.downloadedFiles.push(params.relativePrefix ? `${params.relativePrefix}/${itemName}` : itemName);
4523
+ }
4524
+ }
4525
+ async fetchJsonWithHeaders(url, headers) {
4526
+ const response = await fetch(url, { headers });
4527
+ if (!response.ok) {
4528
+ throw new Error(`HTTP ${response.status} when fetching ${url}`);
4529
+ }
4530
+ return await response.json();
4531
+ }
4532
+ async fetchBinaryWithHeaders(url, headers) {
4533
+ const response = await fetch(url, { headers });
4534
+ if (!response.ok) {
4535
+ throw new Error(`HTTP ${response.status} when downloading ${url}`);
4536
+ }
4537
+ const bytes = await response.arrayBuffer();
4538
+ return Buffer.from(bytes);
4539
+ }
4430
4540
  parseMarketplaceGitSkillSource(source) {
4431
4541
  const trimmed = source.trim();
4432
4542
  if (!trimmed) {
@@ -4447,6 +4557,8 @@ var ServiceCommands = class {
4447
4557
  throw new Error(`Unsupported GitHub skill source URL: ${source}`);
4448
4558
  }
4449
4559
  return {
4560
+ owner: owner2,
4561
+ repo: repo2,
4450
4562
  repoUrl: `https://github.com/${owner2}/${repo2}.git`,
4451
4563
  skillPath: pathParts2.join("/"),
4452
4564
  ref: ref2
@@ -4466,6 +4578,8 @@ var ServiceCommands = class {
4466
4578
  throw new Error(`Unsupported git skill source: ${source}`);
4467
4579
  }
4468
4580
  return {
4581
+ owner,
4582
+ repo,
4469
4583
  repoUrl: `https://github.com/${owner}/${repo}.git`,
4470
4584
  skillPath: pathParts.join("/"),
4471
4585
  ref: ref && ref.trim().length > 0 ? ref.trim() : void 0
@@ -4628,7 +4742,7 @@ ${stderr}`.trim();
4628
4742
  };
4629
4743
 
4630
4744
  // src/cli/workspace.ts
4631
- import { cpSync as cpSync2, existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync7, readdirSync as readdirSync2, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "fs";
4745
+ import { cpSync as cpSync2, existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync7, readdirSync as readdirSync2, rmSync as rmSync4, writeFileSync as writeFileSync5 } from "fs";
4632
4746
  import { createRequire } from "module";
4633
4747
  import { dirname as dirname2, join as join6, resolve as resolve8 } from "path";
4634
4748
  import { fileURLToPath as fileURLToPath3 } from "url";
@@ -4672,7 +4786,7 @@ var WorkspaceManager = class {
4672
4786
  const raw = readFileSync7(templatePath, "utf-8");
4673
4787
  const content = raw.replace(/\$\{APP_NAME\}/g, APP_NAME3);
4674
4788
  mkdirSync5(dirname2(filePath), { recursive: true });
4675
- writeFileSync4(filePath, content);
4789
+ writeFileSync5(filePath, content);
4676
4790
  created.push(entry.target);
4677
4791
  }
4678
4792
  const memoryDir = join6(workspace, "memory");
@@ -5240,7 +5354,7 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
5240
5354
  const merged = history.concat(
5241
5355
  rl.history ?? []
5242
5356
  );
5243
- writeFileSync5(historyFile, merged.join("\n"));
5357
+ writeFileSync6(historyFile, merged.join("\n"));
5244
5358
  process.exit(0);
5245
5359
  });
5246
5360
  let running = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nextclaw",
3
- "version": "0.9.11",
3
+ "version": "0.9.12",
4
4
  "description": "Lightweight personal AI assistant with CLI, multi-provider routing, and channel integrations.",
5
5
  "private": false,
6
6
  "type": "module",