copilotkit 4.13.0 → 4.14.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 (80) hide show
  1. package/README.md +109 -6
  2. package/cli-build-info.json +8 -8
  3. package/index.js +43866 -40955
  4. package/onboarding/index.json +1 -1
  5. package/onboarding/prompts/authenticate/start.md +38 -27
  6. package/onboarding/prompts/conversion/plan.md +3 -3
  7. package/onboarding/prompts/credentials/finalize-plan.md +14 -12
  8. package/onboarding/prompts/credentials/plan.md +21 -21
  9. package/onboarding/prompts/credentials/settle-credentials.md +18 -11
  10. package/onboarding/prompts/credentials/write-plan.md +19 -12
  11. package/onboarding/prompts/fallback/best-effort.md +9 -9
  12. package/onboarding/prompts/feature/a2ui/implement.md +6 -6
  13. package/onboarding/prompts/feature/a2ui/proof.md +6 -6
  14. package/onboarding/prompts/feature/a2ui/start.md +7 -7
  15. package/onboarding/prompts/feature/channels/implement.md +41 -15
  16. package/onboarding/prompts/feature/channels/proof.md +12 -10
  17. package/onboarding/prompts/feature/channels/start.md +13 -12
  18. package/onboarding/prompts/feature/chat-suggestions/implement.md +6 -6
  19. package/onboarding/prompts/feature/chat-suggestions/proof.md +6 -6
  20. package/onboarding/prompts/feature/chat-suggestions/start.md +7 -7
  21. package/onboarding/prompts/feature/complete.md +19 -1
  22. package/onboarding/prompts/feature/learning/implement.md +16 -16
  23. package/onboarding/prompts/feature/learning/proof.md +7 -7
  24. package/onboarding/prompts/feature/learning/start.md +8 -8
  25. package/onboarding/prompts/feature/open-generative-ui/implement.md +6 -6
  26. package/onboarding/prompts/feature/open-generative-ui/proof.md +6 -6
  27. package/onboarding/prompts/feature/open-generative-ui/start.md +7 -7
  28. package/onboarding/prompts/feature/realtime-sync/implement.md +7 -7
  29. package/onboarding/prompts/feature/realtime-sync/proof.md +6 -6
  30. package/onboarding/prompts/feature/realtime-sync/start.md +6 -6
  31. package/onboarding/prompts/feature/rich-threads/implement.md +10 -10
  32. package/onboarding/prompts/feature/rich-threads/proof.md +6 -6
  33. package/onboarding/prompts/feature/rich-threads/start.md +6 -6
  34. package/onboarding/prompts/feature/stop.md +36 -2
  35. package/onboarding/prompts/feature/voice/implement.md +7 -7
  36. package/onboarding/prompts/feature/voice/proof.md +6 -6
  37. package/onboarding/prompts/feature/voice/start.md +8 -8
  38. package/onboarding/prompts/framework/ag2.md +2 -2
  39. package/onboarding/prompts/framework/agno.md +2 -2
  40. package/onboarding/prompts/framework/built-in.md +2 -2
  41. package/onboarding/prompts/framework/claude-sdk-python.md +2 -2
  42. package/onboarding/prompts/framework/claude-sdk-typescript.md +2 -2
  43. package/onboarding/prompts/framework/crewai-flows.md +2 -2
  44. package/onboarding/prompts/framework/deep-agents.md +2 -2
  45. package/onboarding/prompts/framework/google-adk.md +2 -2
  46. package/onboarding/prompts/framework/langgraph-fastapi.md +2 -2
  47. package/onboarding/prompts/framework/langgraph-python.md +2 -2
  48. package/onboarding/prompts/framework/langgraph-typescript.md +2 -2
  49. package/onboarding/prompts/framework/llamaindex.md +2 -2
  50. package/onboarding/prompts/framework/mastra.md +2 -2
  51. package/onboarding/prompts/framework/ms-agent-dotnet.md +2 -2
  52. package/onboarding/prompts/framework/ms-agent-harness-dotnet.md +2 -2
  53. package/onboarding/prompts/framework/ms-agent-python.md +2 -2
  54. package/onboarding/prompts/framework/pydantic-ai.md +2 -2
  55. package/onboarding/prompts/framework/strands-python.md +2 -2
  56. package/onboarding/prompts/framework/strands-typescript.md +2 -2
  57. package/onboarding/prompts/frontend/angular.md +3 -3
  58. package/onboarding/prompts/frontend/nextjs.md +3 -3
  59. package/onboarding/prompts/frontend/plan.md +7 -7
  60. package/onboarding/prompts/frontend/react-native.md +5 -2
  61. package/onboarding/prompts/frontend/react-spa.md +5 -2
  62. package/onboarding/prompts/frontend/vue.md +5 -2
  63. package/onboarding/prompts/implementation/build-and-validate.md +24 -23
  64. package/onboarding/prompts/proof/complete.md +8 -8
  65. package/onboarding/prompts/proof/oss-baseline.md +5 -5
  66. package/onboarding/prompts/proof/round-trip.md +11 -11
  67. package/onboarding/prompts/research/gather.md +36 -7
  68. package/onboarding/prompts/research/merge.md +3 -3
  69. package/onboarding/prompts/research/preflight.md +4 -4
  70. package/onboarding/prompts/research/route.md +10 -8
  71. package/onboarding/prompts/starter/clone.md +97 -26
  72. package/onboarding/prompts/stopped/run-failed.md +2 -2
  73. package/onboarding/prompts/subagent/create-plan.md +4 -4
  74. package/onboarding/prompts/subagent/implement-and-validate.md +26 -6
  75. package/onboarding/prompts/subagent/inspect-repository.md +2 -2
  76. package/onboarding/prompts/subagent/prove-oss-baseline.md +2 -2
  77. package/onboarding/prompts/subagent/prove-round-trip.md +10 -10
  78. package/onboarding/prompts/unsupported/no-validated-path.md +2 -2
  79. package/package.json +5 -1
  80. package/release/release-tool.js +330 -72
