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.
- package/README.md +109 -6
- package/cli-build-info.json +8 -8
- package/index.js +43866 -40955
- package/onboarding/index.json +1 -1
- package/onboarding/prompts/authenticate/start.md +38 -27
- package/onboarding/prompts/conversion/plan.md +3 -3
- package/onboarding/prompts/credentials/finalize-plan.md +14 -12
- package/onboarding/prompts/credentials/plan.md +21 -21
- package/onboarding/prompts/credentials/settle-credentials.md +18 -11
- package/onboarding/prompts/credentials/write-plan.md +19 -12
- package/onboarding/prompts/fallback/best-effort.md +9 -9
- package/onboarding/prompts/feature/a2ui/implement.md +6 -6
- package/onboarding/prompts/feature/a2ui/proof.md +6 -6
- package/onboarding/prompts/feature/a2ui/start.md +7 -7
- package/onboarding/prompts/feature/channels/implement.md +41 -15
- package/onboarding/prompts/feature/channels/proof.md +12 -10
- package/onboarding/prompts/feature/channels/start.md +13 -12
- package/onboarding/prompts/feature/chat-suggestions/implement.md +6 -6
- package/onboarding/prompts/feature/chat-suggestions/proof.md +6 -6
- package/onboarding/prompts/feature/chat-suggestions/start.md +7 -7
- package/onboarding/prompts/feature/complete.md +19 -1
- package/onboarding/prompts/feature/learning/implement.md +16 -16
- package/onboarding/prompts/feature/learning/proof.md +7 -7
- package/onboarding/prompts/feature/learning/start.md +8 -8
- package/onboarding/prompts/feature/open-generative-ui/implement.md +6 -6
- package/onboarding/prompts/feature/open-generative-ui/proof.md +6 -6
- package/onboarding/prompts/feature/open-generative-ui/start.md +7 -7
- package/onboarding/prompts/feature/realtime-sync/implement.md +7 -7
- package/onboarding/prompts/feature/realtime-sync/proof.md +6 -6
- package/onboarding/prompts/feature/realtime-sync/start.md +6 -6
- package/onboarding/prompts/feature/rich-threads/implement.md +10 -10
- package/onboarding/prompts/feature/rich-threads/proof.md +6 -6
- package/onboarding/prompts/feature/rich-threads/start.md +6 -6
- package/onboarding/prompts/feature/stop.md +36 -2
- package/onboarding/prompts/feature/voice/implement.md +7 -7
- package/onboarding/prompts/feature/voice/proof.md +6 -6
- package/onboarding/prompts/feature/voice/start.md +8 -8
- package/onboarding/prompts/framework/ag2.md +2 -2
- package/onboarding/prompts/framework/agno.md +2 -2
- package/onboarding/prompts/framework/built-in.md +2 -2
- package/onboarding/prompts/framework/claude-sdk-python.md +2 -2
- package/onboarding/prompts/framework/claude-sdk-typescript.md +2 -2
- package/onboarding/prompts/framework/crewai-flows.md +2 -2
- package/onboarding/prompts/framework/deep-agents.md +2 -2
- package/onboarding/prompts/framework/google-adk.md +2 -2
- package/onboarding/prompts/framework/langgraph-fastapi.md +2 -2
- package/onboarding/prompts/framework/langgraph-python.md +2 -2
- package/onboarding/prompts/framework/langgraph-typescript.md +2 -2
- package/onboarding/prompts/framework/llamaindex.md +2 -2
- package/onboarding/prompts/framework/mastra.md +2 -2
- package/onboarding/prompts/framework/ms-agent-dotnet.md +2 -2
- package/onboarding/prompts/framework/ms-agent-harness-dotnet.md +2 -2
- package/onboarding/prompts/framework/ms-agent-python.md +2 -2
- package/onboarding/prompts/framework/pydantic-ai.md +2 -2
- package/onboarding/prompts/framework/strands-python.md +2 -2
- package/onboarding/prompts/framework/strands-typescript.md +2 -2
- package/onboarding/prompts/frontend/angular.md +3 -3
- package/onboarding/prompts/frontend/nextjs.md +3 -3
- package/onboarding/prompts/frontend/plan.md +7 -7
- package/onboarding/prompts/frontend/react-native.md +5 -2
- package/onboarding/prompts/frontend/react-spa.md +5 -2
- package/onboarding/prompts/frontend/vue.md +5 -2
- package/onboarding/prompts/implementation/build-and-validate.md +24 -23
- package/onboarding/prompts/proof/complete.md +8 -8
- package/onboarding/prompts/proof/oss-baseline.md +5 -5
- package/onboarding/prompts/proof/round-trip.md +11 -11
- package/onboarding/prompts/research/gather.md +36 -7
- package/onboarding/prompts/research/merge.md +3 -3
- package/onboarding/prompts/research/preflight.md +4 -4
- package/onboarding/prompts/research/route.md +10 -8
- package/onboarding/prompts/starter/clone.md +97 -26
- package/onboarding/prompts/stopped/run-failed.md +2 -2
- package/onboarding/prompts/subagent/create-plan.md +4 -4
- package/onboarding/prompts/subagent/implement-and-validate.md +26 -6
- package/onboarding/prompts/subagent/inspect-repository.md +2 -2
- package/onboarding/prompts/subagent/prove-oss-baseline.md +2 -2
- package/onboarding/prompts/subagent/prove-round-trip.md +10 -10
- package/onboarding/prompts/unsupported/no-validated-path.md +2 -2
- package/package.json +5 -1
- package/release/release-tool.js +330 -72
package/release/release-tool.js
CHANGED
|
@@ -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
|
|
59
|
-
import * as
|
|
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(
|
|
63
|
+
function copilotKitStarter(path7) {
|
|
64
64
|
return {
|
|
65
65
|
owner: "CopilotKit",
|
|
66
66
|
repo: "CopilotKit",
|
|
67
|
-
path:
|
|
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,
|
|
907
|
-
if (!
|
|
906
|
+
function getElementAtPath(obj, path7) {
|
|
907
|
+
if (!path7)
|
|
908
908
|
return obj;
|
|
909
|
-
return
|
|
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(
|
|
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(
|
|
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,
|
|
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 = [...
|
|
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
|
|
1522
|
-
for (const seg of
|
|
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
|
|
13499
|
-
if (
|
|
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 (
|
|
13504
|
-
const key =
|
|
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
|
|
14430
|
+
for (const path7 of uniquePaths) {
|
|
14431
14431
|
const content = await requestGitHub(
|
|
14432
|
-
`${apiRoot}/contents/${encodeURIComponent(
|
|
14432
|
+
`${apiRoot}/contents/${encodeURIComponent(path7)}?ref=${canonicalCommit}`,
|
|
14433
14433
|
"contents",
|
|
14434
|
-
{ path:
|
|
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 ${
|
|
14446
|
-
{ path:
|
|
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 ${
|
|
14452
|
-
{ path:
|
|
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
|
|
14695
|
+
import * as fs5 from "node:fs";
|
|
14696
14696
|
import * as os2 from "node:os";
|
|
14697
|
-
import * as
|
|
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 ? "
|
|
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
|
|
15270
|
-
import * as
|
|
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
|
-
|
|
15310
|
-
|
|
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
|
|
15313
|
-
|
|
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(
|
|
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 (!
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
15380
|
-
|
|
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 :
|
|
15395
|
-
if (!isWholeRepo && !
|
|
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
|
-
|
|
15661
|
+
fs4.mkdirSync(destinationPath, { recursive: true });
|
|
15404
15662
|
await copyDirectory(sourcePath, destinationPath, isWholeRepo);
|
|
15405
15663
|
} catch (cause) {
|
|
15406
15664
|
if (!destinationExisted) {
|
|
15407
|
-
|
|
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
|
-
|
|
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 (!
|
|
15424
|
-
|
|
15681
|
+
if (!fs4.existsSync(destination)) {
|
|
15682
|
+
fs4.mkdirSync(destination, { recursive: true });
|
|
15425
15683
|
}
|
|
15426
|
-
const entries =
|
|
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 =
|
|
15432
|
-
const destPath =
|
|
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
|
-
|
|
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 =
|
|
15495
|
-
|
|
15752
|
+
const temporaryRoot = fs5.mkdtempSync(
|
|
15753
|
+
path5.join(os2.tmpdir(), `copilotkit-smoke-${input.framework}-`)
|
|
15496
15754
|
);
|
|
15497
|
-
const projectDir =
|
|
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 =
|
|
15539
|
-
const program =
|
|
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 =
|
|
15810
|
+
const entries = fs5.readdirSync(projectDir);
|
|
15553
15811
|
return entries.join("\n");
|
|
15554
15812
|
} finally {
|
|
15555
|
-
|
|
15813
|
+
fs5.rmSync(temporaryRoot, { recursive: true, force: true });
|
|
15556
15814
|
}
|
|
15557
15815
|
}
|
|
15558
15816
|
async function executeStarterSmokeChild(command) {
|
|
15559
|
-
return new Promise((
|
|
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
|
-
|
|
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
|
-
|
|
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 === "-" ?
|
|
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
|
-
|
|
15927
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
16174
|
-
archiveIntegrity: calculatePackageIntegrity(
|
|
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(
|
|
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
|
-
|
|
16489
|
+
fs6.readFileSync(expectedManifestPath, "utf8")
|
|
16232
16490
|
);
|
|
16233
16491
|
const tagTarget = optionalString(flags, "--tag-target");
|
|
16234
16492
|
const releaseTag = optionalString(flags, "--release-tag");
|