@kalphq/cli 0.0.0-dev-20260510070528 → 0.0.0-dev-20260512045454
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/dist/{chunk-RT2DIIQ5.js → chunk-5AEWO2OC.js} +104 -96
- package/dist/chunk-5AEWO2OC.js.map +1 -0
- package/dist/{chunk-WRCC37FP.js → chunk-MKVNPOVJ.js} +61 -7
- package/dist/chunk-MKVNPOVJ.js.map +1 -0
- package/dist/{create-QTVTQ6QL.js → create-WU5JH6FP.js} +13 -2
- package/dist/create-WU5JH6FP.js.map +1 -0
- package/dist/{deploy-YZ3OP2MN.js → deploy-FVOKQP6K.js} +3 -3
- package/dist/{dev-UC2WFSOE.js → dev-AHTXYEF2.js} +3 -4
- package/dist/dev-AHTXYEF2.js.map +1 -0
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/dist/push-FIZZS6HQ.js +341 -0
- package/dist/push-FIZZS6HQ.js.map +1 -0
- package/dist/runtime-template/studio/assets/geist-cyrillic-wght-normal-CHSlOQsW.woff2 +0 -0
- package/dist/runtime-template/studio/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2 +0 -0
- package/dist/runtime-template/studio/assets/geist-latin-wght-normal-Dm3htQBi.woff2 +0 -0
- package/dist/runtime-template/studio/assets/geist-mono-cyrillic-wght-normal-BZdD_g9V.woff2 +0 -0
- package/dist/runtime-template/studio/assets/geist-mono-latin-ext-wght-normal-b6lpi8_2.woff2 +0 -0
- package/dist/runtime-template/studio/assets/geist-mono-latin-wght-normal-Cjtb1TV-.woff2 +0 -0
- package/dist/runtime-template/studio/assets/index-BHzMtWls.css +2 -0
- package/dist/runtime-template/studio/assets/index-rgoZQzco.js +112 -0
- package/dist/runtime-template/studio/index.html +2 -2
- package/dist/runtime-template/studio/mockServiceWorker.js +349 -0
- package/package.json +5 -4
- package/dist/chunk-RT2DIIQ5.js.map +0 -1
- package/dist/chunk-WRCC37FP.js.map +0 -1
- package/dist/create-QTVTQ6QL.js.map +0 -1
- package/dist/dev-UC2WFSOE.js.map +0 -1
- package/dist/push-XGNM2IEY.js +0 -263
- package/dist/push-XGNM2IEY.js.map +0 -1
- package/dist/runtime-template/studio/assets/index-D8vnrQHk.js +0 -112
- package/dist/runtime-template/studio/assets/index-GI30ROBZ.css +0 -2
- package/dist/runtime-template/studio/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/dist/runtime-template/studio/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/dist/runtime-template/studio/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/dist/runtime-template/studio/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/dist/runtime-template/studio/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/dist/runtime-template/studio/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/dist/runtime-template/studio/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- /package/dist/{deploy-YZ3OP2MN.js.map → deploy-FVOKQP6K.js.map} +0 -0
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
ensureGlobalConfigDir
|
|
4
|
-
} from "./chunk-FO24J6XL.js";
|
|
5
2
|
|
|
6
3
|
// src/utils/secret.ts
|
|
7
4
|
import { randomBytes } from "crypto";
|
|
@@ -76,11 +73,38 @@ import { mkdir, readFile as readFile2, writeFile as writeFile2 } from "fs/promis
|
|
|
76
73
|
import { join as join2 } from "path";
|
|
77
74
|
var KALP_DIR = ".kalp";
|
|
78
75
|
var STATE_FILE = "state.json";
|
|
76
|
+
function normalizeProjectState(raw) {
|
|
77
|
+
if (!raw || typeof raw !== "object") return null;
|
|
78
|
+
const value = raw;
|
|
79
|
+
const workerUrl = typeof value.workerUrl === "string" && value.workerUrl.length > 0 ? value.workerUrl : null;
|
|
80
|
+
const deployedAt = typeof value.deployedAt === "string" && value.deployedAt.length > 0 ? value.deployedAt : null;
|
|
81
|
+
const accountId = typeof value.accountId === "string" && value.accountId.length > 0 ? value.accountId : null;
|
|
82
|
+
const agents = {};
|
|
83
|
+
const rawAgents = value.agents && typeof value.agents === "object" ? value.agents : {};
|
|
84
|
+
for (const [name, entry] of Object.entries(rawAgents)) {
|
|
85
|
+
if (!entry || typeof entry !== "object") continue;
|
|
86
|
+
const item = entry;
|
|
87
|
+
if (typeof item.localPath !== "string" || item.localPath.length === 0) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const currentVersion = typeof item.currentVersion === "number" && Number.isFinite(item.currentVersion) ? Math.max(0, Math.floor(item.currentVersion)) : 0;
|
|
91
|
+
agents[name] = {
|
|
92
|
+
currentHash: typeof item.currentHash === "string" ? item.currentHash : null,
|
|
93
|
+
currentVersion,
|
|
94
|
+
lastLocalHash: typeof item.lastLocalHash === "string" ? item.lastLocalHash : null,
|
|
95
|
+
lastRemoteHash: typeof item.lastRemoteHash === "string" ? item.lastRemoteHash : null,
|
|
96
|
+
lastPushedAt: typeof item.lastPushedAt === "string" ? item.lastPushedAt : null,
|
|
97
|
+
localPath: item.localPath,
|
|
98
|
+
workerUrl: typeof item.workerUrl === "string" ? item.workerUrl : null
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return { workerUrl, deployedAt, accountId, agents };
|
|
102
|
+
}
|
|
79
103
|
async function readProjectState(cwd) {
|
|
80
104
|
try {
|
|
81
105
|
const statePath = join2(cwd, KALP_DIR, STATE_FILE);
|
|
82
106
|
const content = await readFile2(statePath, "utf-8");
|
|
83
|
-
return JSON.parse(content);
|
|
107
|
+
return normalizeProjectState(JSON.parse(content));
|
|
84
108
|
} catch {
|
|
85
109
|
return null;
|
|
86
110
|
}
|
|
@@ -88,33 +112,8 @@ async function readProjectState(cwd) {
|
|
|
88
112
|
async function writeProjectState(cwd, state) {
|
|
89
113
|
const dir = join2(cwd, KALP_DIR);
|
|
90
114
|
await mkdir(dir, { recursive: true });
|
|
91
|
-
await writeFile2(join2(dir, STATE_FILE), JSON.stringify(state, null, 2)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
// src/utils/agent-store.ts
|
|
95
|
-
import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
96
|
-
import { join as join3 } from "path";
|
|
97
|
-
async function getStorePath() {
|
|
98
|
-
return join3(await ensureGlobalConfigDir(), "agents.json");
|
|
99
|
-
}
|
|
100
|
-
async function readAgentStore() {
|
|
101
|
-
try {
|
|
102
|
-
const storePath = await getStorePath();
|
|
103
|
-
const content = await readFile3(storePath, "utf-8");
|
|
104
|
-
return JSON.parse(content);
|
|
105
|
-
} catch {
|
|
106
|
-
return {};
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
async function getAgentStoreEntry(agentName) {
|
|
110
|
-
const store = await readAgentStore();
|
|
111
|
-
return store[agentName] ?? null;
|
|
112
|
-
}
|
|
113
|
-
async function writeAgentStoreEntry(agentName, entry) {
|
|
114
|
-
const storePath = await getStorePath();
|
|
115
|
-
const store = await readAgentStore();
|
|
116
|
-
store[agentName] = entry;
|
|
117
|
-
await writeFile3(storePath, JSON.stringify(store, null, 2), "utf-8");
|
|
115
|
+
await writeFile2(join2(dir, STATE_FILE), `${JSON.stringify(state, null, 2)}
|
|
116
|
+
`, "utf-8");
|
|
118
117
|
}
|
|
119
118
|
|
|
120
119
|
// src/utils/runtime.ts
|
|
@@ -124,13 +123,14 @@ import {
|
|
|
124
123
|
cp,
|
|
125
124
|
mkdir as mkdir2,
|
|
126
125
|
readdir,
|
|
127
|
-
readFile as
|
|
126
|
+
readFile as readFile3,
|
|
128
127
|
rm,
|
|
129
128
|
stat,
|
|
130
|
-
writeFile as
|
|
129
|
+
writeFile as writeFile3
|
|
131
130
|
} from "fs/promises";
|
|
132
|
-
import { basename, dirname, join as
|
|
131
|
+
import { basename, dirname, join as join3, resolve } from "path";
|
|
133
132
|
import { fileURLToPath } from "url";
|
|
133
|
+
import { deriveLabelFromName } from "@kalphq/project";
|
|
134
134
|
var RUNTIME_ROOT = ".kalp";
|
|
135
135
|
var RUNTIME_DIR = "runtime";
|
|
136
136
|
var STUDIO_DIR = "studio";
|
|
@@ -142,9 +142,9 @@ function sanitizeSegment(input) {
|
|
|
142
142
|
}
|
|
143
143
|
async function resolveProjectSlug(cwd) {
|
|
144
144
|
const fallback = sanitizeSegment(basename(cwd)) || "agent";
|
|
145
|
-
const packageJsonPath =
|
|
145
|
+
const packageJsonPath = join3(cwd, "package.json");
|
|
146
146
|
try {
|
|
147
|
-
const content = await
|
|
147
|
+
const content = await readFile3(packageJsonPath, "utf-8");
|
|
148
148
|
const pkg = JSON.parse(content);
|
|
149
149
|
const name = typeof pkg.name === "string" ? pkg.name : "";
|
|
150
150
|
const sanitized = sanitizeSegment(name);
|
|
@@ -223,20 +223,20 @@ function runtimeTemplateCandidates() {
|
|
|
223
223
|
);
|
|
224
224
|
return [
|
|
225
225
|
{
|
|
226
|
-
studioTemplateDir:
|
|
227
|
-
workerEntryPath:
|
|
226
|
+
studioTemplateDir: join3(distTemplateRoot, STUDIO_DIR),
|
|
227
|
+
workerEntryPath: join3(distTemplateRoot, WORKER_ENTRY_FILE)
|
|
228
228
|
},
|
|
229
229
|
{
|
|
230
|
-
studioTemplateDir:
|
|
231
|
-
workerEntryPath:
|
|
230
|
+
studioTemplateDir: join3(packageRootTemplate, STUDIO_DIR),
|
|
231
|
+
workerEntryPath: join3(packageRootTemplate, WORKER_ENTRY_FILE)
|
|
232
232
|
},
|
|
233
233
|
{
|
|
234
|
-
studioTemplateDir:
|
|
235
|
-
workerEntryPath:
|
|
234
|
+
studioTemplateDir: join3(sourceTemplateRoot, STUDIO_DIR),
|
|
235
|
+
workerEntryPath: join3(sourceTemplateRoot, WORKER_ENTRY_FILE)
|
|
236
236
|
},
|
|
237
237
|
{
|
|
238
238
|
studioTemplateDir: monorepoStudioDist,
|
|
239
|
-
workerEntryPath:
|
|
239
|
+
workerEntryPath: join3(sourceTemplateRoot, WORKER_ENTRY_FILE)
|
|
240
240
|
}
|
|
241
241
|
];
|
|
242
242
|
}
|
|
@@ -271,13 +271,13 @@ ${cssLinks}
|
|
|
271
271
|
`;
|
|
272
272
|
}
|
|
273
273
|
async function ensureStudioIndex(studioDir) {
|
|
274
|
-
const indexPath =
|
|
274
|
+
const indexPath = join3(studioDir, "index.html");
|
|
275
275
|
try {
|
|
276
276
|
await access(indexPath);
|
|
277
277
|
return;
|
|
278
278
|
} catch {
|
|
279
279
|
}
|
|
280
|
-
const assetsDir =
|
|
280
|
+
const assetsDir = join3(studioDir, "assets");
|
|
281
281
|
const assetFiles = await readdir(assetsDir);
|
|
282
282
|
const entryScript = assetFiles.find((file) => /^index-.*\.js$/i.test(file)) ?? assetFiles.find((file) => file.endsWith(".js"));
|
|
283
283
|
if (!entryScript) {
|
|
@@ -287,16 +287,16 @@ async function ensureStudioIndex(studioDir) {
|
|
|
287
287
|
}
|
|
288
288
|
const cssFiles = assetFiles.filter((file) => file.endsWith(".css")).sort();
|
|
289
289
|
const html = createStudioShell(entryScript, cssFiles);
|
|
290
|
-
await
|
|
290
|
+
await writeFile3(indexPath, html, "utf-8");
|
|
291
291
|
}
|
|
292
292
|
async function readLocalAgentNames(cwd) {
|
|
293
|
-
const agentsDir =
|
|
293
|
+
const agentsDir = join3(cwd, "agents");
|
|
294
294
|
try {
|
|
295
295
|
const entries = await readdir(agentsDir, { withFileTypes: true });
|
|
296
296
|
const names = [];
|
|
297
297
|
for (const entry of entries) {
|
|
298
298
|
if (!entry.isDirectory()) continue;
|
|
299
|
-
const indexPath =
|
|
299
|
+
const indexPath = join3(agentsDir, entry.name, "index.ts");
|
|
300
300
|
const exists = await stat(indexPath).then(() => true).catch(() => false);
|
|
301
301
|
if (exists) names.push(entry.name);
|
|
302
302
|
}
|
|
@@ -305,74 +305,83 @@ async function readLocalAgentNames(cwd) {
|
|
|
305
305
|
return [];
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
|
-
function
|
|
309
|
-
const project = normalize(projectPath).toLowerCase();
|
|
310
|
-
const candidate = normalize(candidatePath).toLowerCase();
|
|
311
|
-
return candidate.startsWith(project);
|
|
312
|
-
}
|
|
313
|
-
async function createAgentsSnapshot(cwd) {
|
|
308
|
+
async function createAgentsSnapshot(cwd, mode) {
|
|
314
309
|
const localAgentNames = await readLocalAgentNames(cwd);
|
|
315
310
|
const state = await readProjectState(cwd);
|
|
316
|
-
const globalStore = await readAgentStore();
|
|
317
311
|
const byName = /* @__PURE__ */ new Map();
|
|
312
|
+
const stateAgents = state?.agents ?? {};
|
|
318
313
|
for (const name of localAgentNames) {
|
|
319
|
-
const localPath =
|
|
314
|
+
const localPath = join3(cwd, "agents", name, "index.ts");
|
|
315
|
+
const saved = stateAgents[name];
|
|
316
|
+
const hasRemoteVersion = !!saved?.lastRemoteHash && (saved?.currentVersion ?? 0) > 0;
|
|
317
|
+
if (mode === "remote" && !hasRemoteVersion) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
const resolvedWorkerUrl = saved?.workerUrl ?? (state?.workerUrl ? `${state.workerUrl.replace(/\/$/, "")}/a/${name}` : null);
|
|
321
|
+
const versionNumber = typeof saved?.currentVersion === "number" && saved.currentVersion > 0 ? saved.currentVersion : null;
|
|
320
322
|
byName.set(name, {
|
|
321
323
|
name,
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
324
|
+
label: deriveLabelFromName(name),
|
|
325
|
+
tags: [],
|
|
326
|
+
environment: mode === "remote" ? "remote" : hasRemoteVersion ? "both" : "local",
|
|
327
|
+
status: resolvedWorkerUrl ? "online" : "offline",
|
|
328
|
+
hash: saved?.currentHash ?? null,
|
|
329
|
+
version: versionNumber ? `v${versionNumber}` : null,
|
|
330
|
+
versionNumber,
|
|
331
|
+
lastRemoteHash: saved?.lastRemoteHash ?? null,
|
|
332
|
+
lastLocalHash: saved?.lastLocalHash ?? null,
|
|
333
|
+
workerUrl: resolvedWorkerUrl,
|
|
326
334
|
localPath,
|
|
327
|
-
updatedAt: null
|
|
335
|
+
updatedAt: saved?.lastPushedAt ?? state?.deployedAt ?? null
|
|
328
336
|
});
|
|
329
337
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
name
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
338
|
+
if (mode === "remote") {
|
|
339
|
+
for (const [name, saved] of Object.entries(stateAgents)) {
|
|
340
|
+
const hasRemoteVersion = !!saved.lastRemoteHash && (saved.currentVersion ?? 0) > 0;
|
|
341
|
+
if (!hasRemoteVersion || byName.has(name)) continue;
|
|
342
|
+
const localPath = saved.localPath ?? join3(cwd, "agents", name, "index.ts");
|
|
343
|
+
const workerUrl = saved.workerUrl ?? (state?.workerUrl ? `${state.workerUrl.replace(/\/$/, "")}/a/${name}` : null);
|
|
344
|
+
const versionNumber = saved.currentVersion > 0 ? saved.currentVersion : null;
|
|
345
|
+
byName.set(name, {
|
|
346
|
+
name,
|
|
347
|
+
label: deriveLabelFromName(name),
|
|
348
|
+
tags: [],
|
|
349
|
+
environment: "remote",
|
|
350
|
+
status: workerUrl ? "online" : "offline",
|
|
351
|
+
hash: saved.currentHash ?? null,
|
|
352
|
+
version: versionNumber ? `v${versionNumber}` : null,
|
|
353
|
+
versionNumber,
|
|
354
|
+
lastRemoteHash: saved.lastRemoteHash ?? null,
|
|
355
|
+
lastLocalHash: saved.lastLocalHash ?? null,
|
|
356
|
+
workerUrl,
|
|
357
|
+
localPath,
|
|
358
|
+
updatedAt: saved.lastPushedAt ?? state?.deployedAt ?? null
|
|
359
|
+
});
|
|
353
360
|
}
|
|
354
361
|
}
|
|
355
362
|
return {
|
|
356
363
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
357
364
|
projectPath: cwd,
|
|
358
365
|
workerUrl: state?.workerUrl ?? null,
|
|
366
|
+
mode,
|
|
359
367
|
agents: Array.from(byName.values()).sort((a, b) => a.name.localeCompare(b.name))
|
|
360
368
|
};
|
|
361
369
|
}
|
|
362
|
-
async function materializeRuntime(cwd) {
|
|
363
|
-
const
|
|
364
|
-
const
|
|
365
|
-
const
|
|
366
|
-
const
|
|
370
|
+
async function materializeRuntime(cwd, options = {}) {
|
|
371
|
+
const mode = options.mode ?? "remote";
|
|
372
|
+
const runtimeDir = join3(cwd, RUNTIME_ROOT, RUNTIME_DIR);
|
|
373
|
+
const studioDir = join3(runtimeDir, STUDIO_DIR);
|
|
374
|
+
const workerEntrypointPath = join3(runtimeDir, WORKER_ENTRY_FILE);
|
|
375
|
+
const wranglerConfigPath = join3(runtimeDir, WRANGLER_CONFIG_FILE);
|
|
367
376
|
const template = await resolveRuntimeTemplate();
|
|
368
377
|
await rm(runtimeDir, { recursive: true, force: true });
|
|
369
378
|
await mkdir2(runtimeDir, { recursive: true });
|
|
370
379
|
await cp(template.studioTemplateDir, studioDir, { recursive: true });
|
|
371
380
|
await cp(template.workerEntryPath, workerEntrypointPath);
|
|
372
381
|
await ensureStudioIndex(studioDir);
|
|
373
|
-
const agentsSnapshot = await createAgentsSnapshot(cwd);
|
|
374
|
-
await
|
|
375
|
-
|
|
382
|
+
const agentsSnapshot = await createAgentsSnapshot(cwd, mode);
|
|
383
|
+
await writeFile3(
|
|
384
|
+
join3(runtimeDir, "agents.snapshot.json"),
|
|
376
385
|
`${JSON.stringify(agentsSnapshot, null, 2)}
|
|
377
386
|
`,
|
|
378
387
|
"utf-8"
|
|
@@ -380,7 +389,7 @@ async function materializeRuntime(cwd) {
|
|
|
380
389
|
const projectSlug = await resolveProjectSlug(cwd);
|
|
381
390
|
const workerName = buildWorkerName(projectSlug, cwd);
|
|
382
391
|
const wranglerConfig = createRuntimeConfig(workerName);
|
|
383
|
-
await
|
|
392
|
+
await writeFile3(
|
|
384
393
|
wranglerConfigPath,
|
|
385
394
|
`${JSON.stringify(wranglerConfig, null, 2)}
|
|
386
395
|
`,
|
|
@@ -400,8 +409,7 @@ export {
|
|
|
400
409
|
ensureSecretKey,
|
|
401
410
|
readProjectState,
|
|
402
411
|
writeProjectState,
|
|
403
|
-
|
|
404
|
-
writeAgentStoreEntry,
|
|
412
|
+
readLocalAgentNames,
|
|
405
413
|
materializeRuntime
|
|
406
414
|
};
|
|
407
|
-
//# sourceMappingURL=chunk-
|
|
415
|
+
//# sourceMappingURL=chunk-5AEWO2OC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/secret.ts","../src/utils/project-state.ts","../src/utils/runtime.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nconst SECRET_KEY = \"KALP_SECRET_KEY\";\nconst STUDIO_PASSWORD = \"KALP_STUDIO_PASSWORD\";\nconst STUDIO_ADMIN_USER = \"KALP_STUDIO_ADMIN_USER\";\n\nfunction parseEnv(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const line of content.split(/\\r?\\n/g)) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) continue;\n const eqIndex = trimmed.indexOf(\"=\");\n if (eqIndex <= 0) continue;\n const key = trimmed.slice(0, eqIndex).trim();\n const value = trimmed.slice(eqIndex + 1).trim();\n result[key] = value;\n }\n return result;\n}\n\nfunction toEnvContent(values: Record<string, string>): string {\n const lines = [\n \"# Kalp Studio Authentication Secrets\",\n `${SECRET_KEY}=${values[SECRET_KEY]}`,\n `${STUDIO_PASSWORD}=${values[STUDIO_PASSWORD]}`,\n `${STUDIO_ADMIN_USER}=${values[STUDIO_ADMIN_USER]}`,\n \"\",\n ];\n return lines.join(\"\\n\");\n}\n\nasync function readEnvFile(cwd: string): Promise<string> {\n const envPath = join(cwd, \".env\");\n try {\n return await readFile(envPath, \"utf-8\");\n } catch {\n return \"\";\n }\n}\n\nfunction generateStudioPassword(): string {\n return randomBytes(24).toString(\"base64url\");\n}\n\nexport interface StudioSecrets {\n key: string;\n studioPassword: string;\n studioAdminUser: string;\n isNew: boolean;\n}\n\nexport async function ensureStudioSecrets(cwd: string): Promise<StudioSecrets> {\n const envPath = join(cwd, \".env\");\n const content = await readEnvFile(cwd);\n const parsed = parseEnv(content);\n\n const key = parsed[SECRET_KEY] || randomBytes(32).toString(\"hex\");\n const studioPassword = parsed[STUDIO_PASSWORD] || generateStudioPassword();\n const studioAdminUser = parsed[STUDIO_ADMIN_USER] || \"admin\";\n\n const isNew =\n !parsed[SECRET_KEY] || !parsed[STUDIO_PASSWORD] || !parsed[STUDIO_ADMIN_USER];\n\n if (isNew || !content.trim()) {\n await writeFile(\n envPath,\n toEnvContent({\n ...parsed,\n [SECRET_KEY]: key,\n [STUDIO_PASSWORD]: studioPassword,\n [STUDIO_ADMIN_USER]: studioAdminUser,\n }),\n \"utf-8\",\n );\n }\n\n return { key, studioPassword, studioAdminUser, isNew };\n}\n\nexport async function ensureSecretKey(\n cwd: string,\n): Promise<{ key: string; isNew: boolean }> {\n const secrets = await ensureStudioSecrets(cwd);\n return { key: secrets.key, isNew: secrets.isNew };\n}\n\nexport async function readSecretKey(cwd: string): Promise<string | null> {\n try {\n const envContent = await readEnvFile(cwd);\n const parsed = parseEnv(envContent);\n return parsed[SECRET_KEY] ?? null;\n } catch {\n return null;\n }\n}\n\nexport async function readStudioSecrets(cwd: string): Promise<{\n key: string;\n studioPassword: string;\n studioAdminUser: string;\n} | null> {\n try {\n const envContent = await readEnvFile(cwd);\n const parsed = parseEnv(envContent);\n const key = parsed[SECRET_KEY];\n const studioPassword = parsed[STUDIO_PASSWORD];\n const studioAdminUser = parsed[STUDIO_ADMIN_USER] || \"admin\";\n if (!key || !studioPassword) return null;\n return { key, studioPassword, studioAdminUser };\n } catch {\n return null;\n }\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface ProjectAgentState {\n currentHash: string | null;\n currentVersion: number;\n lastLocalHash: string | null;\n lastRemoteHash: string | null;\n lastPushedAt: string | null;\n localPath: string;\n workerUrl: string | null;\n}\n\nexport interface ProjectState {\n workerUrl: string | null;\n deployedAt: string | null;\n accountId: string | null;\n agents: Record<string, ProjectAgentState>;\n}\n\nconst KALP_DIR = \".kalp\";\nconst STATE_FILE = \"state.json\";\n\nfunction normalizeProjectState(raw: unknown): ProjectState | null {\n if (!raw || typeof raw !== \"object\") return null;\n const value = raw as Record<string, unknown>;\n const workerUrl =\n typeof value.workerUrl === \"string\" && value.workerUrl.length > 0\n ? value.workerUrl\n : null;\n const deployedAt =\n typeof value.deployedAt === \"string\" && value.deployedAt.length > 0\n ? value.deployedAt\n : null;\n const accountId =\n typeof value.accountId === \"string\" && value.accountId.length > 0\n ? value.accountId\n : null;\n\n const agents: Record<string, ProjectAgentState> = {};\n const rawAgents =\n value.agents && typeof value.agents === \"object\"\n ? (value.agents as Record<string, unknown>)\n : {};\n\n for (const [name, entry] of Object.entries(rawAgents)) {\n if (!entry || typeof entry !== \"object\") continue;\n const item = entry as Record<string, unknown>;\n if (typeof item.localPath !== \"string\" || item.localPath.length === 0) {\n continue;\n }\n\n const currentVersion =\n typeof item.currentVersion === \"number\" && Number.isFinite(item.currentVersion)\n ? Math.max(0, Math.floor(item.currentVersion))\n : 0;\n\n agents[name] = {\n currentHash: typeof item.currentHash === \"string\" ? item.currentHash : null,\n currentVersion,\n lastLocalHash: typeof item.lastLocalHash === \"string\" ? item.lastLocalHash : null,\n lastRemoteHash:\n typeof item.lastRemoteHash === \"string\" ? item.lastRemoteHash : null,\n lastPushedAt: typeof item.lastPushedAt === \"string\" ? item.lastPushedAt : null,\n localPath: item.localPath,\n workerUrl: typeof item.workerUrl === \"string\" ? item.workerUrl : null,\n };\n }\n\n return { workerUrl, deployedAt, accountId, agents };\n}\n\nexport async function readProjectState(cwd: string): Promise<ProjectState | null> {\n try {\n const statePath = join(cwd, KALP_DIR, STATE_FILE);\n const content = await readFile(statePath, \"utf-8\");\n return normalizeProjectState(JSON.parse(content));\n } catch {\n return null;\n }\n}\n\nexport async function writeProjectState(\n cwd: string,\n state: ProjectState,\n): Promise<void> {\n const dir = join(cwd, KALP_DIR);\n await mkdir(dir, { recursive: true });\n await writeFile(join(dir, STATE_FILE), `${JSON.stringify(state, null, 2)}\\n`, \"utf-8\");\n}\n","import { createHash } from \"node:crypto\";\nimport {\n access,\n cp,\n mkdir,\n readdir,\n readFile,\n rm,\n stat,\n writeFile,\n} from \"node:fs/promises\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { deriveLabelFromName } from \"@kalphq/project\";\nimport { readProjectState } from \"@/utils/project-state\";\n\nconst RUNTIME_ROOT = \".kalp\";\nconst RUNTIME_DIR = \"runtime\";\nconst STUDIO_DIR = \"studio\";\nconst WRANGLER_CONFIG_FILE = \"wrangler.jsonc\";\nconst WORKER_ENTRY_FILE = \"worker-entry.js\";\nconst COMPATIBILITY_DATE = \"2026-05-10\";\n\nexport interface RuntimePaths {\n runtimeDir: string;\n studioDir: string;\n workerEntrypointPath: string;\n wranglerConfigPath: string;\n workerName: string;\n}\n\ninterface RuntimeAgentRecord {\n name: string;\n label?: string;\n tags?: string[];\n environment: \"local\" | \"remote\" | \"both\";\n status: \"online\" | \"offline\";\n hash: string | null;\n version: string | null;\n versionNumber: number | null;\n lastRemoteHash: string | null;\n lastLocalHash: string | null;\n workerUrl: string | null;\n localPath: string | null;\n updatedAt: string | null;\n}\n\ninterface RuntimeAgentsSnapshot {\n generatedAt: string;\n projectPath: string;\n workerUrl: string | null;\n mode: \"local\" | \"remote\";\n agents: RuntimeAgentRecord[];\n}\n\nexport interface MaterializeRuntimeOptions {\n mode?: \"local\" | \"remote\";\n}\n\ninterface WranglerConfig {\n $schema: string;\n name: string;\n main: string;\n compatibility_date: string;\n compatibility_flags: string[];\n migrations: Array<{ tag: string; new_sqlite_classes: string[] }>;\n durable_objects: {\n bindings: Array<{ name: string; class_name: string }>;\n };\n kv_namespaces: Array<{ binding: string }>;\n assets: {\n directory: string;\n binding: string;\n run_worker_first: boolean;\n };\n observability: { enabled: boolean };\n upload_source_maps: boolean;\n secrets: { required: string[] };\n}\n\ninterface RuntimeTemplatePaths {\n studioTemplateDir: string;\n workerEntryPath: string;\n}\n\nfunction sanitizeSegment(input: string): string {\n return input\n .toLowerCase()\n .replace(/^@/, \"\")\n .replace(/\\//g, \"-\")\n .replace(/[^a-z0-9-]/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\nasync function resolveProjectSlug(cwd: string): Promise<string> {\n const fallback = sanitizeSegment(basename(cwd)) || \"agent\";\n const packageJsonPath = join(cwd, \"package.json\");\n\n try {\n const content = await readFile(packageJsonPath, \"utf-8\");\n const pkg = JSON.parse(content) as { name?: string };\n const name = typeof pkg.name === \"string\" ? pkg.name : \"\";\n const sanitized = sanitizeSegment(name);\n return sanitized || fallback;\n } catch {\n return fallback;\n }\n}\n\nfunction buildWorkerName(slug: string, cwd: string): string {\n const cwdHash = createHash(\"sha1\").update(cwd).digest(\"hex\").slice(0, 8);\n const withPrefix = `kalp-${slug}-${cwdHash}`;\n const maxLen = 63;\n if (withPrefix.length <= maxLen) {\n return withPrefix;\n }\n\n const clipped = withPrefix.slice(0, maxLen).replace(/-+$/g, \"\");\n return clipped || `kalp-${cwdHash}`;\n}\n\nfunction createRuntimeConfig(workerName: string): WranglerConfig {\n return {\n $schema: \"node_modules/wrangler/config-schema.json\",\n name: workerName,\n main: `./${WORKER_ENTRY_FILE}`,\n compatibility_date: COMPATIBILITY_DATE,\n compatibility_flags: [\"nodejs_compat\"],\n migrations: [\n {\n tag: \"v1\",\n new_sqlite_classes: [\"AgentDurableObject\"],\n },\n ],\n durable_objects: {\n bindings: [\n {\n name: \"KALP_RUNTIME_CLOUDFLARE\",\n class_name: \"AgentDurableObject\",\n },\n ],\n },\n kv_namespaces: [\n {\n binding: \"KALP_MANIFESTS\",\n },\n ],\n assets: {\n directory: `./${STUDIO_DIR}`,\n binding: \"ASSETS\",\n run_worker_first: true,\n },\n observability: { enabled: true },\n upload_source_maps: true,\n secrets: {\n required: [\n \"KALP_SECRET_KEY\",\n \"KALP_STUDIO_PASSWORD\",\n \"KALP_STUDIO_ADMIN_USER\",\n ],\n },\n };\n}\n\nfunction runtimeTemplateCandidates(): Array<{\n studioTemplateDir: string;\n workerEntryPath: string;\n}> {\n const here = dirname(fileURLToPath(import.meta.url));\n const distTemplateRoot = resolve(here, \"runtime-template\");\n const packageRootTemplate = resolve(here, \"..\", \"runtime-template\");\n const sourceTemplateRoot = resolve(here, \"..\", \"..\", \"runtime-template\");\n const monorepoStudioDist = resolve(\n here,\n \"..\",\n \"..\",\n \"..\",\n \"..\",\n \"apps\",\n \"studio\",\n \"dist\",\n \"client\",\n );\n\n return [\n {\n studioTemplateDir: join(distTemplateRoot, STUDIO_DIR),\n workerEntryPath: join(distTemplateRoot, WORKER_ENTRY_FILE),\n },\n {\n studioTemplateDir: join(packageRootTemplate, STUDIO_DIR),\n workerEntryPath: join(packageRootTemplate, WORKER_ENTRY_FILE),\n },\n {\n studioTemplateDir: join(sourceTemplateRoot, STUDIO_DIR),\n workerEntryPath: join(sourceTemplateRoot, WORKER_ENTRY_FILE),\n },\n {\n studioTemplateDir: monorepoStudioDist,\n workerEntryPath: join(sourceTemplateRoot, WORKER_ENTRY_FILE),\n },\n ];\n}\n\nasync function resolveRuntimeTemplate(): Promise<RuntimeTemplatePaths> {\n for (const candidate of runtimeTemplateCandidates()) {\n try {\n await access(candidate.studioTemplateDir);\n await access(candidate.workerEntryPath);\n return candidate;\n } catch {\n // continue\n }\n }\n\n throw new Error(\n \"Kalp runtime template not found in CLI package. Reinstall @kalphq/cli.\",\n );\n}\n\nfunction createStudioShell(entryScript: string, cssFiles: string[]): string {\n const cssLinks = cssFiles\n .map((file) => ` <link rel=\"stylesheet\" href=\"/studio/assets/${file}\" />`)\n .join(\"\\n\");\n\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Kalp Studio</title>\n${cssLinks}\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/studio/assets/${entryScript}\"></script>\n </body>\n</html>\n`;\n}\n\nasync function ensureStudioIndex(studioDir: string): Promise<void> {\n const indexPath = join(studioDir, \"index.html\");\n try {\n await access(indexPath);\n return;\n } catch {\n // index.html is missing on some TanStack Start static builds.\n }\n\n const assetsDir = join(studioDir, \"assets\");\n const assetFiles = await readdir(assetsDir);\n const entryScript =\n assetFiles.find((file) => /^index-.*\\.js$/i.test(file)) ??\n assetFiles.find((file) => file.endsWith(\".js\"));\n\n if (!entryScript) {\n throw new Error(\n \"Studio runtime template is missing an entry JS bundle in studio/assets.\",\n );\n }\n\n const cssFiles = assetFiles.filter((file) => file.endsWith(\".css\")).sort();\n const html = createStudioShell(entryScript, cssFiles);\n await writeFile(indexPath, html, \"utf-8\");\n}\n\nexport async function readLocalAgentNames(cwd: string): Promise<string[]> {\n const agentsDir = join(cwd, \"agents\");\n try {\n const entries = await readdir(agentsDir, { withFileTypes: true });\n const names: string[] = [];\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const indexPath = join(agentsDir, entry.name, \"index.ts\");\n const exists = await stat(indexPath)\n .then(() => true)\n .catch(() => false);\n if (exists) names.push(entry.name);\n }\n return names.sort((a, b) => a.localeCompare(b));\n } catch {\n return [];\n }\n}\n\nasync function createAgentsSnapshot(\n cwd: string,\n mode: \"local\" | \"remote\",\n): Promise<RuntimeAgentsSnapshot> {\n const localAgentNames = await readLocalAgentNames(cwd);\n const state = await readProjectState(cwd);\n\n const byName = new Map<string, RuntimeAgentRecord>();\n const stateAgents = state?.agents ?? {};\n\n for (const name of localAgentNames) {\n const localPath = join(cwd, \"agents\", name, \"index.ts\");\n const saved = stateAgents[name];\n const hasRemoteVersion = !!saved?.lastRemoteHash && (saved?.currentVersion ?? 0) > 0;\n\n if (mode === \"remote\" && !hasRemoteVersion) {\n continue;\n }\n\n const resolvedWorkerUrl =\n saved?.workerUrl ??\n (state?.workerUrl ? `${state.workerUrl.replace(/\\/$/, \"\")}/a/${name}` : null);\n const versionNumber =\n typeof saved?.currentVersion === \"number\" && saved.currentVersion > 0\n ? saved.currentVersion\n : null;\n\n byName.set(name, {\n name,\n label: deriveLabelFromName(name),\n tags: [],\n environment:\n mode === \"remote\"\n ? \"remote\"\n : hasRemoteVersion\n ? \"both\"\n : \"local\",\n status: resolvedWorkerUrl ? \"online\" : \"offline\",\n hash: saved?.currentHash ?? null,\n version: versionNumber ? `v${versionNumber}` : null,\n versionNumber,\n lastRemoteHash: saved?.lastRemoteHash ?? null,\n lastLocalHash: saved?.lastLocalHash ?? null,\n workerUrl: resolvedWorkerUrl,\n localPath,\n updatedAt: saved?.lastPushedAt ?? state?.deployedAt ?? null,\n });\n }\n\n if (mode === \"remote\") {\n for (const [name, saved] of Object.entries(stateAgents)) {\n const hasRemoteVersion =\n !!saved.lastRemoteHash && (saved.currentVersion ?? 0) > 0;\n if (!hasRemoteVersion || byName.has(name)) continue;\n\n const localPath = saved.localPath ?? join(cwd, \"agents\", name, \"index.ts\");\n const workerUrl =\n saved.workerUrl ??\n (state?.workerUrl ? `${state.workerUrl.replace(/\\/$/, \"\")}/a/${name}` : null);\n const versionNumber = saved.currentVersion > 0 ? saved.currentVersion : null;\n\n byName.set(name, {\n name,\n label: deriveLabelFromName(name),\n tags: [],\n environment: \"remote\",\n status: workerUrl ? \"online\" : \"offline\",\n hash: saved.currentHash ?? null,\n version: versionNumber ? `v${versionNumber}` : null,\n versionNumber,\n lastRemoteHash: saved.lastRemoteHash ?? null,\n lastLocalHash: saved.lastLocalHash ?? null,\n workerUrl,\n localPath,\n updatedAt: saved.lastPushedAt ?? state?.deployedAt ?? null,\n });\n }\n }\n\n return {\n generatedAt: new Date().toISOString(),\n projectPath: cwd,\n workerUrl: state?.workerUrl ?? null,\n mode,\n agents: Array.from(byName.values()).sort((a, b) => a.name.localeCompare(b.name)),\n };\n}\n\nexport async function materializeRuntime(\n cwd: string,\n options: MaterializeRuntimeOptions = {},\n): Promise<RuntimePaths> {\n const mode = options.mode ?? \"remote\";\n const runtimeDir = join(cwd, RUNTIME_ROOT, RUNTIME_DIR);\n const studioDir = join(runtimeDir, STUDIO_DIR);\n const workerEntrypointPath = join(runtimeDir, WORKER_ENTRY_FILE);\n const wranglerConfigPath = join(runtimeDir, WRANGLER_CONFIG_FILE);\n\n const template = await resolveRuntimeTemplate();\n await rm(runtimeDir, { recursive: true, force: true });\n await mkdir(runtimeDir, { recursive: true });\n\n await cp(template.studioTemplateDir, studioDir, { recursive: true });\n await cp(template.workerEntryPath, workerEntrypointPath);\n await ensureStudioIndex(studioDir);\n const agentsSnapshot = await createAgentsSnapshot(cwd, mode);\n await writeFile(\n join(runtimeDir, \"agents.snapshot.json\"),\n `${JSON.stringify(agentsSnapshot, null, 2)}\\n`,\n \"utf-8\",\n );\n\n const projectSlug = await resolveProjectSlug(cwd);\n const workerName = buildWorkerName(projectSlug, cwd);\n const wranglerConfig = createRuntimeConfig(workerName);\n await writeFile(\n wranglerConfigPath,\n `${JSON.stringify(wranglerConfig, null, 2)}\\n`,\n \"utf-8\",\n );\n\n return {\n runtimeDir,\n studioDir,\n workerEntrypointPath,\n wranglerConfigPath,\n workerName,\n };\n}\n"],"mappings":"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","names":["readFile","writeFile","join","mkdir","readFile","writeFile","join","join","readFile","writeFile","mkdir"]}
|
|
@@ -2,21 +2,63 @@
|
|
|
2
2
|
import {
|
|
3
3
|
ensureStudioSecrets,
|
|
4
4
|
materializeRuntime,
|
|
5
|
+
readProjectState,
|
|
5
6
|
writeProjectState
|
|
6
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-5AEWO2OC.js";
|
|
7
8
|
import {
|
|
8
9
|
requireAuth
|
|
9
10
|
} from "./chunk-5RODADXW.js";
|
|
10
11
|
|
|
11
12
|
// src/utils/deploy.ts
|
|
12
|
-
import { readFile, writeFile } from "fs/promises";
|
|
13
|
+
import { readFile as readFile2, writeFile } from "fs/promises";
|
|
13
14
|
import { execa } from "execa";
|
|
15
|
+
|
|
16
|
+
// src/utils/ai.ts
|
|
17
|
+
import { access, readFile } from "fs/promises";
|
|
18
|
+
import { constants } from "fs";
|
|
19
|
+
import { join } from "path";
|
|
20
|
+
import { createJiti } from "jiti";
|
|
21
|
+
var PROVIDER_SECRET_MAP = {
|
|
22
|
+
openai: "OPENAI_API_KEY",
|
|
23
|
+
anthropic: "ANTHROPIC_API_KEY",
|
|
24
|
+
openrouter: "OPENROUTER_API_KEY",
|
|
25
|
+
custom: "CUSTOM_AI_API_KEY"
|
|
26
|
+
};
|
|
27
|
+
function parseEnv(content) {
|
|
28
|
+
const env = {};
|
|
29
|
+
for (const raw of content.split(/\r?\n/g)) {
|
|
30
|
+
const line = raw.trim();
|
|
31
|
+
if (!line || line.startsWith("#")) continue;
|
|
32
|
+
const idx = line.indexOf("=");
|
|
33
|
+
if (idx <= 0) continue;
|
|
34
|
+
env[line.slice(0, idx).trim()] = line.slice(idx + 1);
|
|
35
|
+
}
|
|
36
|
+
return env;
|
|
37
|
+
}
|
|
38
|
+
async function resolveProviderFromConfig(cwd) {
|
|
39
|
+
const configPath = join(cwd, "kalp.config.ts");
|
|
40
|
+
await access(configPath, constants.F_OK);
|
|
41
|
+
const jiti = createJiti(cwd, { interopDefault: true });
|
|
42
|
+
const config = await jiti.import(configPath);
|
|
43
|
+
const provider = config?.default?.ai?.provider ?? config?.ai?.provider ?? "openai";
|
|
44
|
+
return provider;
|
|
45
|
+
}
|
|
46
|
+
async function readDotEnv(cwd) {
|
|
47
|
+
const envPath = join(cwd, ".env");
|
|
48
|
+
const content = await readFile(envPath, "utf-8").catch(() => "");
|
|
49
|
+
return parseEnv(content);
|
|
50
|
+
}
|
|
51
|
+
function getRequiredSecretForProvider(provider) {
|
|
52
|
+
return PROVIDER_SECRET_MAP[provider];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/utils/deploy.ts
|
|
14
56
|
function findWorkersUrl(output) {
|
|
15
57
|
const match = output.match(/https:\/\/[^\s]+\.workers\.dev/);
|
|
16
58
|
return match?.[0] ?? null;
|
|
17
59
|
}
|
|
18
60
|
async function readWranglerConfig(configPath) {
|
|
19
|
-
const text = await
|
|
61
|
+
const text = await readFile2(configPath, "utf-8");
|
|
20
62
|
return JSON.parse(text);
|
|
21
63
|
}
|
|
22
64
|
async function writeWranglerConfig(configPath, config) {
|
|
@@ -82,7 +124,7 @@ function isNamespaceAlreadyExistsError(output) {
|
|
|
82
124
|
async function resolveWorkerUrl(configPath, deployOutput) {
|
|
83
125
|
const fromOutput = findWorkersUrl(deployOutput);
|
|
84
126
|
if (fromOutput) return fromOutput;
|
|
85
|
-
const configText = await
|
|
127
|
+
const configText = await readFile2(configPath, "utf-8").catch(
|
|
86
128
|
() => null
|
|
87
129
|
);
|
|
88
130
|
const workerName = configText?.match(/"name"\s*:\s*"([^"]+)"/)?.[1];
|
|
@@ -93,13 +135,23 @@ async function resolveWorkerUrl(configPath, deployOutput) {
|
|
|
93
135
|
}
|
|
94
136
|
async function runInitialDeploy(cwd) {
|
|
95
137
|
const auth = await requireAuth();
|
|
138
|
+
const provider = await resolveProviderFromConfig(cwd);
|
|
139
|
+
const requiredProviderSecret = getRequiredSecretForProvider(provider);
|
|
140
|
+
const envMap = await readDotEnv(cwd);
|
|
141
|
+
const providerSecretValue = envMap[requiredProviderSecret]?.trim();
|
|
142
|
+
if (!providerSecretValue) {
|
|
143
|
+
throw new Error(
|
|
144
|
+
`Missing required secret ${requiredProviderSecret} for provider "${provider}". Add it to .env before deploy.`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
96
147
|
const secrets = await ensureStudioSecrets(cwd);
|
|
97
148
|
const runtime = await materializeRuntime(cwd);
|
|
98
149
|
let secretSyncFailed = false;
|
|
99
150
|
const secretEntries = [
|
|
100
151
|
["KALP_SECRET_KEY", secrets.key],
|
|
101
152
|
["KALP_STUDIO_PASSWORD", secrets.studioPassword],
|
|
102
|
-
["KALP_STUDIO_ADMIN_USER", secrets.studioAdminUser]
|
|
153
|
+
["KALP_STUDIO_ADMIN_USER", secrets.studioAdminUser],
|
|
154
|
+
[requiredProviderSecret, providerSecretValue]
|
|
103
155
|
];
|
|
104
156
|
for (const [name, value] of secretEntries) {
|
|
105
157
|
try {
|
|
@@ -140,10 +192,12 @@ async function runInitialDeploy(cwd) {
|
|
|
140
192
|
runtime.wranglerConfigPath,
|
|
141
193
|
deployStdout
|
|
142
194
|
);
|
|
195
|
+
const existingState = await readProjectState(cwd);
|
|
143
196
|
await writeProjectState(cwd, {
|
|
144
197
|
workerUrl,
|
|
145
198
|
deployedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
146
|
-
accountId: auth.accountId
|
|
199
|
+
accountId: auth.accountId,
|
|
200
|
+
agents: existingState?.agents ?? {}
|
|
147
201
|
});
|
|
148
202
|
return { workerUrl, accountId: auth.accountId };
|
|
149
203
|
}
|
|
@@ -151,4 +205,4 @@ async function runInitialDeploy(cwd) {
|
|
|
151
205
|
export {
|
|
152
206
|
runInitialDeploy
|
|
153
207
|
};
|
|
154
|
-
//# sourceMappingURL=chunk-
|
|
208
|
+
//# sourceMappingURL=chunk-MKVNPOVJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/deploy.ts","../src/utils/ai.ts"],"sourcesContent":["import { readFile, writeFile } from \"node:fs/promises\";\nimport { execa } from \"execa\";\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\";\n\nfunction findWorkersUrl(output: string): string | null {\n const match = output.match(/https:\\/\\/[^\\s]+\\.workers\\.dev/);\n return match?.[0] ?? null;\n}\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\nfunction parseKvListOutput(stdout: string): KvNamespaceInfo[] {\n const trimmed = stdout.trim();\n if (!trimmed) return [];\n\n try {\n const parsed = JSON.parse(trimmed);\n if (Array.isArray(parsed)) {\n return parsed\n .map((item) => ({\n id: String((item as { id?: string }).id ?? \"\"),\n title: String((item as { title?: string }).title ?? \"\"),\n }))\n .filter((item) => !!item.id && !!item.title);\n }\n } catch {\n // fallback to text parsing below\n }\n\n const matches = trimmed.match(/[a-f0-9]{32}\\s+[^\\r\\n]+/gi) ?? [];\n return matches\n .map((line) => {\n const [id, ...rest] = line.trim().split(/\\s+/g);\n return { id: id ?? \"\", title: rest.join(\" \") };\n })\n .filter((item) => !!item.id && !!item.title);\n}\n\nasync function listKvNamespaces(\n cwd: string,\n configPath: string,\n): Promise<KvNamespaceInfo[]> {\n const tryJson = await execa(\n \"npx\",\n [\"wrangler\", \"kv\", \"namespace\", \"list\", \"--config\", configPath, \"--json\"],\n { cwd },\n ).catch(() => null);\n\n if (tryJson) {\n return parseKvListOutput(tryJson.stdout);\n }\n\n const plain = await execa(\n \"npx\",\n [\"wrangler\", \"kv\", \"namespace\", \"list\", \"--config\", configPath],\n { cwd },\n );\n return parseKvListOutput(plain.stdout);\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\nasync function resolveWorkerUrl(\n configPath: string,\n deployOutput: string,\n): Promise<string> {\n const fromOutput = findWorkersUrl(deployOutput);\n if (fromOutput) return fromOutput;\n\n const configText = await readFile(configPath, \"utf-8\").catch(\n () => null as string | null,\n );\n const workerName = configText?.match(/\"name\"\\s*:\\s*\"([^\"]+)\"/)?.[1];\n\n if (workerName) {\n return `https://${workerName}.workers.dev`;\n }\n\n throw new Error(\"Could not resolve worker URL from wrangler deploy output.\");\n}\n\nexport async function runInitialDeploy(cwd: string): Promise<{\n workerUrl: string;\n accountId: string;\n}> {\n const auth = await requireAuth();\n const provider = await resolveProviderFromConfig(cwd);\n const requiredProviderSecret = getRequiredSecretForProvider(provider);\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 \"${provider}\". Add it to .env before deploy.`,\n );\n }\n\n const secrets = await ensureStudioSecrets(cwd);\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 [requiredProviderSecret, providerSecretValue],\n ] as const;\n\n for (const [name, value] of secretEntries) {\n try {\n await execa(\n \"npx\",\n [\"wrangler\", \"secret\", \"put\", name, \"--config\", runtime.wranglerConfigPath],\n { cwd, input: `${value}\\n` },\n );\n } catch {\n secretSyncFailed = true;\n break;\n }\n }\n\n await ensureKvNamespaceBindingId(cwd, runtime.wranglerConfigPath).catch(\n () => null,\n );\n\n const deployArgs = secretSyncFailed\n ? [\n \"wrangler\",\n \"deploy\",\n \"--config\",\n runtime.wranglerConfigPath,\n \"--secrets-file\",\n \".env\",\n ]\n : [\"wrangler\", \"deploy\", \"--config\", runtime.wranglerConfigPath];\n\n let deploy = await execa(\"npx\", deployArgs, { cwd }).catch((error) => error);\n if (deploy instanceof Error) {\n const combined = [String((deploy as { stdout?: string }).stdout ?? \"\"), String((deploy as { stderr?: string }).stderr ?? \"\"), deploy.message]\n .join(\"\\n\")\n .trim();\n if (isNamespaceAlreadyExistsError(combined)) {\n await ensureKvNamespaceBindingId(cwd, runtime.wranglerConfigPath);\n deploy = await execa(\"npx\", deployArgs, { cwd });\n } else {\n throw deploy;\n }\n }\n\n const deployStdout = [deploy.stdout, deploy.stderr]\n .filter(Boolean)\n .join(\"\\n\");\n\n const workerUrl = await resolveWorkerUrl(\n runtime.wranglerConfigPath,\n deployStdout,\n );\n\n const existingState = await readProjectState(cwd);\n\n await writeProjectState(cwd, {\n workerUrl,\n deployedAt: new Date().toISOString(),\n accountId: auth.accountId,\n agents: existingState?.agents ?? {},\n });\n\n return { workerUrl, accountId: auth.accountId };\n}\n","import { access, readFile } from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { createJiti } from \"jiti\";\n\nexport type AIProvider = \"openai\" | \"anthropic\" | \"openrouter\" | \"custom\";\n\nconst PROVIDER_SECRET_MAP: Record<AIProvider, string> = {\n openai: \"OPENAI_API_KEY\",\n anthropic: \"ANTHROPIC_API_KEY\",\n openrouter: \"OPENROUTER_API_KEY\",\n custom: \"CUSTOM_AI_API_KEY\",\n};\n\nfunction parseEnv(content: string): Record<string, string> {\n const env: Record<string, string> = {};\n for (const raw of content.split(/\\r?\\n/g)) {\n const line = raw.trim();\n if (!line || line.startsWith(\"#\")) continue;\n const idx = line.indexOf(\"=\");\n if (idx <= 0) continue;\n env[line.slice(0, idx).trim()] = line.slice(idx + 1);\n }\n return env;\n}\n\nexport async function resolveProviderFromConfig(cwd: string): Promise<AIProvider> {\n const configPath = join(cwd, \"kalp.config.ts\");\n await access(configPath, constants.F_OK);\n const jiti = createJiti(cwd, { interopDefault: true });\n const config = (await jiti.import(configPath)) as\n | { default?: { ai?: { provider?: AIProvider } }; ai?: { provider?: AIProvider } }\n | undefined;\n const provider = config?.default?.ai?.provider ?? config?.ai?.provider ?? \"openai\";\n return provider;\n}\n\nexport async function readDotEnv(cwd: string): Promise<Record<string, string>> {\n const envPath = join(cwd, \".env\");\n const content = await readFile(envPath, \"utf-8\").catch(() => \"\");\n return parseEnv(content);\n}\n\nexport function getRequiredSecretForProvider(provider: AIProvider): string {\n return PROVIDER_SECRET_MAP[provider];\n}\n"],"mappings":"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","names":["readFile","readFile"]}
|
|
@@ -13,6 +13,7 @@ import { scaffoldAgent } from "@kalphq/project";
|
|
|
13
13
|
|
|
14
14
|
// src/utils/ui.ts
|
|
15
15
|
import * as p from "@clack/prompts";
|
|
16
|
+
import { deriveLabelFromName } from "@kalphq/project";
|
|
16
17
|
async function promptTemplateSelection() {
|
|
17
18
|
const answer = await p.select({
|
|
18
19
|
message: "Choose an agent template:",
|
|
@@ -55,7 +56,15 @@ async function promptAgentDetails(opts) {
|
|
|
55
56
|
}),
|
|
56
57
|
...opts?.includeTemplate && {
|
|
57
58
|
template: () => promptTemplateSelection()
|
|
58
|
-
}
|
|
59
|
+
},
|
|
60
|
+
label: ({ results }) => p.text({
|
|
61
|
+
message: "Agent label? (display name)",
|
|
62
|
+
placeholder: deriveLabelFromName(results.name),
|
|
63
|
+
initialValue: deriveLabelFromName(results.name),
|
|
64
|
+
validate: (v) => {
|
|
65
|
+
if (!v.trim()) return "Agent label is required.";
|
|
66
|
+
}
|
|
67
|
+
})
|
|
59
68
|
},
|
|
60
69
|
{
|
|
61
70
|
onCancel: () => {
|
|
@@ -66,6 +75,7 @@ async function promptAgentDetails(opts) {
|
|
|
66
75
|
);
|
|
67
76
|
return {
|
|
68
77
|
name: answers.name,
|
|
78
|
+
label: answers.label,
|
|
69
79
|
template: answers.template
|
|
70
80
|
};
|
|
71
81
|
}
|
|
@@ -102,6 +112,7 @@ var create_default = defineCommand({
|
|
|
102
112
|
s.start(`Scaffolding agent ${pc.cyan(agentAnswers.name)}`);
|
|
103
113
|
await scaffoldAgent({
|
|
104
114
|
agentName: agentAnswers.name,
|
|
115
|
+
label: agentAnswers.label,
|
|
105
116
|
cwd,
|
|
106
117
|
template: agentAnswers.template
|
|
107
118
|
});
|
|
@@ -127,4 +138,4 @@ var create_default = defineCommand({
|
|
|
127
138
|
export {
|
|
128
139
|
create_default as default
|
|
129
140
|
};
|
|
130
|
-
//# sourceMappingURL=create-
|
|
141
|
+
//# sourceMappingURL=create-WU5JH6FP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/create.ts","../src/utils/ui.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport * as p from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { scaffoldAgent } from \"@kalphq/project\";\nimport { isProjectInitialized } from \"@/utils/fs\";\nimport { promptAgentDetails } from \"@/utils/ui\";\n\nconst LOGO = \"🦋\";\n\nexport default defineCommand({\n meta: { name: \"create\", description: \"Add a new agent to the project\" },\n async run() {\n const cwd = process.cwd();\n\n p.intro(`${LOGO} ${pc.bold(\"kalp create\")}`);\n\n // ── Check if project is initialized ─────────────────────────────────\n const needsInit = !(await isProjectInitialized(cwd));\n\n if (needsInit) {\n p.log.error(\"This is not a Kalp project.\");\n console.log(\"\");\n console.log(\" Run:\");\n console.log(` ${pc.cyan(\"npx create-kalp@latest\")}`);\n console.log(\"\");\n process.exit(1);\n }\n\n // ── Agent prompts ────────────────────────────────────────────────────\n const agentAnswers = await promptAgentDetails({ includeTemplate: true });\n\n // ── Check if agent already exists ────────────────────────────────────\n const agentDir = join(cwd, \"agents\", agentAnswers.name);\n if (existsSync(agentDir)) {\n p.log.error(`Agent \"${agentAnswers.name}\" already exists.`);\n console.log(\"\");\n console.log(` ${pc.dim(\"Location:\")} ${pc.cyan(agentDir)}`);\n console.log(\"\");\n console.log(\n ` ${pc.dim(\"Choose a different name or remove the existing agent.\")}`,\n );\n process.exit(1);\n }\n\n const s = p.spinner();\n\n // ── Scaffold agent ───────────────────────────────────────────────────\n s.start(`Scaffolding agent ${pc.cyan(agentAnswers.name)}`);\n await scaffoldAgent({\n agentName: agentAnswers.name,\n label: agentAnswers.label,\n cwd,\n template: agentAnswers.template,\n });\n s.stop(\n agentAnswers.template\n ? `Agent created (${agentAnswers.template} template)`\n : \"Agent created\",\n );\n\n p.note(\n [\n `${pc.dim(\"•\")} ${pc.cyan(`agents/${agentAnswers.name}/index.ts`)} ${pc.dim(\"— Agent entrypoint with config\")}`,\n `${pc.dim(\"•\")} ${pc.cyan(`agents/${agentAnswers.name}/contract/`)} ${pc.dim(\"— RPC contract definition\")}`,\n `${pc.dim(\"•\")} ${pc.cyan(`agents/${agentAnswers.name}/hooks/`)} ${pc.dim(\"— Lifecycle hooks (onInit, onTick)\")}`,\n `${pc.dim(\"•\")} ${pc.cyan(`agents/${agentAnswers.name}/routes/`)} ${pc.dim(\"— HTTP endpoints\")}`,\n `${pc.dim(\"•\")} ${pc.cyan(`agents/${agentAnswers.name}/steps/`)} ${pc.dim(\"— Reusable workflow steps\")}`,\n `${pc.dim(\"•\")} ${pc.cyan(`agents/${agentAnswers.name}/tools/`)} ${pc.dim(\"— Callable agent tools\")}`,\n ].join(\"\\n\"),\n \"Created\",\n );\n\n p.outro(\n `${LOGO} ${pc.green(`Agent ${pc.bold(agentAnswers.name)} is ready.`)}`,\n );\n },\n});\n","import * as p from \"@clack/prompts\";\nimport { deriveLabelFromName, type TemplateId } from \"@kalphq/project\";\n\n/**\n * Prompt user to select an agent template.\n */\nexport async function promptTemplateSelection(): Promise<TemplateId> {\n const answer = await p.select({\n message: \"Choose an agent template:\",\n options: [\n {\n value: \"researcher\",\n label: \"🔬 Researcher\",\n hint: \"Deterministic scheduling - pause 24h and auto-resume\",\n },\n {\n value: \"support\",\n label: \"🎧 Support Agent\",\n hint: \"Human-in-the-Loop - pause for days until resolved\",\n },\n {\n value: \"blank\",\n label: \"⬜ Blank\",\n hint: \"Minimal structure with modern Kalp v1 syntax\",\n },\n ],\n });\n\n if (p.isCancel(answer)) {\n p.cancel(\"Cancelled.\");\n process.exit(0);\n }\n\n return answer as TemplateId;\n}\n\nexport async function promptProjectName(opts?: {\n message?: string;\n placeholder?: string;\n allowCurrentDir?: boolean;\n}): Promise<string> {\n const message = opts?.message ?? \"Project name?\";\n const placeholder = opts?.placeholder ?? \"my-project\";\n const allowCurrentDir = opts?.allowCurrentDir ?? false;\n\n const answer = await p.text({\n message,\n placeholder,\n validate: (v) => {\n const value = v.trim();\n if (!value) return \"Project name is required.\";\n if (allowCurrentDir && value === \".\") return;\n if (!/^[a-z0-9-]+$/.test(value)) {\n return allowCurrentDir\n ? \"Use lowercase letters, numbers, and dashes only (or . for current directory).\"\n : \"Use lowercase letters, numbers, and dashes only.\";\n }\n },\n });\n\n if (p.isCancel(answer)) {\n p.cancel(\"Cancelled.\");\n process.exit(0);\n }\n\n return answer.trim();\n}\n\nexport async function promptAgentDetails(opts?: {\n includeTemplate?: boolean;\n}): Promise<{\n name: string;\n label: string;\n template?: TemplateId;\n}> {\n const answers = await p.group(\n {\n name: () =>\n p.text({\n message: \"Agent name?\",\n placeholder: \"my-agent\",\n validate: (v) => {\n if (!v.trim()) return \"Agent name is required.\";\n if (!/^[a-z0-9-]+$/.test(v)) {\n return \"Use lowercase letters, numbers, and dashes only.\";\n }\n },\n }),\n ...(opts?.includeTemplate && {\n template: () => promptTemplateSelection(),\n }),\n label: ({ results }) =>\n p.text({\n message: \"Agent label? (display name)\",\n placeholder: deriveLabelFromName(results.name as string),\n initialValue: deriveLabelFromName(results.name as string),\n validate: (v) => {\n if (!v.trim()) return \"Agent label is required.\";\n },\n }),\n },\n {\n onCancel: () => {\n p.cancel(\"Cancelled.\");\n process.exit(0);\n },\n },\n );\n\n return {\n name: answers.name,\n label: answers.label,\n template: answers.template as TemplateId | undefined,\n };\n}\n"],"mappings":"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","names":["p"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runInitialDeploy
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-MKVNPOVJ.js";
|
|
5
|
+
import "./chunk-5AEWO2OC.js";
|
|
6
6
|
import {
|
|
7
7
|
requireAuth
|
|
8
8
|
} from "./chunk-5RODADXW.js";
|
|
@@ -60,4 +60,4 @@ var deploy_default = defineCommand({
|
|
|
60
60
|
export {
|
|
61
61
|
deploy_default as default
|
|
62
62
|
};
|
|
63
|
-
//# sourceMappingURL=deploy-
|
|
63
|
+
//# sourceMappingURL=deploy-FVOKQP6K.js.map
|