@kaddo/cli 3.69.1 → 3.69.3
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/admin-server/index.js +450 -0
- package/dist/index.js +15 -3
- package/package.json +2 -3
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
// src/server.ts
|
|
2
|
+
import Fastify from "fastify";
|
|
3
|
+
import fastifyCookie from "@fastify/cookie";
|
|
4
|
+
import fastifyCors from "@fastify/cors";
|
|
5
|
+
import fastifyStatic from "@fastify/static";
|
|
6
|
+
import path from "path";
|
|
7
|
+
|
|
8
|
+
// src/session.ts
|
|
9
|
+
import { randomBytes } from "crypto";
|
|
10
|
+
var SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
11
|
+
var SessionManager = class {
|
|
12
|
+
constructor(storage) {
|
|
13
|
+
this.storage = storage;
|
|
14
|
+
}
|
|
15
|
+
storage;
|
|
16
|
+
activeSessionId = null;
|
|
17
|
+
createSession() {
|
|
18
|
+
this.storage.sessions.deleteExpired();
|
|
19
|
+
const id = randomBytes(32).toString("hex");
|
|
20
|
+
const now = /* @__PURE__ */ new Date();
|
|
21
|
+
const expiresAt = new Date(now.getTime() + SESSION_TTL_MS);
|
|
22
|
+
this.storage.sessions.create({
|
|
23
|
+
id,
|
|
24
|
+
createdAt: now.toISOString(),
|
|
25
|
+
expiresAt: expiresAt.toISOString()
|
|
26
|
+
});
|
|
27
|
+
this.activeSessionId = id;
|
|
28
|
+
return id;
|
|
29
|
+
}
|
|
30
|
+
validateSession(id) {
|
|
31
|
+
if (!id) return false;
|
|
32
|
+
const session = this.storage.sessions.findById(id);
|
|
33
|
+
if (!session) return false;
|
|
34
|
+
if (new Date(session.expiresAt) < /* @__PURE__ */ new Date()) {
|
|
35
|
+
this.storage.sessions.deleteById(id);
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
invalidateSession(id) {
|
|
41
|
+
this.storage.sessions.deleteById(id);
|
|
42
|
+
if (this.activeSessionId === id) this.activeSessionId = null;
|
|
43
|
+
}
|
|
44
|
+
invalidateAll() {
|
|
45
|
+
if (this.activeSessionId) {
|
|
46
|
+
this.storage.sessions.deleteById(this.activeSessionId);
|
|
47
|
+
this.activeSessionId = null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// src/core-adapter.ts
|
|
53
|
+
import {
|
|
54
|
+
buildProjectExplanation,
|
|
55
|
+
buildReadinessReport,
|
|
56
|
+
buildProjectRoute,
|
|
57
|
+
loadConfig,
|
|
58
|
+
loadMappedModules
|
|
59
|
+
} from "@kaddo/cli/core";
|
|
60
|
+
function getProjectSummary(dir) {
|
|
61
|
+
const config = loadConfig(dir);
|
|
62
|
+
if (!config) throw new CoreError("PROJECT_NOT_FOUND", "No Kaddo project was found.");
|
|
63
|
+
return {
|
|
64
|
+
name: config.project.name ?? "unknown",
|
|
65
|
+
state: config.project.state ?? "unknown",
|
|
66
|
+
structure: config.project.structure ?? "unknown",
|
|
67
|
+
language: config.project.language ?? "en",
|
|
68
|
+
teamSize: config.team.size ?? "unknown"
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function getKnowledgeSummary(dir) {
|
|
72
|
+
const exp = buildProjectExplanation(dir);
|
|
73
|
+
return {
|
|
74
|
+
layers: exp.layers.map((l) => ({ layer: l.layer, status: l.status })),
|
|
75
|
+
missing: exp.missingKnowledge
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function getWorkItemSummary(dir) {
|
|
79
|
+
const exp = buildProjectExplanation(dir);
|
|
80
|
+
return {
|
|
81
|
+
total: exp.workItems.total,
|
|
82
|
+
byState: exp.workItems.byState,
|
|
83
|
+
byType: exp.workItems.byType,
|
|
84
|
+
items: exp.workItems.items.map((i) => ({
|
|
85
|
+
id: i.id,
|
|
86
|
+
title: i.title,
|
|
87
|
+
type: i.type,
|
|
88
|
+
lifecycle: i.lifecycle,
|
|
89
|
+
initiative: i.initiative
|
|
90
|
+
}))
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function getModules(dir) {
|
|
94
|
+
const mapped = loadMappedModules(dir);
|
|
95
|
+
return {
|
|
96
|
+
modules: mapped.map((m) => ({
|
|
97
|
+
id: m.id,
|
|
98
|
+
role: m.role,
|
|
99
|
+
path: m.path,
|
|
100
|
+
available: m.available
|
|
101
|
+
}))
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function getProjectReadiness(dir) {
|
|
105
|
+
const report = buildReadinessReport(dir);
|
|
106
|
+
return {
|
|
107
|
+
overall: report.overall,
|
|
108
|
+
recommendedNextStep: {
|
|
109
|
+
label: report.nextStepRecommendation.label,
|
|
110
|
+
command: report.nextStepRecommendation.command
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function getProjectRoute(dir) {
|
|
115
|
+
const route = buildProjectRoute(dir);
|
|
116
|
+
return {
|
|
117
|
+
type: route.type,
|
|
118
|
+
completed: route.completed,
|
|
119
|
+
total: route.total,
|
|
120
|
+
progressPercent: route.progressPercent,
|
|
121
|
+
steps: route.steps.map((s) => ({
|
|
122
|
+
id: s.id,
|
|
123
|
+
label: s.label,
|
|
124
|
+
status: s.status,
|
|
125
|
+
...s.evidence ? { evidence: s.evidence } : {},
|
|
126
|
+
...s.reason ? { reason: s.reason } : {},
|
|
127
|
+
...s.command ? { command: s.command } : {}
|
|
128
|
+
}))
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function getFindings(dir) {
|
|
132
|
+
const exp = buildProjectExplanation(dir);
|
|
133
|
+
const items = [];
|
|
134
|
+
if (exp.missingKnowledge.length > 0) {
|
|
135
|
+
for (const m of exp.missingKnowledge) {
|
|
136
|
+
items.push({ level: "warning", message: `Missing: ${m}` });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (exp.duplicateWorkItems.length > 0) {
|
|
140
|
+
for (const d of exp.duplicateWorkItems) {
|
|
141
|
+
items.push({ level: "warning", message: `Possible duplicate Work Items: ${d.items.map((i) => i.id).join(", ")} (${d.reason})` });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const blocking = items.filter((i) => i.level === "blocking").length;
|
|
145
|
+
const warning = items.filter((i) => i.level === "warning").length;
|
|
146
|
+
const fyi = items.filter((i) => i.level === "fyi").length;
|
|
147
|
+
return { blocking, warning, fyi, items };
|
|
148
|
+
}
|
|
149
|
+
function getProjectOverview(dir) {
|
|
150
|
+
return {
|
|
151
|
+
project: getProjectSummary(dir),
|
|
152
|
+
knowledge: getKnowledgeSummary(dir),
|
|
153
|
+
workItems: getWorkItemSummary(dir),
|
|
154
|
+
modules: getModules(dir),
|
|
155
|
+
readiness: getProjectReadiness(dir),
|
|
156
|
+
route: getProjectRoute(dir),
|
|
157
|
+
findings: getFindings(dir)
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
var CoreError = class extends Error {
|
|
161
|
+
constructor(code, message) {
|
|
162
|
+
super(message);
|
|
163
|
+
this.code = code;
|
|
164
|
+
this.name = "CoreError";
|
|
165
|
+
}
|
|
166
|
+
code;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// src/server.ts
|
|
170
|
+
async function createAdminServer(opts) {
|
|
171
|
+
const { projectDir, storage, staticDir, host = "127.0.0.1", port = 4173 } = opts;
|
|
172
|
+
const app = Fastify({ logger: false });
|
|
173
|
+
const sessionManager = new SessionManager(storage);
|
|
174
|
+
await app.register(fastifyCookie);
|
|
175
|
+
await app.register(fastifyCors, {
|
|
176
|
+
origin: `http://${host}:${port}`,
|
|
177
|
+
credentials: true
|
|
178
|
+
});
|
|
179
|
+
if (staticDir) {
|
|
180
|
+
await app.register(fastifyStatic, {
|
|
181
|
+
root: path.resolve(staticDir),
|
|
182
|
+
prefix: "/",
|
|
183
|
+
wildcard: false
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
const sessionId = sessionManager.createSession();
|
|
187
|
+
app.addHook("onRequest", async (request, reply) => {
|
|
188
|
+
if (!request.url.startsWith("/api/")) return;
|
|
189
|
+
if (request.url.startsWith("/api/v1/admin/session")) return;
|
|
190
|
+
if (request.url.startsWith("/api/v1/admin/health")) return;
|
|
191
|
+
const cookieSession = request.cookies["kaddo-session"];
|
|
192
|
+
if (!sessionManager.validateSession(cookieSession)) {
|
|
193
|
+
reply.code(401).send({ error: { code: "SESSION_INVALID", message: "Invalid or expired session." } });
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
app.get("/api/v1/admin/health", async () => ({ status: "ok" }));
|
|
197
|
+
app.get("/api/v1/admin/session", async (_request, reply) => {
|
|
198
|
+
reply.setCookie("kaddo-session", sessionId, {
|
|
199
|
+
path: "/",
|
|
200
|
+
httpOnly: true,
|
|
201
|
+
sameSite: "strict",
|
|
202
|
+
maxAge: 86400
|
|
203
|
+
});
|
|
204
|
+
return { status: "active" };
|
|
205
|
+
});
|
|
206
|
+
const coreRoute = (handler) => {
|
|
207
|
+
return async () => {
|
|
208
|
+
try {
|
|
209
|
+
return handler(projectDir);
|
|
210
|
+
} catch (err) {
|
|
211
|
+
if (err instanceof CoreError) {
|
|
212
|
+
return { error: { code: err.code, message: err.message } };
|
|
213
|
+
}
|
|
214
|
+
throw err;
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
};
|
|
218
|
+
app.get("/api/v1/admin/overview", coreRoute(getProjectOverview));
|
|
219
|
+
app.get("/api/v1/admin/project", coreRoute(getProjectSummary));
|
|
220
|
+
app.get("/api/v1/admin/knowledge", coreRoute(getKnowledgeSummary));
|
|
221
|
+
app.get("/api/v1/admin/work-items", coreRoute(getWorkItemSummary));
|
|
222
|
+
app.get("/api/v1/admin/modules", coreRoute(getModules));
|
|
223
|
+
app.get("/api/v1/admin/readiness", coreRoute(getProjectReadiness));
|
|
224
|
+
app.get("/api/v1/admin/route", coreRoute(getProjectRoute));
|
|
225
|
+
app.get("/api/v1/admin/findings", coreRoute(getFindings));
|
|
226
|
+
if (staticDir) {
|
|
227
|
+
app.setNotFoundHandler(async (_request, reply) => {
|
|
228
|
+
return reply.sendFile("index.html");
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
app,
|
|
233
|
+
sessionId,
|
|
234
|
+
sessionManager,
|
|
235
|
+
start: async () => {
|
|
236
|
+
await app.listen({ host, port });
|
|
237
|
+
return `http://${host}:${port}`;
|
|
238
|
+
},
|
|
239
|
+
stop: async () => {
|
|
240
|
+
sessionManager.invalidateAll();
|
|
241
|
+
await app.close();
|
|
242
|
+
await storage.close();
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// src/storage/sqlite-storage.ts
|
|
248
|
+
import { DatabaseSync } from "sqlite";
|
|
249
|
+
var SQLiteAdminStorage = class {
|
|
250
|
+
constructor(dbPath) {
|
|
251
|
+
this.dbPath = dbPath;
|
|
252
|
+
this.db = new DatabaseSync(dbPath);
|
|
253
|
+
this.db.exec("PRAGMA journal_mode = WAL");
|
|
254
|
+
this.sessions = {
|
|
255
|
+
create: (session) => {
|
|
256
|
+
this.db.prepare(
|
|
257
|
+
"INSERT OR REPLACE INTO admin_sessions (id, created_at, expires_at) VALUES (?, ?, ?)"
|
|
258
|
+
).run(session.id, session.createdAt, session.expiresAt);
|
|
259
|
+
},
|
|
260
|
+
findById: (id) => {
|
|
261
|
+
const row = this.db.prepare(
|
|
262
|
+
"SELECT id, created_at, expires_at FROM admin_sessions WHERE id = ?"
|
|
263
|
+
).get(id);
|
|
264
|
+
if (!row) return void 0;
|
|
265
|
+
return { id: row.id, createdAt: row.created_at, expiresAt: row.expires_at };
|
|
266
|
+
},
|
|
267
|
+
deleteById: (id) => {
|
|
268
|
+
this.db.prepare("DELETE FROM admin_sessions WHERE id = ?").run(id);
|
|
269
|
+
},
|
|
270
|
+
deleteExpired: () => {
|
|
271
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
272
|
+
this.db.prepare("DELETE FROM admin_sessions WHERE expires_at < ?").run(now);
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
this.preferences = {
|
|
276
|
+
get: (key) => {
|
|
277
|
+
const row = this.db.prepare(
|
|
278
|
+
"SELECT value FROM admin_preferences WHERE key = ?"
|
|
279
|
+
).get(key);
|
|
280
|
+
return row?.value;
|
|
281
|
+
},
|
|
282
|
+
set: (key, value) => {
|
|
283
|
+
this.db.prepare(
|
|
284
|
+
"INSERT OR REPLACE INTO admin_preferences (key, value) VALUES (?, ?)"
|
|
285
|
+
).run(key, value);
|
|
286
|
+
},
|
|
287
|
+
delete: (key) => {
|
|
288
|
+
this.db.prepare("DELETE FROM admin_preferences WHERE key = ?").run(key);
|
|
289
|
+
},
|
|
290
|
+
all: () => {
|
|
291
|
+
return this.db.prepare("SELECT key, value FROM admin_preferences").all();
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
this.cache = {
|
|
295
|
+
get: (key) => {
|
|
296
|
+
const row = this.db.prepare(
|
|
297
|
+
"SELECT value, expires_at FROM admin_cache WHERE key = ?"
|
|
298
|
+
).get(key);
|
|
299
|
+
if (!row) return void 0;
|
|
300
|
+
if (row.expires_at && new Date(row.expires_at) < /* @__PURE__ */ new Date()) {
|
|
301
|
+
this.db.prepare("DELETE FROM admin_cache WHERE key = ?").run(key);
|
|
302
|
+
return void 0;
|
|
303
|
+
}
|
|
304
|
+
return row.value;
|
|
305
|
+
},
|
|
306
|
+
set: (key, value, ttlMs) => {
|
|
307
|
+
const expiresAt = ttlMs ? new Date(Date.now() + ttlMs).toISOString() : null;
|
|
308
|
+
this.db.prepare(
|
|
309
|
+
"INSERT OR REPLACE INTO admin_cache (key, value, expires_at) VALUES (?, ?, ?)"
|
|
310
|
+
).run(key, value, expiresAt);
|
|
311
|
+
},
|
|
312
|
+
delete: (key) => {
|
|
313
|
+
this.db.prepare("DELETE FROM admin_cache WHERE key = ?").run(key);
|
|
314
|
+
},
|
|
315
|
+
clear: () => {
|
|
316
|
+
this.db.exec("DELETE FROM admin_cache");
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
dbPath;
|
|
321
|
+
db;
|
|
322
|
+
sessions;
|
|
323
|
+
preferences;
|
|
324
|
+
cache;
|
|
325
|
+
async initialize() {
|
|
326
|
+
this.db.exec(`
|
|
327
|
+
CREATE TABLE IF NOT EXISTS admin_sessions (
|
|
328
|
+
id TEXT PRIMARY KEY,
|
|
329
|
+
created_at TEXT NOT NULL,
|
|
330
|
+
expires_at TEXT NOT NULL
|
|
331
|
+
);
|
|
332
|
+
CREATE TABLE IF NOT EXISTS admin_preferences (
|
|
333
|
+
key TEXT PRIMARY KEY,
|
|
334
|
+
value TEXT NOT NULL
|
|
335
|
+
);
|
|
336
|
+
CREATE TABLE IF NOT EXISTS admin_cache (
|
|
337
|
+
key TEXT PRIMARY KEY,
|
|
338
|
+
value TEXT NOT NULL,
|
|
339
|
+
expires_at TEXT
|
|
340
|
+
);
|
|
341
|
+
CREATE TABLE IF NOT EXISTS audit_events (
|
|
342
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
343
|
+
timestamp TEXT NOT NULL,
|
|
344
|
+
action TEXT NOT NULL,
|
|
345
|
+
detail TEXT
|
|
346
|
+
);
|
|
347
|
+
`);
|
|
348
|
+
}
|
|
349
|
+
async close() {
|
|
350
|
+
this.db.close();
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
// src/contracts/schemas.ts
|
|
355
|
+
import { z } from "zod";
|
|
356
|
+
var ProjectSummarySchema = z.object({
|
|
357
|
+
name: z.string(),
|
|
358
|
+
state: z.string(),
|
|
359
|
+
structure: z.string(),
|
|
360
|
+
language: z.string(),
|
|
361
|
+
teamSize: z.string()
|
|
362
|
+
});
|
|
363
|
+
var KnowledgeSummarySchema = z.object({
|
|
364
|
+
layers: z.array(z.object({
|
|
365
|
+
layer: z.string(),
|
|
366
|
+
status: z.string()
|
|
367
|
+
})),
|
|
368
|
+
missing: z.array(z.string())
|
|
369
|
+
});
|
|
370
|
+
var WorkItemSummarySchema = z.object({
|
|
371
|
+
total: z.number(),
|
|
372
|
+
byState: z.record(z.string(), z.number()),
|
|
373
|
+
byType: z.record(z.string(), z.number()),
|
|
374
|
+
items: z.array(z.object({
|
|
375
|
+
id: z.string(),
|
|
376
|
+
title: z.string(),
|
|
377
|
+
type: z.string(),
|
|
378
|
+
lifecycle: z.string(),
|
|
379
|
+
initiative: z.string()
|
|
380
|
+
}))
|
|
381
|
+
});
|
|
382
|
+
var ModuleSummarySchema = z.object({
|
|
383
|
+
modules: z.array(z.object({
|
|
384
|
+
id: z.string(),
|
|
385
|
+
role: z.string(),
|
|
386
|
+
path: z.string().optional(),
|
|
387
|
+
available: z.boolean()
|
|
388
|
+
}))
|
|
389
|
+
});
|
|
390
|
+
var ProjectReadinessSchema = z.object({
|
|
391
|
+
overall: z.string(),
|
|
392
|
+
recommendedNextStep: z.object({
|
|
393
|
+
label: z.string(),
|
|
394
|
+
command: z.string().optional()
|
|
395
|
+
})
|
|
396
|
+
});
|
|
397
|
+
var RouteStepSchema = z.object({
|
|
398
|
+
id: z.string(),
|
|
399
|
+
label: z.string(),
|
|
400
|
+
status: z.string(),
|
|
401
|
+
evidence: z.array(z.string()).optional(),
|
|
402
|
+
reason: z.string().optional(),
|
|
403
|
+
command: z.string().optional()
|
|
404
|
+
});
|
|
405
|
+
var ProjectRouteSchema = z.object({
|
|
406
|
+
type: z.string(),
|
|
407
|
+
completed: z.number(),
|
|
408
|
+
total: z.number(),
|
|
409
|
+
progressPercent: z.number(),
|
|
410
|
+
steps: z.array(RouteStepSchema)
|
|
411
|
+
});
|
|
412
|
+
var FindingsSummarySchema = z.object({
|
|
413
|
+
blocking: z.number(),
|
|
414
|
+
warning: z.number(),
|
|
415
|
+
fyi: z.number(),
|
|
416
|
+
items: z.array(z.object({
|
|
417
|
+
level: z.enum(["blocking", "warning", "fyi"]),
|
|
418
|
+
message: z.string()
|
|
419
|
+
}))
|
|
420
|
+
});
|
|
421
|
+
var ProjectOverviewSchema = z.object({
|
|
422
|
+
project: ProjectSummarySchema,
|
|
423
|
+
knowledge: KnowledgeSummarySchema,
|
|
424
|
+
workItems: WorkItemSummarySchema,
|
|
425
|
+
modules: ModuleSummarySchema,
|
|
426
|
+
readiness: ProjectReadinessSchema,
|
|
427
|
+
route: ProjectRouteSchema,
|
|
428
|
+
findings: FindingsSummarySchema
|
|
429
|
+
});
|
|
430
|
+
var ErrorResponseSchema = z.object({
|
|
431
|
+
error: z.object({
|
|
432
|
+
code: z.string(),
|
|
433
|
+
message: z.string()
|
|
434
|
+
})
|
|
435
|
+
});
|
|
436
|
+
export {
|
|
437
|
+
ErrorResponseSchema,
|
|
438
|
+
FindingsSummarySchema,
|
|
439
|
+
KnowledgeSummarySchema,
|
|
440
|
+
ModuleSummarySchema,
|
|
441
|
+
ProjectOverviewSchema,
|
|
442
|
+
ProjectReadinessSchema,
|
|
443
|
+
ProjectRouteSchema,
|
|
444
|
+
ProjectSummarySchema,
|
|
445
|
+
RouteStepSchema,
|
|
446
|
+
SQLiteAdminStorage,
|
|
447
|
+
SessionManager,
|
|
448
|
+
WorkItemSummarySchema,
|
|
449
|
+
createAdminServer
|
|
450
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -18510,8 +18510,8 @@ function isPortAvailable(port, host) {
|
|
|
18510
18510
|
function resolveStaticDir() {
|
|
18511
18511
|
const __dirname = path8.dirname(fileURLToPath2(import.meta.url));
|
|
18512
18512
|
const candidates = [
|
|
18513
|
-
// Bundled inside CLI
|
|
18514
|
-
path8.resolve(__dirname, "
|
|
18513
|
+
// Bundled inside CLI dist (npm install)
|
|
18514
|
+
path8.resolve(__dirname, "admin-dist"),
|
|
18515
18515
|
// Monorepo development
|
|
18516
18516
|
path8.resolve(__dirname, "..", "..", "admin", "dist"),
|
|
18517
18517
|
path8.resolve(__dirname, "..", "node_modules", "@kaddo", "admin", "dist")
|
|
@@ -18554,7 +18554,19 @@ async function runAdmin(opts = {}) {
|
|
|
18554
18554
|
console.error("Admin frontend not built. Run `pnpm -r build` first.");
|
|
18555
18555
|
process.exit(1);
|
|
18556
18556
|
}
|
|
18557
|
-
|
|
18557
|
+
let adminServer;
|
|
18558
|
+
try {
|
|
18559
|
+
const __dirname = path8.dirname(fileURLToPath2(import.meta.url));
|
|
18560
|
+
const bundled = path8.resolve(__dirname, "admin-server", "index.js");
|
|
18561
|
+
if (exists(bundled)) {
|
|
18562
|
+
adminServer = await import(bundled);
|
|
18563
|
+
} else {
|
|
18564
|
+
adminServer = await import("@kaddo/admin-server");
|
|
18565
|
+
}
|
|
18566
|
+
} catch {
|
|
18567
|
+
adminServer = await import("@kaddo/admin-server");
|
|
18568
|
+
}
|
|
18569
|
+
const { createAdminServer, SQLiteAdminStorage } = adminServer;
|
|
18558
18570
|
const dbDir = join(dir, ".kaddo", "admin");
|
|
18559
18571
|
ensureDir(dbDir);
|
|
18560
18572
|
const dbPath = join(dbDir, "admin.db");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaddo/cli",
|
|
3
|
-
"version": "3.69.
|
|
3
|
+
"version": "3.69.3",
|
|
4
4
|
"description": "Knowledge Driven Development toolkit",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -29,7 +29,6 @@
|
|
|
29
29
|
},
|
|
30
30
|
"files": [
|
|
31
31
|
"dist",
|
|
32
|
-
"dist/admin-dist",
|
|
33
32
|
"README.md",
|
|
34
33
|
"LICENSE"
|
|
35
34
|
],
|
|
@@ -37,7 +36,7 @@
|
|
|
37
36
|
"access": "public"
|
|
38
37
|
},
|
|
39
38
|
"scripts": {
|
|
40
|
-
"build": "tsup && node -e \"const fs=require('fs');
|
|
39
|
+
"build": "tsup && node -e \"const fs=require('fs');[['../admin/dist','dist/admin-dist'],['../admin-server/dist','dist/admin-server']].forEach(([s,d])=>{if(fs.existsSync(s)){fs.cpSync(s,d,{recursive:true})}})\"",
|
|
41
40
|
"dev": "tsup --watch",
|
|
42
41
|
"test": "vitest run",
|
|
43
42
|
"prepublishOnly": "npm run build"
|