@@ -55,16 +55,16 @@ var require_starter_source_policy = __commonJS({
55
55
 
56
56
  // apps/cli/src/release/cli-release.ts
57
57
  import { execFileSync as execFileSync2 } from "node:child_process";
58
- import * as fs5 from "node:fs";
59
- import * as path5 from "node:path";
58
+ import * as fs6 from "node:fs";
59
+ import * as path6 from "node:path";
60
60
 
61
61
  // apps/cli/src/starter-source-catalog.ts
62
62
  var import_starter_source_policy = __toESM(require_starter_source_policy(), 1);
63
- function copilotKitStarter(path6) {
63
+ function copilotKitStarter(path7) {
64
64
  return {
65
65
  owner: "CopilotKit",
66
66
  repo: "CopilotKit",
67
- path: path6,
67
+ path: path7,
68
68
  mode: "sparse",
69
69
  ownership: "first-party"
70
70
  };
@@ -903,10 +903,10 @@ function mergeDefs(...defs) {
903
903
  function cloneDef(schema) {
904
904
  return mergeDefs(schema._zod.def);
905
905
  }
906
- function getElementAtPath(obj, path6) {
907
- if (!path6)
906
+ function getElementAtPath(obj, path7) {
907
+ if (!path7)
908
908
  return obj;
909
- return path6.reduce((acc, key) => acc?.[key], obj);
909
+ return path7.reduce((acc, key) => acc?.[key], obj);
910
910
  }
911
911
  function promiseAllObject(promisesObj) {
912
912
  const keys = Object.keys(promisesObj);
@@ -1289,11 +1289,11 @@ function aborted(x, startIndex = 0) {
1289
1289
  }
1290
1290
  return false;
1291
1291
  }
1292
- function prefixIssues(path6, issues) {
1292
+ function prefixIssues(path7, issues) {
1293
1293
  return issues.map((iss) => {
1294
1294
  var _a2;
1295
1295
  (_a2 = iss).path ?? (_a2.path = []);
1296
- iss.path.unshift(path6);
1296
+ iss.path.unshift(path7);
1297
1297
  return iss;
1298
1298
  });
1299
1299
  }
@@ -1476,7 +1476,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
1476
1476
  }
1477
1477
  function treeifyError(error48, mapper = (issue2) => issue2.message) {
1478
1478
  const result = { errors: [] };
1479
- const processError = (error49, path6 = []) => {
1479
+ const processError = (error49, path7 = []) => {
1480
1480
  var _a2, _b;
1481
1481
  for (const issue2 of error49.issues) {
1482
1482
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -1486,7 +1486,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
1486
1486
  } else if (issue2.code === "invalid_element") {
1487
1487
  processError({ issues: issue2.issues }, issue2.path);
1488
1488
  } else {
1489
- const fullpath = [...path6, ...issue2.path];
1489
+ const fullpath = [...path7, ...issue2.path];
1490
1490
  if (fullpath.length === 0) {
1491
1491
  result.errors.push(mapper(issue2));
1492
1492
  continue;
@@ -1518,8 +1518,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
1518
1518
  }
1519
1519
  function toDotPath(_path) {
1520
1520
  const segs = [];
1521
- const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1522
- for (const seg of path6) {
1521
+ const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1522
+ for (const seg of path7) {
1523
1523
  if (typeof seg === "number")
1524
1524
  segs.push(`[${seg}]`);
1525
1525
  else if (typeof seg === "symbol")
@@ -13495,13 +13495,13 @@ function resolveRef(ref, ctx) {
13495
13495
  if (!ref.startsWith("#")) {
13496
13496
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
13497
13497
  }
13498
- const path6 = ref.slice(1).split("/").filter(Boolean);
13499
- if (path6.length === 0) {
13498
+ const path7 = ref.slice(1).split("/").filter(Boolean);
13499
+ if (path7.length === 0) {
13500
13500
  return ctx.rootSchema;
13501
13501
  }
13502
13502
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
13503
- if (path6[0] === defsKey) {
13504
- const key = path6[1];
13503
+ if (path7[0] === defsKey) {
13504
+ const key = path7[1];
13505
13505
  if (!key || !ctx.defs[key]) {
13506
13506
  throw new Error(`Reference not found: ${ref}`);
13507
13507
  }
@@ -14427,11 +14427,11 @@ async function resolveCopilotKitSource(options) {
14427
14427
  }
14428
14428
  }
14429
14429
  const uniquePaths = options.validateStarterPaths === false ? [] : [...new Set(options.starterPaths)];
14430
- for (const path6 of uniquePaths) {
14430
+ for (const path7 of uniquePaths) {
14431
14431
  const content = await requestGitHub(
14432
- `${apiRoot}/contents/${encodeURIComponent(path6)}?ref=${canonicalCommit}`,
14432
+ `${apiRoot}/contents/${encodeURIComponent(path7)}?ref=${canonicalCommit}`,
14433
14433
  "contents",
14434
- { path: path6, canonicalCommit },
14434
+ { path: path7, canonicalCommit },
14435
14435
  fetchImpl,
14436
14436
  options.githubToken,
14437
14437
  options.requestTimeoutMs
@@ -14442,14 +14442,14 @@ async function resolveCopilotKitSource(options) {
14442
14442
  if (content !== null && typeof content === "object" && !Array.isArray(content) && "type" in content && content.type === "file") {
14443
14443
  throw new ReleasePreflightError(
14444
14444
  "STARTER_PATH_NOT_DIRECTORY",
14445
- `The CopilotKit starter path ${path6} is not a directory`,
14446
- { path: path6, canonicalCommit }
14445
+ `The CopilotKit starter path ${path7} is not a directory`,
14446
+ { path: path7, canonicalCommit }
14447
14447
  );
14448
14448
  }
14449
14449
  throw new ReleasePreflightError(
14450
14450
  "GITHUB_RESPONSE_INVALID",
14451
- `GitHub returned invalid contents metadata for ${path6}`,
14452
- { path: path6, canonicalCommit }
14451
+ `GitHub returned invalid contents metadata for ${path7}`,
14452
+ { path: path7, canonicalCommit }
14453
14453
  );
14454
14454
  }
14455
14455
  return {
@@ -14692,13 +14692,126 @@ function planReleaseReconciliation(options) {
14692
14692
 
14693
14693
  // apps/cli/src/release/smoke-starters.ts
14694
14694
  import { execFile } from "node:child_process";
14695
- import * as fs4 from "node:fs";
14695
+ import * as fs5 from "node:fs";
14696
14696
  import * as os2 from "node:os";
14697
- import * as path4 from "node:path";
14697
+ import * as path5 from "node:path";
14698
+
14699
+ // libs/feature-flags/src/registry.ts
14700
+ function defineFlags(defs) {
14701
+ return Object.fromEntries(
14702
+ Object.entries(defs).map(([key, body]) => [key, { ...body, key }])
14703
+ );
14704
+ }
14705
+ var FLAG_DEFINITIONS = defineFlags({
14706
+ // Ops can auto-deploy before App API, including in staging. Keep issuance
14707
+ // off in every environment until all verifiers accept this signed claim.
14708
+ "cli.organization-slug": {
14709
+ purpose: "Include the Clerk organization slug in CLI product credentials after App API rollout.",
14710
+ owner: "platform",
14711
+ createdAt: "2026-09-17",
14712
+ status: "rollout",
14713
+ surfaces: ["ops-api"],
14714
+ defaultByEnv: { dev: false, ci: false, prod: false },
14715
+ envVar: "OPS_CLI_ORGANIZATION_SLUG_ENABLED"
14716
+ },
14717
+ // Self-hosted is a seam, not an offered choice yet (PE-94): the target moves
14718
+ // only the app API URL, and no onboarding path offers it. Keep released
14719
+ // binaries on managed until a self-hosted deployment can serve the product.
14720
+ "cli.self-hosted-deployment": {
14721
+ purpose: "Lets the CLI target a self-hosted Intelligence deployment through --deployment or COPILOTKIT_DEPLOYMENT.",
14722
+ owner: "platform",
14723
+ createdAt: "2026-09-22",
14724
+ status: "rollout",
14725
+ surfaces: ["cli"],
14726
+ defaultByEnv: { dev: true, ci: true, prod: false }
14727
+ },
14728
+ "threads.bounded-replay": {
14729
+ purpose: "Stage connect history on disk and require SDK acknowledgements for bounded delivery.",
14730
+ owner: "realtime",
14731
+ createdAt: "2026-09-16",
14732
+ status: "rollout",
14733
+ surfaces: ["realtime-gateway", "copilotkit-core"],
14734
+ defaultByEnv: { dev: true, ci: true, prod: false },
14735
+ envVar: "REALTIME_GATEWAY_BOUNDED_REPLAY_ENABLED"
14736
+ },
14737
+ // `active` (not `rollout`): a long-lived operational kill-switch, default-on
14738
+ // in every env; `envVar` adopts the pre-existing INSPECT_ROUTES_ENABLED name.
14739
+ "inspect.routes": {
14740
+ purpose: "Gates the /api/_inspect/* introspection routes used by the web inspector; operational kill-switch.",
14741
+ owner: "platform",
14742
+ createdAt: "2026-06-23",
14743
+ status: "active",
14744
+ surfaces: ["app-api"],
14745
+ defaultByEnv: { dev: true, ci: true, prod: true },
14746
+ envVar: "INSPECT_ROUTES_ENABLED"
14747
+ },
14748
+ // Rollout flag for the in-progress Channels feature (OSS-373). Lets the
14749
+ // SDK, UI, and infra land incrementally and deploy dark; production stays off
14750
+ // until the rollout completes and the prod default is flipped in a later
14751
+ // build. Server boundaries enforce it via the shared `resolveChannelsRollout`
14752
+ // helper; `envVar` pins the pre-existing FF_MANAGED_BOTS toggle name so the
14753
+ // operational override is byte-identical across the rename.
14754
+ channels: {
14755
+ purpose: "Gates the Channels feature (activation, listener, delivery, egress) so unfinished customer behavior stays dark until rollout completes.",
14756
+ owner: "channels",
14757
+ createdAt: "2026-06-25",
14758
+ status: "rollout",
14759
+ surfaces: ["app-api", "realtime-gateway", "app-frontend"],
14760
+ defaultByEnv: { dev: true, ci: true, prod: false },
14761
+ envVar: "FF_MANAGED_BOTS"
14762
+ },
14763
+ "managed-channels": {
14764
+ purpose: "Canonical Managed Channels rollout gate, evaluated alongside the legacy FF_MANAGED_BOTS override while deployments migrate.",
14765
+ owner: "channels",
14766
+ createdAt: "2026-07-09",
14767
+ status: "rollout",
14768
+ surfaces: ["app-api", "realtime-gateway", "app-frontend"],
14769
+ defaultByEnv: { dev: true, ci: true, prod: true }
14770
+ },
14771
+ "learning.platform-v1": {
14772
+ purpose: "Gates the Learning V1 control API, runtime workers, product UI, and CLI download while the platform rolls out.",
14773
+ owner: "learning",
14774
+ createdAt: "2026-08-06",
14775
+ status: "rollout",
14776
+ surfaces: ["app-api", "app-frontend", "cli"],
14777
+ defaultByEnv: { dev: false, ci: false, prod: false },
14778
+ envVar: "LEARNING_ENABLED"
14779
+ },
14780
+ "analytics.pipeline": {
14781
+ purpose: "Gates project-scoped analytics reads and realtime projection while the durable pipeline rolls out.",
14782
+ owner: "analytics",
14783
+ createdAt: "2026-08-16",
14784
+ status: "rollout",
14785
+ surfaces: ["app-api", "realtime-gateway"],
14786
+ defaultByEnv: { dev: false, ci: false, prod: false },
14787
+ envVar: "ANALYTICS_ENABLED"
14788
+ },
14789
+ // PE-242: an agent cannot tell whether the developer's browser shares its
14790
+ // machine, so the loopback redirect fails over SSH, in VMs, and in
14791
+ // containers. Ops mounts the device routes and the CLI switches
14792
+ // `login --json` to them; with the flag off both keep the loopback flow.
14793
+ // On in prod from CLI 4.14.0; Ops prod already served the routes.
14794
+ "cli.device-login": {
14795
+ purpose: "Signs in `copilotkit login --json` and `login --device` with an RFC 8628 device authorization grant instead of the loopback redirect.",
14796
+ owner: "platform",
14797
+ createdAt: "2026-09-23",
14798
+ status: "rollout",
14799
+ surfaces: ["ops-api", "cli"],
14800
+ defaultByEnv: { dev: true, ci: true, prod: true }
14801
+ },
14802
+ "ops.stripe-billing-v1": {
14803
+ purpose: "Gates the direct Stripe Checkout, Portal, projection, and provider-aware billing API during rollout.",
14804
+ owner: "ops",
14805
+ createdAt: "2026-09-08",
14806
+ status: "rollout",
14807
+ surfaces: ["ops-api"],
14808
+ defaultByEnv: { dev: true, ci: true, prod: false }
14809
+ }
14810
+ });
14698
14811
 
14699
14812
  // apps/cli/src/config.ts
14700
14813
  function getTemplateRef() {
14701
- return true ? "1e13b4945b44c6afa2e398a0c9935415d4aa7577" : "main";
14814
+ return true ? "2c42a41a7e749c4473705769d1ae985d89718465" : "main";
14702
14815
  }
14703
14816
 
14704
14817
  // apps/cli/src/services/agentcore-config.ts
@@ -15266,10 +15379,60 @@ var FRAMEWORK_TEMPLATES = {
15266
15379
  };
15267
15380
 
15268
15381
  // apps/cli/src/services/project-scaffold.ts
15269
- import * as fs3 from "node:fs";
15270
- import * as path3 from "node:path";
15382
+ import * as fs4 from "node:fs";
15383
+ import * as path4 from "node:path";
15271
15384
  import * as os from "node:os";
15272
15385
  import { execFileSync } from "node:child_process";
15386
+
15387
+ // apps/cli/src/services/project-config.ts
15388
+ import * as fs3 from "node:fs";
15389
+ import * as path3 from "node:path";
15390
+ var projectConfigSchema = external_exports.object({
15391
+ projectId: external_exports.string().min(1),
15392
+ projectSlug: external_exports.string().min(1),
15393
+ /**
15394
+ * Clerk organization the selection was made under.
15395
+ *
15396
+ * Absent on a self-hosted deployment, which has no Clerk organization at
15397
+ * all. Demanding it made `.copilotkit/project.json` unparseable there, and
15398
+ * the symptom surfaced a long way from the cause: `verify` reported the
15399
+ * file "exists but could not be read" and failed `project_selected` on a
15400
+ * correctly wired project, because resolution never reached the contents
15401
+ * (PE-95).
15402
+ *
15403
+ * Optional, not loose. An empty string is still rejected: absent means
15404
+ * self-hosted, blank means something wrote a bug.
15405
+ */
15406
+ clerkOrgId: external_exports.string().min(1).optional(),
15407
+ telemetryBindingId: external_exports.string().trim().min(1).optional(),
15408
+ /**
15409
+ * Absolute URL of this project's CopilotKit runtime, when the project pins
15410
+ * one.
15411
+ *
15412
+ * Stated, never guessed. `copilotkit verify` works out the port from the
15413
+ * app's own dev configuration, and this is where a project whose runtime is
15414
+ * somewhere that cannot be worked out — a different mount path, a
15415
+ * container, a port that only ever appears on a command line — says so once
15416
+ * instead of passing `--runtime-url` on every invocation (OSS-1090).
15417
+ *
15418
+ * A person writes it, and so does `project select --runtime-url`. An
15419
+ * onboarding run settles a free port and then has nowhere to put it, so
15420
+ * `verify` falls back to its assumed default and reports on whatever holds
15421
+ * that port — in one run, an unrelated checkout (PE-58). The flag is still
15422
+ * a statement rather than a guess: the caller has to name the URL.
15423
+ */
15424
+ runtimeUrl: external_exports.string().trim().min(1).optional()
15425
+ }).strict();
15426
+ function canonicalizeDir(dir) {
15427
+ const resolved = path3.resolve(dir);
15428
+ try {
15429
+ return fs3.realpathSync(resolved);
15430
+ } catch {
15431
+ return resolved;
15432
+ }
15433
+ }
15434
+
15435
+ // apps/cli/src/services/project-scaffold.ts
15273
15436
  var PROJECT_DIRECTORY_NAMES = /* @__PURE__ */ new Set([
15274
15437
  "agent",
15275
15438
  "api",
@@ -15306,23 +15469,118 @@ function entryHoldsProject(entry) {
15306
15469
  return true;
15307
15470
  return PROJECT_DIRECTORY_NAMES.has(entry) || PROJECT_MANIFEST_NAMES.has(entry);
15308
15471
  }
15309
- function isProjectDirOccupied(projectDir) {
15310
- return fs3.existsSync(projectDir) && fs3.readdirSync(projectDir).some(entryHoldsProject);
15472
+ var SYSTEM_FOLDERS = [
15473
+ "/Applications",
15474
+ "/Library",
15475
+ "/System",
15476
+ "/Users",
15477
+ "/Volumes",
15478
+ "/bin",
15479
+ "/etc",
15480
+ "/home",
15481
+ "/opt",
15482
+ "/private",
15483
+ "/private/tmp",
15484
+ "/private/var",
15485
+ "/sbin",
15486
+ "/tmp",
15487
+ "/usr",
15488
+ "/var"
15489
+ ];
15490
+ var PROJECTS_BELOW_DEPTH = 2;
15491
+ function sharedFolderKind(dir, homeDir) {
15492
+ const home = canonicalizeDir(homeDir);
15493
+ if (dir === home)
15494
+ return "home";
15495
+ const system = new Set(
15496
+ [
15497
+ ...SYSTEM_FOLDERS,
15498
+ path4.parse(dir).root,
15499
+ path4.dirname(home),
15500
+ os.tmpdir(),
15501
+ process.env["SystemRoot"] ?? ""
15502
+ ].filter((folder) => folder !== "").map(canonicalizeDir)
15503
+ );
15504
+ return system.has(dir) ? "system" : void 0;
15505
+ }
15506
+ function readEntries(dir) {
15507
+ try {
15508
+ return fs4.readdirSync(dir, { withFileTypes: true });
15509
+ } catch {
15510
+ return [];
15511
+ }
15311
15512
  }
15312
- function assertProjectDirAvailable(projectDir) {
15313
- if (isProjectDirOccupied(projectDir)) {
15513
+ function findProjectsBelow(dir) {
15514
+ const found = [];
15515
+ const visit = (relative, depth) => {
15516
+ for (const entry of readEntries(path4.join(dir, relative))) {
15517
+ if (!entry.isDirectory())
15518
+ continue;
15519
+ if (entry.name.startsWith(".") || entry.name === "node_modules")
15520
+ continue;
15521
+ 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))) {
15524
+ found.push(child);
15525
+ } else if (depth < PROJECTS_BELOW_DEPTH) {
15526
+ visit(child, depth + 1);
15527
+ }
15528
+ }
15529
+ };
15530
+ visit("", 1);
15531
+ return found.sort();
15532
+ }
15533
+ function readProjectDirContents(projectDir, homeDir = os.homedir()) {
15534
+ if (!fs4.existsSync(projectDir))
15535
+ return { kind: "available" };
15536
+ const dir = canonicalizeDir(projectDir);
15537
+ const folder = sharedFolderKind(dir, homeDir);
15538
+ if (folder !== void 0)
15539
+ return { kind: "shared-folder", folder };
15540
+ const entries = readEntries(dir).map((entry) => entry.name);
15541
+ if (entries.some(entryHoldsProject))
15542
+ return { kind: "project" };
15543
+ const projects = findProjectsBelow(dir);
15544
+ if (projects.length === 0)
15545
+ return { kind: "available" };
15546
+ return entries.includes(".git") ? { kind: "project" } : { kind: "projects-below", projects };
15547
+ }
15548
+ function assertProjectDirAvailable(projectDir, homeDir = os.homedir()) {
15549
+ const message = occupiedMessage(
15550
+ projectDir,
15551
+ readProjectDirContents(projectDir, homeDir)
15552
+ );
15553
+ if (message !== void 0) {
15314
15554
  throw tagError(
15315
- new Error(`${projectDir} already holds a project`),
15555
+ new Error(message),
15316
15556
  TELEMETRY_ERROR_CODES.PREREQUISITE_MISSING
15317
15557
  );
15318
15558
  }
15319
15559
  }
15560
+ var LISTED_PROJECTS = 5;
15561
+ function occupiedMessage(projectDir, contents) {
15562
+ const elsewhere = "Create an empty folder for the new app, or open your project folder, and run init there.";
15563
+ switch (contents.kind) {
15564
+ case "available":
15565
+ return void 0;
15566
+ case "project":
15567
+ return `${projectDir} already holds a project`;
15568
+ case "shared-folder":
15569
+ return contents.folder === "home" ? `${projectDir} is your home folder. ${elsewhere}` : `${projectDir} is a system folder. ${elsewhere}`;
15570
+ case "projects-below": {
15571
+ const named = contents.projects.slice(0, LISTED_PROJECTS);
15572
+ const more = contents.projects.length - named.length;
15573
+ const list = named.join(", ") + (more > 0 ? `, and ${more} more` : "");
15574
+ return `${projectDir} holds other projects: ${list}. ${elsewhere}`;
15575
+ }
15576
+ }
15577
+ }
15320
15578
  async function scaffoldProject(options) {
15321
15579
  const { projectDir, template } = options;
15322
15580
  assertProjectDirAvailable(projectDir);
15323
15581
  const localTemplateDir = process.env["COPILOTKIT_TEMPLATE_DIR"];
15324
15582
  if (localTemplateDir !== void 0 && localTemplateDir !== "") {
15325
- if (!fs3.existsSync(localTemplateDir)) {
15583
+ if (!fs4.existsSync(localTemplateDir)) {
15326
15584
  throw tagError(
15327
15585
  new Error(
15328
15586
  `COPILOTKIT_TEMPLATE_DIR points at a path that does not exist: ${localTemplateDir}`
@@ -15330,7 +15588,7 @@ async function scaffoldProject(options) {
15330
15588
  TELEMETRY_ERROR_CODES.TEMPLATE_FETCH_FAILED
15331
15589
  );
15332
15590
  }
15333
- fs3.mkdirSync(projectDir, { recursive: true });
15591
+ fs4.mkdirSync(projectDir, { recursive: true });
15334
15592
  await copyDirectory(localTemplateDir, projectDir, true);
15335
15593
  return;
15336
15594
  }
@@ -15345,7 +15603,7 @@ async function scaffoldProject(options) {
15345
15603
  }
15346
15604
  function pathEntryExists(entryPath) {
15347
15605
  try {
15348
- fs3.lstatSync(entryPath);
15606
+ fs4.lstatSync(entryPath);
15349
15607
  return true;
15350
15608
  } catch (error48) {
15351
15609
  if (error48 instanceof Error && "code" in error48 && error48.code === "ENOENT") {
@@ -15356,7 +15614,7 @@ function pathEntryExists(entryPath) {
15356
15614
  }
15357
15615
  async function cloneTemplate(source, destinationPath) {
15358
15616
  const { owner, repo, revision, subdirectoryPath, mode } = source;
15359
- const tempDir = fs3.mkdtempSync(path3.join(os.tmpdir(), "copilotkit-clone-"));
15617
+ const tempDir = fs4.mkdtempSync(path4.join(os.tmpdir(), "copilotkit-clone-"));
15360
15618
  const isWholeRepo = mode === "whole-repository";
15361
15619
  const destinationExisted = pathEntryExists(destinationPath);
15362
15620
  try {
@@ -15376,8 +15634,8 @@ async function cloneTemplate(source, destinationPath) {
15376
15634
  { cwd: tempDir, stdio: "pipe" },
15377
15635
  TELEMETRY_ERROR_CODES.GIT_FAILED
15378
15636
  );
15379
- fs3.writeFileSync(
15380
- path3.join(tempDir, ".git/info/sparse-checkout"),
15637
+ fs4.writeFileSync(
15638
+ path4.join(tempDir, ".git/info/sparse-checkout"),
15381
15639
  subdirectoryPath
15382
15640
  );
15383
15641
  }
@@ -15391,8 +15649,8 @@ async function cloneTemplate(source, destinationPath) {
15391
15649
  { cwd: tempDir, stdio: "pipe" },
15392
15650
  TELEMETRY_ERROR_CODES.GIT_FAILED
15393
15651
  );
15394
- const sourcePath = isWholeRepo ? tempDir : path3.join(tempDir, subdirectoryPath);
15395
- if (!isWholeRepo && !fs3.existsSync(sourcePath)) {
15652
+ const sourcePath = isWholeRepo ? tempDir : path4.join(tempDir, subdirectoryPath);
15653
+ if (!isWholeRepo && !fs4.existsSync(sourcePath)) {
15396
15654
  throw tagError(
15397
15655
  new Error(
15398
15656
  `Template directory '${subdirectoryPath}' not found in the repository.`
@@ -15400,11 +15658,11 @@ async function cloneTemplate(source, destinationPath) {
15400
15658
  TELEMETRY_ERROR_CODES.TEMPLATE_FETCH_FAILED
15401
15659
  );
15402
15660
  }
15403
- fs3.mkdirSync(destinationPath, { recursive: true });
15661
+ fs4.mkdirSync(destinationPath, { recursive: true });
15404
15662
  await copyDirectory(sourcePath, destinationPath, isWholeRepo);
15405
15663
  } catch (cause) {
15406
15664
  if (!destinationExisted) {
15407
- fs3.rmSync(destinationPath, { recursive: true, force: true });
15665
+ fs4.rmSync(destinationPath, { recursive: true, force: true });
15408
15666
  }
15409
15667
  const error48 = cause instanceof Error ? cause : new Error("Starter template checkout failed");
15410
15668
  const code = error48.code;
@@ -15414,26 +15672,26 @@ async function cloneTemplate(source, destinationPath) {
15414
15672
  throw tagError(error48, TELEMETRY_ERROR_CODES.TEMPLATE_FETCH_FAILED);
15415
15673
  } finally {
15416
15674
  try {
15417
- fs3.rmSync(tempDir, { recursive: true, force: true });
15675
+ fs4.rmSync(tempDir, { recursive: true, force: true });
15418
15676
  } catch {
15419
15677
  }
15420
15678
  }
15421
15679
  }
15422
15680
  async function copyDirectory(source, destination, excludeGit = false) {
15423
- if (!fs3.existsSync(destination)) {
15424
- fs3.mkdirSync(destination, { recursive: true });
15681
+ if (!fs4.existsSync(destination)) {
15682
+ fs4.mkdirSync(destination, { recursive: true });
15425
15683
  }
15426
- const entries = fs3.readdirSync(source, { withFileTypes: true });
15684
+ const entries = fs4.readdirSync(source, { withFileTypes: true });
15427
15685
  for (const entry of entries) {
15428
15686
  if (excludeGit && entry.name === ".git") {
15429
15687
  continue;
15430
15688
  }
15431
- const srcPath = path3.join(source, entry.name);
15432
- const destPath = path3.join(destination, entry.name);
15689
+ const srcPath = path4.join(source, entry.name);
15690
+ const destPath = path4.join(destination, entry.name);
15433
15691
  if (entry.isDirectory()) {
15434
15692
  await copyDirectory(srcPath, destPath, excludeGit);
15435
15693
  } else {
15436
- fs3.copyFileSync(srcPath, destPath);
15694
+ fs4.copyFileSync(srcPath, destPath);
15437
15695
  }
15438
15696
  }
15439
15697
  }
@@ -15491,10 +15749,10 @@ var StarterSmokeError = class extends Error {
15491
15749
  }
15492
15750
  };
15493
15751
  async function scaffoldStarterForSmoke(input, scaffold = scaffoldProject) {
15494
- const temporaryRoot = fs4.mkdtempSync(
15495
- path4.join(os2.tmpdir(), `copilotkit-smoke-${input.framework}-`)
15752
+ const temporaryRoot = fs5.mkdtempSync(
15753
+ path5.join(os2.tmpdir(), `copilotkit-smoke-${input.framework}-`)
15496
15754
  );
15497
- const projectDir = path4.join(temporaryRoot, "project");
15755
+ const projectDir = path5.join(temporaryRoot, "project");
15498
15756
  try {
15499
15757
  const definition = FRAMEWORK_TEMPLATES[input.framework];
15500
15758
  const configuredTemplate = definition.template;
@@ -15535,8 +15793,8 @@ async function scaffoldStarterForSmoke(input, scaffold = scaffoldProject) {
15535
15793
  const credential = command?.match(
15536
15794
  /dotnet user-secrets set ([A-Za-z0-9_]+)/
15537
15795
  )?.[1];
15538
- const programPath = path4.join(projectDir, "agent", "Program.cs");
15539
- const program = fs4.existsSync(programPath) ? fs4.readFileSync(programPath, "utf8") : "";
15796
+ const programPath = path5.join(projectDir, "agent", "Program.cs");
15797
+ const program = fs5.existsSync(programPath) ? fs5.readFileSync(programPath, "utf8") : "";
15540
15798
  if (!credential || !program.includes(credential)) {
15541
15799
  throw new StarterSmokeError(
15542
15800
  "STARTER_CREDENTIAL_MISMATCH",
@@ -15549,14 +15807,14 @@ async function scaffoldStarterForSmoke(input, scaffold = scaffoldProject) {
15549
15807
  );
15550
15808
  }
15551
15809
  }
15552
- const entries = fs4.readdirSync(projectDir);
15810
+ const entries = fs5.readdirSync(projectDir);
15553
15811
  return entries.join("\n");
15554
15812
  } finally {
15555
- fs4.rmSync(temporaryRoot, { recursive: true, force: true });
15813
+ fs5.rmSync(temporaryRoot, { recursive: true, force: true });
15556
15814
  }
15557
15815
  }
15558
15816
  async function executeStarterSmokeChild(command) {
15559
- return new Promise((resolve4, reject) => {
15817
+ return new Promise((resolve5, reject) => {
15560
15818
  execFile(
15561
15819
  command.executable,
15562
15820
  [...command.args],
@@ -15570,7 +15828,7 @@ async function executeStarterSmokeChild(command) {
15570
15828
  reject(error48);
15571
15829
  return;
15572
15830
  }
15573
- resolve4(stdout);
15831
+ resolve5(stdout);
15574
15832
  }
15575
15833
  );
15576
15834
  });
@@ -15587,7 +15845,7 @@ async function runStarterSmokeChild(input, execute = executeStarterSmokeChild, e
15587
15845
  return await execute({
15588
15846
  executable: process.execPath,
15589
15847
  args: [
15590
- path4.resolve(entrypoint),
15848
+ path5.resolve(entrypoint),
15591
15849
  "smoke-one",
15592
15850
  "--framework",
15593
15851
  input.framework,
@@ -15897,7 +16155,7 @@ function parseArguments(args) {
15897
16155
  return { command: releaseCommand, flags };
15898
16156
  }
15899
16157
  function readJsonObject(inputPath) {
15900
- const text = inputPath === "-" ? fs5.readFileSync(0, "utf8") : fs5.readFileSync(inputPath, "utf8");
16158
+ const text = inputPath === "-" ? fs6.readFileSync(0, "utf8") : fs6.readFileSync(inputPath, "utf8");
15901
16159
  const value = JSON.parse(text);
15902
16160
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
15903
16161
  throw new ReleaseCliInputError(`Expected a JSON object in ${inputPath}`);
@@ -15923,8 +16181,8 @@ function emitResult(result, scalarOutputs, flags, stdout) {
15923
16181
  `;
15924
16182
  const outputPath = flags.get("--output");
15925
16183
  if (outputPath !== void 0) {
15926
- fs5.mkdirSync(path5.dirname(path5.resolve(outputPath)), { recursive: true });
15927
- fs5.writeFileSync(outputPath, json2);
16184
+ fs6.mkdirSync(path6.dirname(path6.resolve(outputPath)), { recursive: true });
16185
+ fs6.writeFileSync(outputPath, json2);
15928
16186
  }
15929
16187
  const githubOutputPath = flags.get("--github-output");
15930
16188
  if (githubOutputPath !== void 0) {
@@ -15937,7 +16195,7 @@ function emitResult(result, scalarOutputs, flags, stdout) {
15937
16195
  }
15938
16196
  return `${name}=${serialized}`;
15939
16197
  });
15940
- fs5.appendFileSync(githubOutputPath, `${outputLines.join("\n")}
16198
+ fs6.appendFileSync(githubOutputPath, `${outputLines.join("\n")}
15941
16199
  `);
15942
16200
  }
15943
16201
  stdout(json2);
@@ -15973,7 +16231,7 @@ async function runReleaseCli(args, dependencies = {}) {
15973
16231
  }
15974
16232
  const validateStarterPaths = validateStarterPathsValue === "true";
15975
16233
  const pathsFile = optionalString(flags, "--paths-file");
15976
- const pathsDocument = pathsFile ? JSON.parse(fs5.readFileSync(pathsFile, "utf8")) : getFirstPartyStarterPaths();
16234
+ const pathsDocument = pathsFile ? JSON.parse(fs6.readFileSync(pathsFile, "utf8")) : getFirstPartyStarterPaths();
15977
16235
  const starterPaths = pathsDocument !== null && typeof pathsDocument === "object" && !Array.isArray(pathsDocument) && "starterPaths" in pathsDocument ? pathsDocument.starterPaths : pathsDocument ?? getFirstPartyStarterPaths();
15978
16236
  if (!Array.isArray(starterPaths) || starterPaths.length === 0 || starterPaths.length > 100 || !starterPaths.every(
15979
16237
  (value) => typeof value === "string" && /^[A-Za-z0-9._/-]+$/.test(value) && !value.startsWith("/") && !value.split("/").includes("..")
@@ -16086,7 +16344,7 @@ async function runReleaseCli(args, dependencies = {}) {
16086
16344
  const buildInfoPath = requiredString(flags, "--build-info");
16087
16345
  let result2;
16088
16346
  try {
16089
- result2 = parseBuildInfo(fs5.readFileSync(buildInfoPath, "utf8"));
16347
+ result2 = parseBuildInfo(fs6.readFileSync(buildInfoPath, "utf8"));
16090
16348
  } catch (error48) {
16091
16349
  throw new ReleaseCliInputError(
16092
16350
  `Invalid CLI build information: ${error48 instanceof Error ? error48.message : String(error48)}`
@@ -16128,7 +16386,7 @@ async function runReleaseCli(args, dependencies = {}) {
16128
16386
  }
16129
16387
  if (command === "verify-published") {
16130
16388
  const archivePath = requiredString(flags, "--archive");
16131
- const archive = fs5.readFileSync(archivePath);
16389
+ const archive = fs6.readFileSync(archivePath);
16132
16390
  const result2 = await verifyPublishedPackage({
16133
16391
  archive,
16134
16392
  registryIntegrity: requiredString(flags, "--registry-integrity"),
@@ -16170,8 +16428,8 @@ async function runReleaseCli(args, dependencies = {}) {
16170
16428
  const buildInfoPath = requiredString(flags, "--build-info");
16171
16429
  const archivePath = requiredString(flags, "--archive");
16172
16430
  const result2 = createValidationManifest({
16173
- buildInfo: parseBuildInfo(fs5.readFileSync(buildInfoPath, "utf8")),
16174
- archiveIntegrity: calculatePackageIntegrity(fs5.readFileSync(archivePath))
16431
+ buildInfo: parseBuildInfo(fs6.readFileSync(buildInfoPath, "utf8")),
16432
+ archiveIntegrity: calculatePackageIntegrity(fs6.readFileSync(archivePath))
16175
16433
  });
16176
16434
  emitResult(
16177
16435
  result2,
@@ -16190,7 +16448,7 @@ async function runReleaseCli(args, dependencies = {}) {
16190
16448
  }
16191
16449
  if (command === "manifest") {
16192
16450
  const buildInfoPath = requiredString(flags, "--build-info");
16193
- const buildInfo = parseBuildInfo(fs5.readFileSync(buildInfoPath, "utf8"));
16451
+ const buildInfo = parseBuildInfo(fs6.readFileSync(buildInfoPath, "utf8"));
16194
16452
  const completionRunId = optionalString(flags, "--completion-run-id");
16195
16453
  const completion = completionRunId !== void 0 ? {
16196
16454
  workflowRunId: completionRunId,
@@ -16228,7 +16486,7 @@ async function runReleaseCli(args, dependencies = {}) {
16228
16486
  if (command === "reconcile") {
16229
16487
  const expectedManifestPath = requiredString(flags, "--expected-manifest");
16230
16488
  const expectedManifest = parseReleaseManifest(
16231
- fs5.readFileSync(expectedManifestPath, "utf8")
16489
+ fs6.readFileSync(expectedManifestPath, "utf8")
16232
16490
  );
16233
16491
  const tagTarget = optionalString(flags, "--tag-target");
16234
16492
  const releaseTag = optionalString(flags, "--release-tag");