copilotkit 4.15.0 → 4.17.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 (81) hide show
  1. package/README.md +118 -10
  2. package/cli-build-info.json +8 -8
  3. package/index.js +24194 -3483
  4. package/onboarding/index.json +1 -1
  5. package/onboarding/prompts/authenticate/start.md +17 -15
  6. package/onboarding/prompts/conversion/plan.md +3 -3
  7. package/onboarding/prompts/credentials/finalize-plan.md +20 -20
  8. package/onboarding/prompts/credentials/plan.md +21 -21
  9. package/onboarding/prompts/credentials/settle-credentials.md +46 -10
  10. package/onboarding/prompts/credentials/write-plan.md +35 -20
  11. package/onboarding/prompts/fallback/best-effort.md +23 -15
  12. package/onboarding/prompts/feature/a2ui/implement.md +40 -12
  13. package/onboarding/prompts/feature/a2ui/proof.md +29 -9
  14. package/onboarding/prompts/feature/a2ui/start.md +8 -10
  15. package/onboarding/prompts/feature/blocked-by-plan.md +4 -4
  16. package/onboarding/prompts/feature/channels/implement.md +41 -13
  17. package/onboarding/prompts/feature/channels/proof.md +30 -11
  18. package/onboarding/prompts/feature/channels/start.md +11 -9
  19. package/onboarding/prompts/feature/chat-suggestions/implement.md +40 -12
  20. package/onboarding/prompts/feature/chat-suggestions/proof.md +29 -9
  21. package/onboarding/prompts/feature/chat-suggestions/start.md +8 -10
  22. package/onboarding/prompts/feature/complete.md +2 -2
  23. package/onboarding/prompts/feature/learning/implement.md +58 -26
  24. package/onboarding/prompts/feature/learning/proof.md +30 -10
  25. package/onboarding/prompts/feature/learning/start.md +15 -12
  26. package/onboarding/prompts/feature/open-generative-ui/implement.md +41 -13
  27. package/onboarding/prompts/feature/open-generative-ui/proof.md +29 -9
  28. package/onboarding/prompts/feature/open-generative-ui/start.md +8 -10
  29. package/onboarding/prompts/feature/realtime-sync/implement.md +41 -13
  30. package/onboarding/prompts/feature/realtime-sync/proof.md +31 -10
  31. package/onboarding/prompts/feature/realtime-sync/start.md +8 -9
  32. package/onboarding/prompts/feature/rich-threads/implement.md +42 -14
  33. package/onboarding/prompts/feature/rich-threads/proof.md +31 -10
  34. package/onboarding/prompts/feature/rich-threads/start.md +8 -9
  35. package/onboarding/prompts/feature/stop.md +3 -3
  36. package/onboarding/prompts/feature/voice/implement.md +40 -12
  37. package/onboarding/prompts/feature/voice/proof.md +29 -9
  38. package/onboarding/prompts/feature/voice/start.md +8 -9
  39. package/onboarding/prompts/framework/ag2.md +2 -2
  40. package/onboarding/prompts/framework/agno.md +4 -4
  41. package/onboarding/prompts/framework/built-in.md +2 -2
  42. package/onboarding/prompts/framework/claude-sdk-python.md +8 -7
  43. package/onboarding/prompts/framework/claude-sdk-typescript.md +2 -2
  44. package/onboarding/prompts/framework/crewai-flows.md +15 -7
  45. package/onboarding/prompts/framework/deep-agents.md +4 -3
  46. package/onboarding/prompts/framework/google-adk.md +7 -7
  47. package/onboarding/prompts/framework/langgraph-fastapi.md +2 -2
  48. package/onboarding/prompts/framework/langgraph-python.md +2 -2
  49. package/onboarding/prompts/framework/langgraph-typescript.md +2 -2
  50. package/onboarding/prompts/framework/llamaindex.md +4 -4
  51. package/onboarding/prompts/framework/mastra.md +2 -2
  52. package/onboarding/prompts/framework/ms-agent-dotnet.md +2 -2
  53. package/onboarding/prompts/framework/ms-agent-harness-dotnet.md +2 -2
  54. package/onboarding/prompts/framework/ms-agent-python.md +6 -6
  55. package/onboarding/prompts/framework/pydantic-ai.md +2 -2
  56. package/onboarding/prompts/framework/strands-python.md +4 -4
  57. package/onboarding/prompts/framework/strands-typescript.md +4 -4
  58. package/onboarding/prompts/frontend/angular.md +3 -3
  59. package/onboarding/prompts/frontend/nextjs.md +16 -3
  60. package/onboarding/prompts/frontend/plan.md +7 -7
  61. package/onboarding/prompts/frontend/react-native.md +2 -2
  62. package/onboarding/prompts/frontend/react-spa.md +2 -2
  63. package/onboarding/prompts/frontend/vue.md +2 -2
  64. package/onboarding/prompts/implementation/build-and-validate.md +67 -28
  65. package/onboarding/prompts/proof/complete.md +21 -14
  66. package/onboarding/prompts/proof/oss-baseline.md +16 -12
  67. package/onboarding/prompts/proof/round-trip.md +33 -22
  68. package/onboarding/prompts/research/gather.md +8 -7
  69. package/onboarding/prompts/research/merge.md +3 -3
  70. package/onboarding/prompts/research/preflight.md +4 -4
  71. package/onboarding/prompts/research/route.md +6 -6
  72. package/onboarding/prompts/starter/clone.md +30 -20
  73. package/onboarding/prompts/stopped/run-failed.md +15 -9
  74. package/onboarding/prompts/subagent/create-plan.md +15 -10
  75. package/onboarding/prompts/subagent/implement-and-validate.md +25 -11
  76. package/onboarding/prompts/subagent/inspect-repository.md +14 -6
  77. package/onboarding/prompts/subagent/prove-oss-baseline.md +11 -4
  78. package/onboarding/prompts/subagent/prove-round-trip.md +48 -14
  79. package/onboarding/prompts/unsupported/no-validated-path.md +2 -2
  80. package/package.json +1 -5
  81. package/release/release-tool.js +222 -46
