@blogic-cz/agent-tools 0.15.5 → 0.15.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blogic-cz/agent-tools",
3
- "version": "0.15.5",
3
+ "version": "0.15.6",
4
4
  "description": "CLI tools for AI coding agent workflows — GitHub, database, Kubernetes, Azure DevOps, logs, sessions, and audit",
5
5
  "keywords": [
6
6
  "agent",
@@ -17,6 +17,7 @@ import { K8sService, K8sServiceLayer } from "./service";
17
17
  import { ConfigService, ConfigServiceLayer, getDefaultEnvironment, getToolConfig } from "#config";
18
18
  import type { K8sConfig } from "#config";
19
19
  import { K8sContextError } from "./errors";
20
+ import { hasKubernetesConfig, selectK8sProfile } from "./profile";
20
21
  import {
21
22
  transformDescribe,
22
23
  transformGenericKubectl,
@@ -60,6 +61,21 @@ const resolveEnv = (
60
61
  });
61
62
  });
62
63
 
64
+ const resolveEnvAndProfile = (
65
+ envOption: Option.Option<string>,
66
+ profileOption: Option.Option<string>,
67
+ config: Parameters<typeof getDefaultEnvironment>[0],
68
+ ) =>
69
+ Effect.gen(function* () {
70
+ const resolvedEnv = yield* resolveEnv(envOption, config);
71
+ const profileName = selectK8sProfile(
72
+ config?.kubernetes,
73
+ Option.getOrUndefined(profileOption),
74
+ resolvedEnv,
75
+ );
76
+ return { env: resolvedEnv, profile: profileName };
77
+ });
78
+
63
79
  type CommonK8sCommandOptions = {
64
80
  readonly env: Option.Option<string>;
65
81
  readonly dryRun: boolean;
@@ -67,26 +83,36 @@ type CommonK8sCommandOptions = {
67
83
  readonly profile: Option.Option<string>;
68
84
  };
69
85
 
86
+ const noKubernetesConfigResult = (): CommandResult => ({
87
+ success: false,
88
+ error: "No Kubernetes configuration found",
89
+ hint: "Add a 'kubernetes' section to agent-tools.json5 with clusterId and namespaces.",
90
+ nextCommand:
91
+ "echo '{ kubernetes: { default: { clusterId: \"my-cluster\" } } }' > agent-tools.json5",
92
+ executionTimeMs: 0,
93
+ });
94
+
70
95
  const executeK8sCommand = (command: string, options: CommonK8sCommandOptions) =>
71
96
  Effect.gen(function* () {
72
97
  const config = yield* ConfigService;
73
- const profileName = Option.getOrUndefined(options.profile);
98
+
99
+ // Check for a missing 'kubernetes' section before resolving --env, so that case still
100
+ // surfaces "add a kubernetes section" instead of an env-resolution error (e.g. prod-safety).
101
+ if (!hasKubernetesConfig(config?.kubernetes)) {
102
+ return noKubernetesConfigResult();
103
+ }
104
+
105
+ const { env: resolvedEnv, profile: profileName } = yield* resolveEnvAndProfile(
106
+ options.env,
107
+ options.profile,
108
+ config,
109
+ );
74
110
  const k8sConfig = getToolConfig<K8sConfig>(config, "kubernetes", profileName);
75
111
 
76
112
  if (!k8sConfig) {
77
- const result: CommandResult = {
78
- success: false,
79
- error: "No Kubernetes configuration found",
80
- hint: "Add a 'kubernetes' section to agent-tools.json5 with clusterId and namespaces.",
81
- nextCommand:
82
- "echo '{ kubernetes: { default: { clusterId: \"my-cluster\" } } }' > agent-tools.json5",
83
- executionTimeMs: 0,
84
- };
85
- return result;
113
+ return noKubernetesConfigResult();
86
114
  }
87
115
 
88
- const resolvedEnv = yield* resolveEnv(options.env, config);
89
-
90
116
  const k8sService = yield* K8sService;
91
117
  const result = yield* k8sService.runKubectl(command, options.dryRun, profileName).pipe(
92
118
  Effect.catchTags({
@@ -190,8 +216,11 @@ const resolveStructuredNamespace = (
190
216
  if (explicitNamespace) return explicitNamespace;
191
217
 
192
218
  const config = yield* ConfigService;
193
- const resolvedEnv = yield* resolveEnv(envOption, config);
194
- const profileName = Option.getOrUndefined(profileOption);
219
+ const { env: resolvedEnv, profile: profileName } = yield* resolveEnvAndProfile(
220
+ envOption,
221
+ profileOption,
222
+ config,
223
+ );
195
224
  const k8sConfig = getToolConfig<K8sConfig>(config, "kubernetes", profileName);
196
225
 
197
226
  if (!k8sConfig) return undefined;
@@ -0,0 +1,22 @@
1
+ // --profile wins if given; else a kubernetes.<env> section (different cluster per env) wins; else undefined (getToolConfig default).
2
+ export function selectK8sProfile(
3
+ kubernetesSection: Record<string, unknown> | undefined,
4
+ explicitProfile: string | undefined,
5
+ resolvedEnv: string,
6
+ ): string | undefined {
7
+ if (explicitProfile) {
8
+ return explicitProfile;
9
+ }
10
+
11
+ if (kubernetesSection && Object.hasOwn(kubernetesSection, resolvedEnv)) {
12
+ return resolvedEnv;
13
+ }
14
+
15
+ return undefined;
16
+ }
17
+
18
+ export function hasKubernetesConfig(
19
+ kubernetesSection: Record<string, unknown> | undefined,
20
+ ): boolean {
21
+ return !!kubernetesSection && Object.keys(kubernetesSection).length > 0;
22
+ }