@kalphq/cli 0.0.0-dev-20260512203604 → 0.0.0-dev-20260513001041

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.
@@ -4,60 +4,25 @@ import {
4
4
  } from "./chunk-TNKYKA7N.js";
5
5
  import {
6
6
  ensureStudioSecrets,
7
+ getRequiredSecretForProvider,
8
+ loadProjectConfig,
7
9
  materializeRuntime,
10
+ readDotEnv,
8
11
  readProjectState,
12
+ resolveIdentityAuthRequirements,
13
+ resolveProviderFromConfig,
14
+ resolveRuntimeIdentityConfig,
9
15
  writeProjectState
10
- } from "./chunk-WMQSBT64.js";
16
+ } from "./chunk-YMEEYCMI.js";
11
17
  import {
12
18
  requireAuth
13
19
  } from "./chunk-5RODADXW.js";
14
20
 
15
21
  // src/utils/deploy.ts
16
- import { readFile as readFile2, writeFile } from "fs/promises";
22
+ import { readFile, writeFile } from "fs/promises";
17
23
  import { createHash } from "crypto";
18
-
19
- // src/utils/ai.ts
20
- import { access, readFile } from "fs/promises";
21
- import { constants } from "fs";
22
- import { join } from "path";
23
- import { createJiti } from "jiti";
24
- var PROVIDER_SECRET_MAP = {
25
- openai: "OPENAI_API_KEY",
26
- anthropic: "ANTHROPIC_API_KEY",
27
- openrouter: "OPENROUTER_API_KEY",
28
- custom: "CUSTOM_AI_API_KEY"
29
- };
30
- function parseEnv(content) {
31
- const env = {};
32
- for (const raw of content.split(/\r?\n/g)) {
33
- const line = raw.trim();
34
- if (!line || line.startsWith("#")) continue;
35
- const idx = line.indexOf("=");
36
- if (idx <= 0) continue;
37
- env[line.slice(0, idx).trim()] = line.slice(idx + 1);
38
- }
39
- return env;
40
- }
41
- async function resolveProviderFromConfig(cwd) {
42
- const configPath = join(cwd, "kalp.config.ts");
43
- await access(configPath, constants.F_OK);
44
- const jiti = createJiti(cwd, { interopDefault: true });
45
- const config = await jiti.import(configPath);
46
- const provider = config?.default?.ai?.provider ?? config?.ai?.provider ?? "openai";
47
- return provider;
48
- }
49
- async function readDotEnv(cwd) {
50
- const envPath = join(cwd, ".env");
51
- const content = await readFile(envPath, "utf-8").catch(() => "");
52
- return parseEnv(content);
53
- }
54
- function getRequiredSecretForProvider(provider) {
55
- return PROVIDER_SECRET_MAP[provider];
56
- }
57
-
58
- // src/utils/deploy.ts
59
24
  async function readWranglerConfig(configPath) {
60
- const text = await readFile2(configPath, "utf-8");
25
+ const text = await readFile(configPath, "utf-8");
61
26
  return JSON.parse(text);
62
27
  }