@@ -30,13 +30,13 @@ Before you show the best-effort plan, require this complete packet:
30
30
  - Give the ordered proof rules.
31
31
 
32
32
  After the developer approves the best-effort plan, run
33
- `npx --prefer-offline --yes copilotkit@4.15.0 onboard read fallback/best-effort`.
33
+ `npx --prefer-offline --yes copilotkit@4.17.0 onboard read fallback/best-effort`.
34
34
 
35
35
  Send one short report. Run the friction command without another developer question. Do not
36
36
  ask the developer about telemetry: the command applies the setting they already have.
37
37
 
38
38
  ```text
39
- npx --prefer-offline --yes copilotkit@4.15.0 onboard friction --phase stop --category <slug> --message "<sentences>"
39
+ npx --prefer-offline --yes copilotkit@4.17.0 onboard friction --phase stop --category <slug> --message "<sentences>"
40
40
  ```
41
41
 
42
42
  `--message` takes one or two sentences: the step you stopped at and what stopped it.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "copilotkit",
3
- "version": "4.15.0",
3
+ "version": "4.17.0",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=20.9.0"
@@ -16,9 +16,5 @@
16
16
  "optionalDependencies": {
17
17
  "@microsoft/teams.cli": "3.0.3"
18
18
  },
19
- "dependencies": {
20
- "@mastra/core": "1.48.0",
21
- "@mastra/libsql": "1.14.3"
22
- },
23
19
  "license": "SEE LICENSE IN LICENSE"
24
20
  }
