@agent-native/core 0.51.9 → 0.51.11

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.
@@ -1889,6 +1889,10 @@ A few recap-specific authoring rules the registry table cannot encode:
1889
1889
  shared optional \`summary\` / \`editable\` envelope; give a block a heading by
1890
1890
  placing a \`rich-text\` block with a Markdown \`###\` heading directly above it
1891
1891
  (blocks no longer take a \`title\`).
1892
+ - Every capitalized block component must be self-closing (\`<RichText ... />\`) or
1893
+ explicitly closed around children (\`<RichText ...>...</RichText>\`). Never
1894
+ leave a bare opening tag like \`<RichText ...>\` in a paragraph; MDX treats it
1895
+ as unclosed JSX and import fails before the recap can render.
1892
1896
  - \`Endpoint\`: prose \`description\` is the MDX **children** (body between the
1893
1897
  tags), not an attribute; for a WebSocket upgrade use \`method="GET"\`. Each
1894
1898
  request/response \`example\` is a JSON **string** (the renderer parses it into
@@ -2635,12 +2639,19 @@ function clientPromptOptions() {
2635
2639
  hint: CLIENT_HINTS[client],
2636
2640
  }));
2637
2641
  }
2638
- // For now the interactive installer offers only the two plan skills, each as
2639
- // an independently selectable entry (uncheck one to install just the other).
2640
- // The other built-in skills stay installable via `agent-native skills add
2641
- // <name>` but are hidden from the default checklist. The values are the real
2642
- // slash-command names so users see exactly what they are installing.
2643
- const PLAN_SKILL_PROMPT_OPTIONS = [
2642
+ const DEFAULT_PUBLIC_SKILLS_SOURCE = "BuilderIO/skills";
2643
+ const PUBLIC_SKILL_TARGET_PREFIX = "public-skills:";
2644
+ const BUILT_IN_SKILL_PROMPT_OPTIONS = [
2645
+ {
2646
+ value: "assets",
2647
+ label: "assets",
2648
+ hint: BUILT_IN_APP_SKILLS.assets.manifest.description,
2649
+ },
2650
+ {
2651
+ value: "design-exploration",
2652
+ label: "design-exploration",
2653
+ hint: BUILT_IN_APP_SKILLS.design.manifest.description,
2654
+ },
2644
2655
  {
2645
2656
  value: "visual-plan",
2646
2657
  label: "visual-plan",
@@ -2651,9 +2662,58 @@ const PLAN_SKILL_PROMPT_OPTIONS = [
2651
2662
  label: "visual-recap",
2652
2663
  hint: "Interactive visual recap that maps PRs/diffs with diagrams, annotated diffs, API/schema summaries, and review notes.",
2653
2664
  },
2665
+ {
2666
+ value: "context-xray",
2667
+ label: "context-xray",
2668
+ hint: BUILT_IN_APP_SKILLS["context-xray"].manifest.description,
2669
+ },
2654
2670
  ];
2655
- function skillPromptOptions() {
2656
- return PLAN_SKILL_PROMPT_OPTIONS;
2671
+ const DEFAULT_SKILL_PROMPT_TARGETS = ["visual-plan", "visual-recap"];
2672
+ function publicSkillEntries(options) {
2673
+ if (options.catalogMode !== "all")
2674
+ return [];
2675
+ const seen = new Set();
2676
+ return (options.publicSkillEntries ?? [])
2677
+ .map((entry) => ({
2678
+ name: entry.name.trim().toLowerCase(),
2679
+ description: entry.description,
2680
+ }))
2681
+ .filter((entry) => {
2682
+ if (!entry.name || isKnownSkill(entry.name) || seen.has(entry.name)) {
2683
+ return false;
2684
+ }
2685
+ seen.add(entry.name);
2686
+ return true;
2687
+ })
2688
+ .sort((a, b) => a.name.localeCompare(b.name));
2689
+ }
2690
+ function publicSkillNames(options) {
2691
+ return new Set(publicSkillEntries(options).map((entry) => entry.name));
2692
+ }
2693
+ function publicSkillPromptOptions(options) {
2694
+ return publicSkillEntries(options).map((entry) => ({
2695
+ value: entry.name,
2696
+ label: entry.name,
2697
+ hint: entry.description ?? "Public skill from the BuilderIO skills catalog.",
2698
+ }));
2699
+ }
2700
+ function skillPromptOptions(options = {}) {
2701
+ return [
2702
+ ...BUILT_IN_SKILL_PROMPT_OPTIONS,
2703
+ ...publicSkillPromptOptions(options),
2704
+ ];
2705
+ }
2706
+ function publicSkillSelectionTarget(skillNames) {
2707
+ return `${PUBLIC_SKILL_TARGET_PREFIX}${skillNames.join(",")}`;
2708
+ }
2709
+ function publicSkillSelectionNames(target) {
2710
+ if (!target.startsWith(PUBLIC_SKILL_TARGET_PREFIX))
2711
+ return null;
2712
+ return target
2713
+ .slice(PUBLIC_SKILL_TARGET_PREFIX.length)
2714
+ .split(",")
2715
+ .map((name) => name.trim().toLowerCase())
2716
+ .filter(Boolean);
2657
2717
  }
2658
2718
  function prVisualRecapWorkflowPath(baseDir) {
2659
2719
  return path.join(baseDir, ".github", "workflows", "pr-visual-recap.yml");
@@ -2783,6 +2843,18 @@ async function promptForPlanMcpUrl() {
2783
2843
  }
2784
2844
  return String(result).trim();
2785
2845
  }
2846
+ async function promptForUpdateInstructions() {
2847
+ const clack = await import("@clack/prompts");
2848
+ const result = await clack.confirm({
2849
+ message: "Add managed AGENTS.md / CLAUDE.md instructions for always-on skill behavior?",
2850
+ initialValue: true,
2851
+ });
2852
+ if (clack.isCancel(result)) {
2853
+ clack.cancel("Skipped managed instruction updates.");
2854
+ return null;
2855
+ }
2856
+ return Boolean(result);
2857
+ }
2786
2858
  async function promptForSkills(context) {
2787
2859
  const clack = await import("@clack/prompts");
2788
2860
  const result = await clack.multiselect({
@@ -2844,12 +2916,66 @@ function targetIncludesPlans(target) {
2844
2916
  function targetsIncludePlans(targets) {
2845
2917
  return targets.some(targetIncludesPlans);
2846
2918
  }
2919
+ function planSkillNamesSelected(skillNames) {
2920
+ return Boolean(skillNames?.some((name) => normalizeKnownSkillTarget(name) === "visual-plans"));
2921
+ }
2922
+ function recapSkillNamesSelected(skillNames) {
2923
+ return Boolean(skillNames?.some((name) => {
2924
+ const normalized = name.trim().toLowerCase();
2925
+ return (normalized === "visual-recap" ||
2926
+ normalized === "visual-recaps" ||
2927
+ normalizeKnownSkillTarget(normalized) === "visual-plans");
2928
+ }));
2929
+ }
2930
+ function resolveSelectedSkillTargets(selected, options) {
2931
+ const publicNames = publicSkillNames(options);
2932
+ const builtInSelections = [];
2933
+ const publicSelections = [];
2934
+ for (const raw of selected) {
2935
+ const skill = raw.trim().toLowerCase();
2936
+ if (!skill)
2937
+ continue;
2938
+ if (isKnownSkill(skill)) {
2939
+ builtInSelections.push(skill);
2940
+ continue;
2941
+ }
2942
+ if (publicNames.has(skill)) {
2943
+ publicSelections.push(skill);
2944
+ continue;
2945
+ }
2946
+ throw new Error(`Unknown skill: ${raw}. Run "npx @agent-native/core@latest skills list".`);
2947
+ }
2948
+ const out = [];
2949
+ const planSubskills = ["visual-plan", "visual-recap"];
2950
+ const selectedPlanSubskills = planSubskills.filter((skill) => builtInSelections.includes(skill));
2951
+ if (selectedPlanSubskills.length === planSubskills.length) {
2952
+ out.push("visual-plans");
2953
+ }
2954
+ else {
2955
+ out.push(...selectedPlanSubskills);
2956
+ }
2957
+ out.push(...builtInSelections.filter((skill) => !planSubskills.includes(skill) && !out.includes(skill)));
2958
+ if (publicSelections.length > 0) {
2959
+ out.push(publicSkillSelectionTarget([...new Set(publicSelections)]));
2960
+ }
2961
+ return out;
2962
+ }
2847
2963
  async function resolveSkillTargets(parsed, options) {
2964
+ if (!parsed.target && parsed.plainSkillNames?.length) {
2965
+ return resolveSelectedSkillTargets(parsed.plainSkillNames, options);
2966
+ }
2848
2967
  if (parsed.target || !shouldPrompt(parsed, options)) {
2849
- return [parsed.target ?? "assets"];
2968
+ const target = parsed.target ?? "assets";
2969
+ if (!parsed.target)
2970
+ return [target];
2971
+ const normalizedTarget = target.trim().toLowerCase();
2972
+ if (publicSkillNames(options).has(normalizedTarget)) {
2973
+ return [publicSkillSelectionTarget([normalizedTarget])];
2974
+ }
2975
+ return [target];
2850
2976
  }
2851
2977
  const prompt = options.promptSkills ?? promptForSkills;
2852
- const promptOptions = skillPromptOptions();
2978
+ const promptOptions = skillPromptOptions(options);
2853
2979
  // The interactive multiselect skill picker is about to be shown (no --skill /
2854
2980
  // target passed and we are interactive) — record the funnel "prompted" step.
2855
2981
  options.telemetry?.track("skills_cli skills prompted", {
@@ -2857,22 +2983,12 @@ async function resolveSkillTargets(parsed, options) {
2857
2983
  available: promptOptions.map((option) => option.value).join(","),
2858
2984
  });
2859
2985
  const selected = await prompt({
2860
- initialTargets: ["visual-plan", "visual-recap"],
2986
+ initialTargets: DEFAULT_SKILL_PROMPT_TARGETS,
2861
2987
  options: promptOptions,
2862
2988
  });
2863
2989
  if (!selected || selected.length === 0)
2864
2990
  return null;
2865
- // Both plan skills share one MCP connector, so when both are selected install
2866
- // them through the bundle target — that registers/authenticates the connector
2867
- // once instead of twice.
2868
- const planSubskills = ["visual-plan", "visual-recap"];
2869
- if (planSubskills.every((skill) => selected.includes(skill))) {
2870
- return [
2871
- "visual-plans",
2872
- ...selected.filter((s) => !planSubskills.includes(s)),
2873
- ];
2874
- }
2875
- return selected;
2991
+ return resolveSelectedSkillTargets(selected, options);
2876
2992
  }
2877
2993
  export function parseSkillsArgs(argv) {
2878
2994
  const first = argv[0];
@@ -2928,6 +3044,14 @@ export function parseSkillsArgs(argv) {
2928
3044
  out.client = value;
2929
3045
  out.clientExplicit = true;
2930
3046
  }
3047
+ else if ((value = eat("--agent")) !== undefined) {
3048
+ out.client = value;
3049
+ out.clientExplicit = true;
3050
+ }
3051
+ else if ((value = eat("-a")) !== undefined) {
3052
+ out.client = value;
3053
+ out.clientExplicit = true;
3054
+ }
2931
3055
  else if ((value = eat("--skill")) !== undefined) {
2932
3056
  out.plainSkillNames = [...(out.plainSkillNames ?? []), value];
2933
3057
  }
@@ -2938,6 +3062,8 @@ export function parseSkillsArgs(argv) {
2938
3062
  out.scope = value;
2939
3063
  out.scopeExplicit = true;
2940
3064
  }
3065
+ else if ((value = eat("--cwd")) !== undefined)
3066
+ out.baseDir = value;
2941
3067
  else if ((value = eat("--mcp-url")) !== undefined)
2942
3068
  out.mcpUrl = value;
2943
3069
  else if ((value = eat("--mode")) !== undefined)
@@ -2954,6 +3080,18 @@ export function parseSkillsArgs(argv) {
2954
3080
  out.dryRun = true;
2955
3081
  else if (arg === "--json")
2956
3082
  out.printJson = true;
3083
+ else if (arg === "-g" || arg === "--global") {
3084
+ out.scope = "user";
3085
+ out.scopeExplicit = true;
3086
+ }
3087
+ else if (arg === "--project") {
3088
+ out.scope = "project";
3089
+ out.scopeExplicit = true;
3090
+ }
3091
+ else if (arg === "--copy") {
3092
+ // Compatibility with @agent-native/skills. Core always copies skill
3093
+ // instructions instead of linking to the source repo.
3094
+ }
2957
3095
  else if (arg === "--mcp-only")
2958
3096
  out.instructions = false;
2959
3097
  else if (arg === "--instructions-only" || arg === "--no-mcp")
@@ -3230,6 +3368,12 @@ function agentNativeSkillsInstallArgs(parsed, target, clients) {
3230
3368
  args.push("--with-github-action");
3231
3369
  if (parsed.force)
3232
3370
  args.push("--force");
3371
+ if (parsed.planMode)
3372
+ args.push("--mode", parsed.planMode);
3373
+ if (parsed.mcpUrl)
3374
+ args.push("--mcp-url", parsed.mcpUrl);
3375
+ if (!parsed.mcp)
3376
+ args.push("--no-mcp");
3233
3377
  if (!parsed.connect)
3234
3378
  args.push("--no-connect");
3235
3379
  for (const skill of parsed.plainSkillNames ?? []) {
@@ -3241,6 +3385,8 @@ function agentNativeSkillsInstallArgs(parsed, target, clients) {
3241
3385
  args.push("--no-update-instructions");
3242
3386
  if (parsed.yes)
3243
3387
  args.push("--yes");
3388
+ if (parsed.dryRun)
3389
+ args.push("--dry-run");
3244
3390
  return args;
3245
3391
  }
3246
3392
  async function addPlainSkillRepo(parsed, options) {
@@ -3248,11 +3394,12 @@ async function addPlainSkillRepo(parsed, options) {
3248
3394
  if (!parsed.instructions && parsed.mcp) {
3249
3395
  throw new Error("Plain skill repositories only install skill instructions. Run without --mcp-only.");
3250
3396
  }
3251
- if (parsed.mcpUrl) {
3397
+ if (parsed.mcpUrl && !planSkillNamesSelected(parsed.plainSkillNames)) {
3252
3398
  throw new Error("--mcp-url only applies to app-backed Agent Native skills.");
3253
3399
  }
3254
3400
  const clients = parsed.clients ?? resolveClients(parsed.client);
3255
3401
  const skillsAgents = skillsAgentsForClients(clients);
3402
+ const selectedSkillNames = parsed.plainSkillNames ?? [];
3256
3403
  if (skillsAgents.length === 0) {
3257
3404
  throw new Error("Plain skill repositories can only install instructions for Codex or Claude Code clients.");
3258
3405
  }
@@ -3265,15 +3412,17 @@ async function addPlainSkillRepo(parsed, options) {
3265
3412
  throw new Error(`npx @agent-native/skills@latest add exited with ${code}.`);
3266
3413
  }
3267
3414
  options.telemetry?.track("skills_cli install completed", {
3268
- skills: target,
3415
+ skills: selectedSkillNames.length ? selectedSkillNames.join(",") : target,
3269
3416
  clients: clients.join(","),
3270
3417
  scope: parsed.scope,
3271
3418
  dryRun: Boolean(parsed.dryRun),
3272
3419
  });
3273
3420
  return {
3274
3421
  id: target,
3275
- displayName: target,
3276
- skillNames: [],
3422
+ displayName: selectedSkillNames.length
3423
+ ? selectedSkillNames.join(", ")
3424
+ : target,
3425
+ skillNames: selectedSkillNames,
3277
3426
  skillsAgents,
3278
3427
  mcpUrl: "",
3279
3428
  mcpClients: [],
@@ -3356,6 +3505,14 @@ async function connectAfterEnsure(installTarget, clients, parsed, options) {
3356
3505
  }
3357
3506
  export async function addAgentNativeSkill(parsed, options = {}) {
3358
3507
  const target = parsed.target ?? "assets";
3508
+ const publicSelection = publicSkillSelectionNames(target);
3509
+ if (publicSelection) {
3510
+ return addPlainSkillRepo({
3511
+ ...parsed,
3512
+ target: options.publicSkillSource ?? DEFAULT_PUBLIC_SKILLS_SOURCE,
3513
+ plainSkillNames: publicSelection,
3514
+ }, options);
3515
+ }
3359
3516
  const knownTarget = normalizeKnownSkillTarget(target);
3360
3517
  const planMode = knownTarget === "visual-plans"
3361
3518
  ? (parsed.planMode ?? (parsed.mcpUrl ? "self-hosted" : "hosted"))
@@ -3651,15 +3808,29 @@ export async function addAgentNativeSkill(parsed, options = {}) {
3651
3808
  installTarget.cleanup?.();
3652
3809
  }
3653
3810
  }
3654
- function listSkills() {
3655
- return Object.values(BUILT_IN_APP_SKILLS).map((entry) => ({
3656
- id: entry.manifest.id,
3657
- aliases: BUILT_IN_APP_SKILL_DISPLAY_ALIASES[entry.manifest.id] ?? [],
3658
- name: entry.manifest.displayName,
3659
- description: entry.manifest.description,
3660
- mcpUrl: isLocalOnlyBuiltInSkill(entry) ? "" : entry.manifest.hosted.mcpUrl,
3661
- local: isLocalOnlyBuiltInSkill(entry),
3662
- }));
3811
+ function listSkills(options = {}) {
3812
+ return [
3813
+ ...Object.values(BUILT_IN_APP_SKILLS).map((entry) => ({
3814
+ id: entry.manifest.id,
3815
+ aliases: BUILT_IN_APP_SKILL_DISPLAY_ALIASES[entry.manifest.id] ?? [],
3816
+ name: entry.manifest.displayName,
3817
+ description: entry.manifest.description,
3818
+ mcpUrl: isLocalOnlyBuiltInSkill(entry)
3819
+ ? ""
3820
+ : entry.manifest.hosted.mcpUrl,
3821
+ local: isLocalOnlyBuiltInSkill(entry),
3822
+ source: "agent-native",
3823
+ })),
3824
+ ...publicSkillEntries(options).map((entry) => ({
3825
+ id: entry.name,
3826
+ aliases: [],
3827
+ name: entry.name,
3828
+ description: entry.description ?? "Public skill from the BuilderIO skills catalog.",
3829
+ mcpUrl: "",
3830
+ local: true,
3831
+ source: options.publicSkillSource ?? DEFAULT_PUBLIC_SKILLS_SOURCE,
3832
+ })),
3833
+ ];
3663
3834
  }
3664
3835
  function skillStateJson(state) {
3665
3836
  return {
@@ -3692,6 +3863,39 @@ function planModeSummary(mode) {
3692
3863
  return "Self-hosted/custom Plan app";
3693
3864
  return "Hosted Plans - shareable links and comments";
3694
3865
  }
3866
+ function instructionContentForSkill(skillName) {
3867
+ if (skillName === "quick-recap") {
3868
+ return "When writing final response status indicators, use the /quick-recap skill always.";
3869
+ }
3870
+ if (skillName === "efficient-fable") {
3871
+ return "When operating as Claude Fable, use the /efficient-fable skill always.";
3872
+ }
3873
+ if (skillName === "efficient-frontier") {
3874
+ return "When using a high-cost frontier model for codebase-heavy work, use the /efficient-frontier skill always.";
3875
+ }
3876
+ if (skillName === "stay-within-limits") {
3877
+ return "When long-running or parallel work needs usage-limit checks, use the /stay-within-limits skill always.";
3878
+ }
3879
+ if (skillName === "visual-plan") {
3880
+ return "When work needs an interactive visual plan before implementation, use the /visual-plan skill always.";
3881
+ }
3882
+ if (skillName === "visual-recap") {
3883
+ return "When a PR, branch, commit, or diff needs an interactive visual recap, use the /visual-recap skill always.";
3884
+ }
3885
+ return null;
3886
+ }
3887
+ function selectedPlainSkillNamesForInstructionPrompt(targets, parsed) {
3888
+ const names = new Set(parsed.plainSkillNames ?? []);
3889
+ for (const target of targets) {
3890
+ for (const name of publicSkillSelectionNames(target) ?? []) {
3891
+ names.add(name);
3892
+ }
3893
+ }
3894
+ return [...names];
3895
+ }
3896
+ function hasManagedInstructionBlock(skillNames) {
3897
+ return skillNames.some((name) => Boolean(instructionContentForSkill(name)));
3898
+ }
3695
3899
  function runSkillsStatusOrUpdate(parsed, options, update) {
3696
3900
  const before = collectSkillInstallStates(parsed, options);
3697
3901
  const changed = update ? updateSkillInstallStates(before, parsed.dryRun) : [];
@@ -3748,6 +3952,9 @@ function readCliVersion() {
3748
3952
  }
3749
3953
  export async function runSkills(argv, options = {}) {
3750
3954
  const parsed = parseSkillsArgs(argv);
3955
+ if (parsed.baseDir) {
3956
+ options = { ...options, baseDir: path.resolve(parsed.baseDir) };
3957
+ }
3751
3958
  const log = parsed.printJson
3752
3959
  ? undefined
3753
3960
  : (message) => process.stdout.write(`${message}\n`);
@@ -3760,6 +3967,7 @@ export async function runSkills(argv, options = {}) {
3760
3967
  // `npx @agent-native/skills@latest add …`; this env guard tells that child process
3761
3968
  // to run its OWN headless installer instead of bouncing back into core,
3762
3969
  // which would otherwise be an infinite skills → core → skills loop.
3970
+ const previousDirect = process.env.AGENT_NATIVE_SKILLS_DIRECT;
3763
3971
  process.env.AGENT_NATIVE_SKILLS_DIRECT = "1";
3764
3972
  // Best-effort install-funnel telemetry. Created once per run and flushed in a
3765
3973
  // finally so events send on success, error, and cancellation — the CLI is
@@ -3776,7 +3984,7 @@ export async function runSkills(argv, options = {}) {
3776
3984
  try {
3777
3985
  telemetry.track("skills_cli started");
3778
3986
  if (parsed.command === "list") {
3779
- const skills = listSkills();
3987
+ const skills = listSkills(optionsWithTelemetry);
3780
3988
  telemetry.track("skills_cli skills listed", {
3781
3989
  availableCount: skills.length,
3782
3990
  available: skills.map((skill) => skill.id).join(","),
@@ -3811,10 +4019,11 @@ export async function runSkills(argv, options = {}) {
3811
4019
  // Best-effort "took everything offered" signal: compare against the
3812
4020
  // interactive picker's option count (the plan sub-skills collapse into a
3813
4021
  // single bundle target, so this is approximate, like the standalone CLI).
3814
- selectedAll: targets.length === skillPromptOptions().length,
4022
+ selectedAll: targets.length === skillPromptOptions(options).length,
3815
4023
  preselected,
3816
4024
  });
3817
- const includesPlans = targetsIncludePlans(targets);
4025
+ const includesPlans = targetsIncludePlans(targets) ||
4026
+ planSkillNamesSelected(parsed.plainSkillNames);
3818
4027
  if (parsed.planMode && !includesPlans) {
3819
4028
  throw new Error("--mode only applies to visual-plan / visual-recap.");
3820
4029
  }
@@ -3874,6 +4083,20 @@ export async function runSkills(argv, options = {}) {
3874
4083
  parsed.scope = scope;
3875
4084
  }
3876
4085
  telemetry.track("skills_cli scope selected", { scope: parsed.scope });
4086
+ const instructionSkillNames = selectedPlainSkillNamesForInstructionPrompt(targets, parsed);
4087
+ if (parsed.updateInstructions === undefined &&
4088
+ hasManagedInstructionBlock(instructionSkillNames) &&
4089
+ shouldPrompt(parsed, options)) {
4090
+ const prompt = options.promptUpdateInstructions ?? promptForUpdateInstructions;
4091
+ const choice = await prompt();
4092
+ if (choice === null) {
4093
+ telemetry.track("skills_cli cancelled", {
4094
+ step: "managed-instructions",
4095
+ });
4096
+ return;
4097
+ }
4098
+ parsed.updateInstructions = choice === true;
4099
+ }
3877
4100
  // Decide the optional PR Visual Recap GitHub Action UP FRONT — before any
3878
4101
  // install or MCP registration — so every prompt is answered before we touch
3879
4102
  // disk. The choice is threaded into each install via `withGithubAction` +
@@ -3884,7 +4107,7 @@ export async function runSkills(argv, options = {}) {
3884
4107
  return false;
3885
4108
  const only = builtInOnlySkillNames(target);
3886
4109
  return !only || only.includes("visual-recap");
3887
- });
4110
+ }) || recapSkillNamesSelected(parsed.plainSkillNames);
3888
4111
  if (anyRecapTarget &&
3889
4112
  !parsed.withGithubAction &&
3890
4113
  !fs.existsSync(prVisualRecapWorkflowPath(recapBaseDir)) &&
@@ -4028,6 +4251,12 @@ export async function runSkills(argv, options = {}) {
4028
4251
  }
4029
4252
  finally {
4030
4253
  await telemetry.flush();
4254
+ if (previousDirect === undefined) {
4255
+ delete process.env.AGENT_NATIVE_SKILLS_DIRECT;
4256
+ }
4257
+ else {
4258
+ process.env.AGENT_NATIVE_SKILLS_DIRECT = previousDirect;
4259
+ }
4031
4260
  }
4032
4261
  }
4033
4262
  //# sourceMappingURL=skills.js.map