63
28
  async function writeWranglerConfig(configPath, config) {
@@ -95,8 +60,12 @@ function isNamespaceAlreadyExistsError(output) {
95
60
  }
96
61
  async function runInitialDeploy(cwd) {
97
62
  const auth = await requireAuth();
63
+ const loadedConfig = await loadProjectConfig(cwd);
64
+ const identityConfig = resolveRuntimeIdentityConfig(loadedConfig.raw);
65
+ const identitySecretRequirements = resolveIdentityAuthRequirements(identityConfig);
98
66
  const aiProvider = await resolveProviderFromConfig(cwd);
99
67
  const requiredProviderSecret = getRequiredSecretForProvider(aiProvider);
68
+ const secrets = await ensureStudioSecrets(cwd);
100
69
  const envMap = await readDotEnv(cwd);
101
70
  const providerSecretValue = envMap[requiredProviderSecret]?.trim();
102
71
  if (!providerSecretValue) {
@@ -104,7 +73,15 @@ async function runInitialDeploy(cwd) {
104
73
  `Missing required secret ${requiredProviderSecret} for provider "${aiProvider}". Add it to .env before deploy.`
105
74
  );
106
75
  }
107
- const secrets = await ensureStudioSecrets(cwd);
76
+ const resolvedIdentitySecrets = identitySecretRequirements.map((requirement) => {
77
+ const value = envMap[requirement.envKey]?.trim();
78
+ if (!value) {
79
+ throw new Error(
80
+ `Missing required secret ${requirement.envKey} for ${requirement.reason}. Add it to .env before deploy.`
81
+ );
82
+ }
83
+ return { name: requirement.envKey, value };
84
+ });
108
85
  const runtimeProvider = resolveProvider();
109
86
  const runtime = await materializeRuntime(cwd);
110
87
  let secretSyncFailed = false;
@@ -112,9 +89,15 @@ async function runInitialDeploy(cwd) {
112
89
  ["KALP_SECRET_KEY", secrets.key],
113
90
  ["KALP_STUDIO_PASSWORD", secrets.studioPassword],
114
91
  ["KALP_STUDIO_ADMIN_USER", secrets.studioAdminUser],
115
- [requiredProviderSecret, providerSecretValue]
92
+ ["KALP_SERVICE_KEY", secrets.serviceKey],
93
+ [requiredProviderSecret, providerSecretValue],
94
+ ...resolvedIdentitySecrets.map((item) => [item.name, item.value])
116
95
  ];
96
+ const dedupedSecrets = /* @__PURE__ */ new Map();
117
97
  for (const [name, value] of secretEntries) {
98
+ dedupedSecrets.set(name, value);
99
+ }
100
+ for (const [name, value] of dedupedSecrets.entries()) {
118
101
  try {
119
102
  await runtimeProvider.putSecret({
120
103
  cwd,
@@ -130,14 +113,6 @@ async function runInitialDeploy(cwd) {
130
113
  await ensureKvNamespaceBindingId(cwd, runtime.wranglerConfigPath).catch(
131
114
  () => null
132
115
  );
133
- const deployArgs = secretSyncFailed ? [
134
- "wrangler",
135
- "deploy",
136
- "--config",
137
- runtime.wranglerConfigPath,
138
- "--secrets-file",
139
- ".env"
140
- ] : ["wrangler", "deploy", "--config", runtime.wranglerConfigPath];
141
116
  let deploy = await runtimeProvider.deployRuntime({
142
117
  cwd,
143
118
  configPath: runtime.wranglerConfigPath,
@@ -161,11 +136,14 @@ async function runInitialDeploy(cwd) {
161
136
  const existingState = await readProjectState(cwd);
162
137
  const credentialsFingerprint = createHash("sha256").update(`${secrets.studioAdminUser}:${secrets.studioPassword}`).digest("hex");
163
138
  const credentialsChanged = existingState?.studioCredentialsFingerprint !== credentialsFingerprint;
139
+ const serviceKeyFingerprint = createHash("sha256").update(secrets.serviceKey).digest("hex");
140
+ const serviceKeyChanged = existingState?.serviceKeyFingerprint !== serviceKeyFingerprint;
164
141
  await writeProjectState(cwd, {
165
142
  workerUrl,
166
143
  deployedAt: (/* @__PURE__ */ new Date()).toISOString(),
167
144
  accountId: auth.accountId,
168
145
  studioCredentialsFingerprint: credentialsFingerprint,
146
+ serviceKeyFingerprint,
169
147
  agents: existingState?.agents ?? {}
170
148
  });
171
149
  return {
@@ -174,11 +152,13 @@ async function runInitialDeploy(cwd) {
174
152
  accountId: auth.accountId,
175
153
  studioAdminUser: secrets.studioAdminUser,
176
154
  studioPassword: secrets.studioPassword,
177
- credentialsChanged
155
+ serviceKey: secrets.serviceKey,
156
+ credentialsChanged,
157
+ serviceKeyChanged
178
158
  };
179
159
  }
180
160
 
181
161
  export {
182
162
  runInitialDeploy
183
163
  };
184
- //# sourceMappingURL=chunk-6WQW3UVW.js.map
164
+ //# sourceMappingURL=chunk-YG64BYWB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/deploy.ts"],"sourcesContent":["import { readFile, writeFile } from \"node:fs/promises\";\nimport { createHash } from \"node:crypto\";\nimport { requireAuth } from \"@/utils/auth\";\nimport { ensureStudioSecrets } from \"@/utils/secret\";\nimport { readProjectState, writeProjectState } from \"@/utils/project-state\";\nimport { materializeRuntime } from \"@/utils/runtime\";\nimport {\n getRequiredSecretForProvider,\n readDotEnv,\n resolveProviderFromConfig,\n} from \"@/utils/ai\";\nimport {\n loadProjectConfig,\n resolveIdentityAuthRequirements,\n resolveRuntimeIdentityConfig,\n} from \"@/utils/project-config\";\nimport { resolveProvider } from \"@/utils/providers\";\n\ninterface RuntimeWranglerConfig {\n name?: string;\n kv_namespaces?: Array<{ binding: string; id?: string }>;\n}\n\ninterface KvNamespaceInfo {\n id: string;\n title: string;\n}\n\nasync function readWranglerConfig(\n configPath: string,\n): Promise<RuntimeWranglerConfig> {\n const text = await readFile(configPath, \"utf-8\");\n return JSON.parse(text) as RuntimeWranglerConfig;\n}\n\nasync function writeWranglerConfig(\n configPath: string,\n config: RuntimeWranglerConfig,\n): Promise<void> {\n await writeFile(configPath, `${JSON.stringify(config, null, 2)}\\n`, \"utf-8\");\n}\n\nfunction deriveKvNamespaceTitle(workerName: string, binding: string): string {\n return `${workerName}-${binding.toLowerCase().replace(/_/g, \"-\")}`;\n}\n\nasync function listKvNamespaces(\n cwd: string,\n configPath: string,\n): Promise<KvNamespaceInfo[]> {\n const provider = resolveProvider();\n const namespaces = await provider.listNamespaces({ cwd, configPath });\n return namespaces.map((item) => ({\n id: item.id,\n title: item.title,\n }));\n}\n\nasync function ensureKvNamespaceBindingId(\n cwd: string,\n configPath: string,\n): Promise<string | null> {\n const config = await readWranglerConfig(configPath);\n const binding = config.kv_namespaces?.find(\n (item) => item.binding === \"KALP_MANIFESTS\",\n );\n\n if (!binding || !config.name) return null;\n if (binding.id) return binding.id;\n\n const expectedTitle = deriveKvNamespaceTitle(config.name, binding.binding);\n const namespaces = await listKvNamespaces(cwd, configPath);\n const existing = namespaces.find((item) => item.title === expectedTitle);\n if (!existing) return null;\n\n binding.id = existing.id;\n await writeWranglerConfig(configPath, config);\n return existing.id;\n}\n\nfunction isNamespaceAlreadyExistsError(output: string): boolean {\n return output.includes(\"[code: 10014]\") && output.includes(\"already exists\");\n}\n\nexport async function runInitialDeploy(cwd: string): Promise<{\n workerUrl: string;\n customDomains: string[];\n accountId: string;\n studioAdminUser: string;\n studioPassword: string;\n serviceKey: string;\n credentialsChanged: boolean;\n serviceKeyChanged: boolean;\n}> {\n const auth = await requireAuth();\n const loadedConfig = await loadProjectConfig(cwd);\n const identityConfig = resolveRuntimeIdentityConfig(loadedConfig.raw);\n const identitySecretRequirements = resolveIdentityAuthRequirements(identityConfig);\n const aiProvider = await resolveProviderFromConfig(cwd);\n const requiredProviderSecret = getRequiredSecretForProvider(aiProvider);\n const secrets = await ensureStudioSecrets(cwd);\n const envMap = await readDotEnv(cwd);\n const providerSecretValue = envMap[requiredProviderSecret]?.trim();\n if (!providerSecretValue) {\n throw new Error(\n `Missing required secret ${requiredProviderSecret} for provider \"${aiProvider}\". Add it to .env before deploy.`,\n );\n }\n\n const resolvedIdentitySecrets = identitySecretRequirements.map((requirement) => {\n const value = envMap[requirement.envKey]?.trim();\n if (!value) {\n throw new Error(\n `Missing required secret ${requirement.envKey} for ${requirement.reason}. Add it to .env before deploy.`,\n );\n }\n return { name: requirement.envKey, value };\n });\n\n const runtimeProvider = resolveProvider();\n const runtime = await materializeRuntime(cwd);\n let secretSyncFailed = false;\n const secretEntries = [\n [\"KALP_SECRET_KEY\", secrets.key],\n [\"KALP_STUDIO_PASSWORD\", secrets.studioPassword],\n [\"KALP_STUDIO_ADMIN_USER\", secrets.studioAdminUser],\n [\"KALP_SERVICE_KEY\", secrets.serviceKey],\n [requiredProviderSecret, providerSecretValue],\n ...resolvedIdentitySecrets.map((item) => [item.name, item.value] as const),\n ];\n const dedupedSecrets = new Map<string, string>();\n for (const [name, value] of secretEntries) {\n dedupedSecrets.set(name, value);\n }\n\n for (const [name, value] of dedupedSecrets.entries()) {\n try {\n await runtimeProvider.putSecret({\n cwd,\n configPath: runtime.wranglerConfigPath,\n name,\n value,\n });\n } catch {\n secretSyncFailed = true;\n break;\n }\n }\n\n await ensureKvNamespaceBindingId(cwd, runtime.wranglerConfigPath).catch(\n () => null,\n );\n\n let deploy = await runtimeProvider\n .deployRuntime({\n cwd,\n configPath: runtime.wranglerConfigPath,\n useSecretsFile: secretSyncFailed,\n })\n .catch((error) => error);\n if (deploy instanceof Error) {\n const combined = deploy.message;\n if (isNamespaceAlreadyExistsError(combined)) {\n await ensureKvNamespaceBindingId(cwd, runtime.wranglerConfigPath);\n deploy = await runtimeProvider.deployRuntime({\n cwd,\n configPath: runtime.wranglerConfigPath,\n useSecretsFile: secretSyncFailed,\n });\n } else {\n throw deploy;\n }\n }\n\n const workerUrl = deploy.workerUrl;\n const customDomains = deploy.customDomains ?? [];\n\n const existingState = await readProjectState(cwd);\n\n const credentialsFingerprint = createHash(\"sha256\")\n .update(`${secrets.studioAdminUser}:${secrets.studioPassword}`)\n .digest(\"hex\");\n const credentialsChanged =\n existingState?.studioCredentialsFingerprint !== credentialsFingerprint;\n const serviceKeyFingerprint = createHash(\"sha256\")\n .update(secrets.serviceKey)\n .digest(\"hex\");\n const serviceKeyChanged =\n existingState?.serviceKeyFingerprint !== serviceKeyFingerprint;\n\n await writeProjectState(cwd, {\n workerUrl,\n deployedAt: new Date().toISOString(),\n accountId: auth.accountId,\n studioCredentialsFingerprint: credentialsFingerprint,\n serviceKeyFingerprint,\n agents: existingState?.agents ?? {},\n });\n\n return {\n workerUrl,\n customDomains,\n accountId: auth.accountId,\n studioAdminUser: secrets.studioAdminUser,\n studioPassword: secrets.studioPassword,\n serviceKey: secrets.serviceKey,\n credentialsChanged,\n serviceKeyChanged,\n };\n}\n"],"mappings":"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","names":[]}