@@ -14811,7 +14811,7 @@ var FLAG_DEFINITIONS = defineFlags({
14811
14811
 
14812
14812
  // apps/cli/src/config.ts
14813
14813
  function getTemplateRef() {
14814
- return true ? "33db9a81ccfd2d6e820defe3c1616594909439af" : "main";
14814
+ return true ? "0c8647a7f4ecf565e58405642539c9d9744f62c5" : "main";
14815
14815
  }
14816
14816
 
14817
14817
  // apps/cli/src/services/agentcore-config.ts
@@ -14980,6 +14980,13 @@ async function writeShowcaseConfig(projectDir, showcase) {
14980
14980
  // apps/cli/src/services/telemetry/event-properties.ts
14981
14981
  var TELEMETRY_ERROR_CODES = {
14982
14982
  TEMPLATE_FETCH_FAILED: "TEMPLATE_FETCH_FAILED",
14983
+ /**
14984
+ * Copying the fetched starter into the project folder failed. Separate from
14985
+ * {@link TELEMETRY_ERROR_CODES.TEMPLATE_FETCH_FAILED}: a Windows antivirus
14986
+ * lock (`EBUSY`) used to be filed as a failed download (PE-358). Buckets as
14987
+ * `filesystem`, or `sandbox_denied` when a sandbox refused the write.
14988
+ */
14989
+ TEMPLATE_COPY_FAILED: "TEMPLATE_COPY_FAILED",
14983
14990
  GIT_FAILED: "GIT_FAILED",
14984
14991
  PREREQUISITE_MISSING: "PREREQUISITE_MISSING",
14985
14992
  INVALID_FRAMEWORK: "INVALID_FRAMEWORK",
@@ -15026,6 +15033,11 @@ function tagError(err, code) {
15026
15033
  err.code = code;
15027
15034
  return err;
15028
15035
  }
15036
+ function annotateFailure(err, cause) {
15037
+ const annotated = err;
15038
+ annotated.failureCause = { ...cause, ...annotated.failureCause };
15039
+ return err;
15040
+ }
15029
15041
 
15030
15042
  // apps/cli/src/types.ts
15031
15043
  var AGENT_FRAMEWORKS = Object.keys(
@@ -15320,6 +15332,7 @@ var FRAMEWORK_TEMPLATES = {
15320
15332
  // key requirement here would falsely warn on valid Azure/`agent/.env`
15321
15333
  // setups — the guidance below points at `agent/.env` instead.
15322
15334
  environment: [],
15335
+ modelKeyTargets: [{ key: "OPENAI_API_KEY", envFile: "agent/.env" }],
15323
15336
  setupNotes: [
15324
15337
  { text: " Set up the agent model credentials in agent/.env:" },
15325
15338
  { text: " OpenAI: ", code: "OPENAI_API_KEY=sk-..." },
@@ -15382,7 +15395,7 @@ var FRAMEWORK_TEMPLATES = {
15382
15395
  import * as fs4 from "node:fs";
15383
15396
  import * as path4 from "node:path";
15384
15397
  import * as os from "node:os";
15385
- import { execFileSync } from "node:child_process";
15398
+ import { execFileSync, spawn } from "node:child_process";
15386
15399
 
15387
15400
  // apps/cli/src/services/project-config.ts
15388
15401
  import * as fs3 from "node:fs";
@@ -15433,6 +15446,11 @@ function canonicalizeDir(dir) {
15433
15446
  }
15434
15447
 
15435
15448
  // apps/cli/src/services/project-scaffold.ts
15449
+ var DEFAULT_GIT_STALL_TIMEOUT_MS = 6e4;
15450
+ var NON_INTERACTIVE_GIT_ENV = {
15451
+ GIT_TERMINAL_PROMPT: "0",
15452
+ GCM_INTERACTIVE: "never"
15453
+ };
15436
15454
  var PROJECT_DIRECTORY_NAMES = /* @__PURE__ */ new Set([
15437
15455
  "agent",
15438
15456
  "api",
@@ -15450,12 +15468,17 @@ var PROJECT_MANIFEST_NAMES = /* @__PURE__ */ new Set([
15450
15468
  "Gemfile",
15451
15469
  "build.gradle",
15452
15470
  "composer.json",
15471
+ "global.json",
15453
15472
  "go.mod",
15454
15473
  "package.json",
15455
15474
  "pom.xml",
15456
15475
  "pyproject.toml",
15457
15476
  "requirements.txt"
15458
15477
  ]);
15478
+ var PROJECT_MANIFEST_EXTENSIONS = [".csproj", ".sln"];
15479
+ function isProjectManifest(entry) {
15480
+ return PROJECT_MANIFEST_NAMES.has(entry) || PROJECT_MANIFEST_EXTENSIONS.some((extension) => entry.endsWith(extension));
15481
+ }
15459
15482
  var ENV_TEMPLATE_SUFFIXES = [".example", ".sample", ".template"];
15460
15483
  function isCredentialEnvFile(entry) {
15461
15484
  if (!entry.startsWith(".env"))
@@ -15467,7 +15490,7 @@ function isCredentialEnvFile(entry) {
15467
15490
  function entryHoldsProject(entry) {
15468
15491
  if (isCredentialEnvFile(entry))
15469
15492
  return true;
15470
- return PROJECT_DIRECTORY_NAMES.has(entry) || PROJECT_MANIFEST_NAMES.has(entry);
15493
+ return PROJECT_DIRECTORY_NAMES.has(entry) || isProjectManifest(entry);
15471
15494
  }
15472
15495
  var SYSTEM_FOLDERS = [
15473
15496
  "/Applications",
@@ -15511,24 +15534,68 @@ function readEntries(dir) {
15511
15534
  }
15512
15535
  }
15513
15536
  function findProjectsBelow(dir) {
15537
+ return walkProjectsBelow(dir, readEntries(dir), {
15538
+ stopAfter: Number.POSITIVE_INFINITY,
15539
+ maxEntries: Number.POSITIVE_INFINITY
15540
+ }).found.sort();
15541
+ }
15542
+ function readEntriesUpTo(dir, limit) {
15543
+ if (limit === Number.POSITIVE_INFINITY) {
15544
+ return {
15545
+ entries: fs4.readdirSync(dir, { withFileTypes: true }),
15546
+ exhausted: false
15547
+ };
15548
+ }
15549
+ const handle = fs4.opendirSync(dir);
15550
+ const entries = [];
15551
+ try {
15552
+ for (let entry = handle.readSync(); entry !== null; entry = handle.readSync()) {
15553
+ if (entries.length >= limit)
15554
+ return { entries, exhausted: true };
15555
+ entries.push(entry);
15556
+ }
15557
+ return { entries, exhausted: false };
15558
+ } finally {
15559
+ handle.closeSync();
15560
+ }
15561
+ }
15562
+ function walkProjectsBelow(dir, top, limits) {
15514
15563
  const found = [];
15515
- const visit = (relative, depth) => {
15516
- for (const entry of readEntries(path4.join(dir, relative))) {
15564
+ let budget = limits.maxEntries - top.length;
15565
+ let exhausted = budget < 0;
15566
+ const readChild = (childDir) => {
15567
+ try {
15568
+ const read = readEntriesUpTo(childDir, budget);
15569
+ budget -= read.entries.length;
15570
+ if (read.exhausted)
15571
+ exhausted = true;
15572
+ return read.entries;
15573
+ } catch {
15574
+ return [];
15575
+ }
15576
+ };
15577
+ const visit = (relative, entries, depth) => {
15578
+ for (const entry of entries) {
15579
+ if (found.length >= limits.stopAfter || exhausted)
15580
+ return;
15517
15581
  if (!entry.isDirectory())
15518
15582
  continue;
15519
15583
  if (entry.name.startsWith(".") || entry.name === "node_modules")
15520
15584
  continue;
15521
15585
  const child = path4.join(relative, entry.name);
15522
- const names = readEntries(path4.join(dir, child)).map((e) => e.name);
15523
- if (names.some((n) => n === ".git" || PROJECT_MANIFEST_NAMES.has(n))) {
15586
+ const childEntries = readChild(path4.join(dir, child));
15587
+ if (exhausted)
15588
+ return;
15589
+ const names = childEntries.map((e) => e.name);
15590
+ if (names.some((n) => n === ".git" || isProjectManifest(n))) {
15524
15591
  found.push(child);
15525
15592
  } else if (depth < PROJECTS_BELOW_DEPTH) {
15526
- visit(child, depth + 1);
15593
+ visit(child, childEntries, depth + 1);
15527
15594
  }
15528
15595
  }
15529
15596
  };
15530
- visit("", 1);
15531
- return found.sort();
15597
+ visit("", top, 1);
15598
+ return { found, exhausted };
15532
15599
  }
15533
15600
  function readProjectDirContents(projectDir, homeDir = os.homedir()) {
15534
15601
  if (!fs4.existsSync(projectDir))
@@ -15577,6 +15644,7 @@ function occupiedMessage(projectDir, contents) {
15577
15644
  }
15578
15645
  async function scaffoldProject(options) {
15579
15646
  const { projectDir, template } = options;
15647
+ const stallTimeoutMs = options.gitStallTimeoutMs ?? DEFAULT_GIT_STALL_TIMEOUT_MS;
15580
15648
  assertProjectDirAvailable(projectDir);
15581
15649
  const localTemplateDir = process.env["COPILOTKIT_TEMPLATE_DIR"];
15582
15650
  if (localTemplateDir !== void 0 && localTemplateDir !== "") {
@@ -15588,8 +15656,16 @@ async function scaffoldProject(options) {
15588
15656
  TELEMETRY_ERROR_CODES.TEMPLATE_FETCH_FAILED
15589
15657
  );
15590
15658
  }
15591
- fs4.mkdirSync(projectDir, { recursive: true });
15592
- await copyDirectory(localTemplateDir, projectDir, true);
15659
+ try {
15660
+ fs4.mkdirSync(projectDir, { recursive: true });
15661
+ await copyDirectory(localTemplateDir, projectDir, true);
15662
+ } catch (cause) {
15663
+ throw wrapStepError(
15664
+ cause,
15665
+ TELEMETRY_ERROR_CODES.TEMPLATE_COPY_FAILED,
15666
+ "copy"
15667
+ );
15668
+ }
15593
15669
  return;
15594
15670
  }
15595
15671
  const source = typeof template === "string" ? parseGitHubUrl(template) : {
@@ -15599,7 +15675,7 @@ async function scaffoldProject(options) {
15599
15675
  subdirectoryPath: template.path,
15600
15676
  mode: template.mode
15601
15677
  };
15602
- await cloneTemplate(source, projectDir);
15678
+ await cloneTemplate(source, projectDir, stallTimeoutMs);
15603
15679
  }
15604
15680
  function pathEntryExists(entryPath) {
15605
15681
  try {
@@ -15612,61 +15688,85 @@ function pathEntryExists(entryPath) {
15612
15688
  throw error48;
15613
15689
  }
15614
15690
  }
15615
- async function cloneTemplate(source, destinationPath) {
15691
+ async function cloneTemplate(source, destinationPath, stallTimeoutMs) {
15616
15692
  const { owner, repo, revision, subdirectoryPath, mode } = source;
15617
15693
  const tempDir = fs4.mkdtempSync(path4.join(os.tmpdir(), "copilotkit-clone-"));
15618
15694
  const isWholeRepo = mode === "whole-repository";
15619
15695
  const destinationExisted = pathEntryExists(destinationPath);
15620
15696
  try {
15621
- runGit(
15697
+ await runGit(
15622
15698
  ["init"],
15623
- { cwd: tempDir, stdio: "pipe" },
15624
- TELEMETRY_ERROR_CODES.GIT_FAILED
15699
+ { cwd: tempDir, stallTimeoutMs },
15700
+ TELEMETRY_ERROR_CODES.GIT_FAILED,
15701
+ "git_init"
15625
15702
  );
15626
- runGit(
15703
+ await runGit(
15627
15704
  ["remote", "add", "origin", `https://github.com/${owner}/${repo}.git`],
15628
- { cwd: tempDir, stdio: "pipe" },
15629
- TELEMETRY_ERROR_CODES.GIT_FAILED
15705
+ { cwd: tempDir, stallTimeoutMs },
15706
+ TELEMETRY_ERROR_CODES.GIT_FAILED,
15707
+ "remote_add"
15630
15708
  );
15631
15709
  if (!isWholeRepo) {
15632
- runGit(
15710
+ await runGit(
15633
15711
  ["config", "core.sparseCheckout", "true"],
15634
- { cwd: tempDir, stdio: "pipe" },
15635
- TELEMETRY_ERROR_CODES.GIT_FAILED
15636
- );
15637
- fs4.writeFileSync(
15638
- path4.join(tempDir, ".git/info/sparse-checkout"),
15639
- subdirectoryPath
15712
+ { cwd: tempDir, stallTimeoutMs },
15713
+ TELEMETRY_ERROR_CODES.GIT_FAILED,
15714
+ "sparse_config"
15640
15715
  );
15716
+ try {
15717
+ fs4.writeFileSync(
15718
+ path4.join(tempDir, ".git/info/sparse-checkout"),
15719
+ subdirectoryPath
15720
+ );
15721
+ } catch (cause) {
15722
+ throw wrapStepError(
15723
+ cause,
15724
+ TELEMETRY_ERROR_CODES.GIT_FAILED,
15725
+ "sparse_config"
15726
+ );
15727
+ }
15641
15728
  }
15642
- runGit(
15643
- ["fetch", "--depth=1", "origin", revision],
15644
- { cwd: tempDir, stdio: "pipe" },
15645
- TELEMETRY_ERROR_CODES.TEMPLATE_FETCH_FAILED
15729
+ await runGit(
15730
+ ["fetch", "--progress", "--depth=1", "origin", revision],
15731
+ { cwd: tempDir, stallTimeoutMs },
15732
+ TELEMETRY_ERROR_CODES.TEMPLATE_FETCH_FAILED,
15733
+ "fetch"
15646
15734
  );
15647
- runGit(
15648
- ["checkout", "--detach", "FETCH_HEAD"],
15649
- { cwd: tempDir, stdio: "pipe" },
15650
- TELEMETRY_ERROR_CODES.GIT_FAILED
15735
+ await runGit(
15736
+ ["checkout", "--progress", "--detach", "FETCH_HEAD"],
15737
+ { cwd: tempDir, stallTimeoutMs },
15738
+ TELEMETRY_ERROR_CODES.GIT_FAILED,
15739
+ "checkout"
15651
15740
  );
15652
15741
  const sourcePath = isWholeRepo ? tempDir : path4.join(tempDir, subdirectoryPath);
15653
15742
  if (!isWholeRepo && !fs4.existsSync(sourcePath)) {
15654
- throw tagError(
15655
- new Error(
15656
- `Template directory '${subdirectoryPath}' not found in the repository.`
15743
+ throw annotateFailure(
15744
+ tagError(
15745
+ new Error(
15746
+ `Template directory '${subdirectoryPath}' not found in the repository.`
15747
+ ),
15748
+ TELEMETRY_ERROR_CODES.TEMPLATE_FETCH_FAILED
15657
15749
  ),
15658
- TELEMETRY_ERROR_CODES.TEMPLATE_FETCH_FAILED
15750
+ { failedStep: "subdirectory_missing" }
15751
+ );
15752
+ }
15753
+ try {
15754
+ fs4.mkdirSync(destinationPath, { recursive: true });
15755
+ await copyDirectory(sourcePath, destinationPath, isWholeRepo);
15756
+ } catch (cause) {
15757
+ throw wrapStepError(
15758
+ cause,
15759
+ TELEMETRY_ERROR_CODES.TEMPLATE_COPY_FAILED,
15760
+ "copy"
15659
15761
  );
15660
15762
  }
15661
- fs4.mkdirSync(destinationPath, { recursive: true });
15662
- await copyDirectory(sourcePath, destinationPath, isWholeRepo);
15663
15763
  } catch (cause) {
15664
15764
  if (!destinationExisted) {
15665
15765
  fs4.rmSync(destinationPath, { recursive: true, force: true });
15666
15766
  }
15667
15767
  const error48 = cause instanceof Error ? cause : new Error("Starter template checkout failed");
15668
15768
  const code = error48.code;
15669
- if (code === TELEMETRY_ERROR_CODES.TEMPLATE_FETCH_FAILED || code === TELEMETRY_ERROR_CODES.GIT_FAILED) {
15769
+ if (code === TELEMETRY_ERROR_CODES.TEMPLATE_FETCH_FAILED || code === TELEMETRY_ERROR_CODES.TEMPLATE_COPY_FAILED || code === TELEMETRY_ERROR_CODES.GIT_FAILED) {
15670
15770
  throw error48;
15671
15771
  }
15672
15772
  throw tagError(error48, TELEMETRY_ERROR_CODES.TEMPLATE_FETCH_FAILED);
@@ -15695,12 +15795,88 @@ async function copyDirectory(source, destination, excludeGit = false) {
15695
15795
  }
15696
15796
  }
15697
15797
  }
15698
- function runGit(args, opts, code) {
15798
+ function wrapStepError(cause, code, failedStep) {
15799
+ const message = cause instanceof Error ? cause.message : `Starter step failed: ${failedStep}`;
15800
+ const status = cause?.status;
15801
+ return annotateFailure(tagError(new Error(message, { cause }), code), {
15802
+ failedStep,
15803
+ ...typeof status === "number" ? { gitExitCode: status } : {}
15804
+ });
15805
+ }
15806
+ var GIT_STDERR_TAIL_LINES = 20;
15807
+ var GIT_PROGRESS_LINE = /^(remote: )?(Counting|Compressing|Receiving|Resolving|Enumerating|Updating files|Total)\b/;
15808
+ function gitStderrTail(stderr) {
15809
+ return stderr.split(/\r|\n/).map((line) => line.trimEnd()).filter((line) => line !== "" && !GIT_PROGRESS_LINE.test(line)).slice(-GIT_STDERR_TAIL_LINES).join("\n");
15810
+ }
15811
+ var GIT_STDERR_MAX_CHARS = 64 * 1024;
15812
+ function stallError(command, failedStep, options) {
15813
+ const seconds = Math.round(options.stallTimeoutMs / 1e3);
15814
+ const advice = failedStep === "fetch" ? " Check your network connection to github.com. If you are behind a proxy, set HTTPS_PROXY to its address and run the command again." : "";
15815
+ return Object.assign(
15816
+ new Error(
15817
+ `\`${command}\` stopped: git printed nothing for ${seconds} seconds.${advice}`
15818
+ ),
15819
+ { code: "ETIMEDOUT" }
15820
+ );
15821
+ }
15822
+ async function runGit(args, options, code, failedStep) {
15823
+ const command = `git ${args.join(" ")}`;
15699
15824
  try {
15700
- execFileSync("git", args, opts);
15825
+ await new Promise((resolve5, reject) => {
15826
+ const child = spawn("git", args, {
15827
+ cwd: options.cwd,
15828
+ env: { ...process.env, ...NON_INTERACTIVE_GIT_ENV },
15829
+ stdio: ["ignore", "ignore", "pipe"],
15830
+ windowsHide: true
15831
+ });
15832
+ let stderr = "";
15833
+ let settled = false;
15834
+ let watchdog;
15835
+ const settle = (finish) => {
15836
+ if (settled)
15837
+ return;
15838
+ settled = true;
15839
+ clearTimeout(watchdog);
15840
+ finish();
15841
+ };
15842
+ const armWatchdog = () => {
15843
+ clearTimeout(watchdog);
15844
+ watchdog = setTimeout(() => {
15845
+ child.kill();
15846
+ child.stderr.destroy();
15847
+ child.unref();
15848
+ settle(() => reject(stallError(command, failedStep, options)));
15849
+ }, options.stallTimeoutMs);
15850
+ };
15851
+ armWatchdog();
15852
+ child.stderr.setEncoding("utf8");
15853
+ child.stderr.on("data", (chunk) => {
15854
+ stderr = (stderr + chunk).slice(-GIT_STDERR_MAX_CHARS);
15855
+ armWatchdog();
15856
+ });
15857
+ child.on("error", (error48) => settle(() => reject(error48)));
15858
+ child.on(
15859
+ "close",
15860
+ (status) => settle(() => {
15861
+ if (status === 0) {
15862
+ resolve5();
15863
+ return;
15864
+ }
15865
+ const tail = gitStderrTail(stderr);
15866
+ reject(
15867
+ Object.assign(
15868
+ new Error(
15869
+ `Command failed: ${command}${tail ? `
15870
+ ${tail}` : ""}`
15871
+ ),
15872
+ { status }
15873
+ )
15874
+ );
15875
+ })
15876
+ );
15877
+ });
15701
15878
  } catch (cause) {
15702
- const wrapped = cause instanceof Error ? cause : new Error(`git command failed: git ${args.join(" ")}`);
15703
- throw tagError(wrapped, code);
15879
+ throw wrapStepError(cause, code, failedStep);
15704
15880
  }
15705
15881
  }
15706
15882
  function parseGitHubUrl(githubUrl) {