theokit 0.74.5 → 0.75.0
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/{actions-virtual-module-MIQJEHKJ.js → actions-virtual-module-MIQPBAZW.js} +5 -5
- package/dist/{actions-virtual-module-4J7Z37Y4.js → actions-virtual-module-QEI6QPK4.js} +5 -5
- package/dist/adapters/agent-mount.js +1 -1
- package/dist/{agent-XPZUWTHR.js → agent-IIF6JUWX.js} +3 -3
- package/dist/{app-typed-client-AZMUYIYV.js → app-typed-client-CHSITA46.js} +5 -5
- package/dist/{app-typed-client-DSS23KDC.js → app-typed-client-XQJXF646.js} +5 -5
- package/dist/{build-F3O5LJHY.js → build-QIO4VAW2.js} +22 -87
- package/dist/build-QIO4VAW2.js.map +1 -0
- package/dist/{chunk-PZLH4WGU.js → chunk-2BMJQMTH.js} +5 -5
- package/dist/{chunk-44E7XIZC.js → chunk-3MKRDJQ2.js} +2 -2
- package/dist/{chunk-4ERYQBL6.js → chunk-4Z5XO4O4.js} +2 -2
- package/dist/{chunk-FPC6ZEEU.js → chunk-6RVWPEKK.js} +10 -10
- package/dist/{chunk-V7ISZGNS.js → chunk-7HGZ3CKL.js} +2 -2
- package/dist/{chunk-6R5F5YF2.js → chunk-A6UFN6QQ.js} +16 -11
- package/dist/{chunk-6R5F5YF2.js.map → chunk-A6UFN6QQ.js.map} +1 -1
- package/dist/{chunk-5KRMDP46.js → chunk-AHYOVVJ7.js} +13 -3
- package/dist/chunk-AHYOVVJ7.js.map +1 -0
- package/dist/{chunk-WR5B2XNT.js → chunk-FNAEKJHO.js} +2 -2
- package/dist/{chunk-HKF6YNY4.js → chunk-FU3LEX2I.js} +26 -12
- package/dist/chunk-FU3LEX2I.js.map +1 -0
- package/dist/{chunk-VD3BCME6.js → chunk-I5PDEWZZ.js} +2 -2
- package/dist/chunk-IWIRHUNV.js +96 -0
- package/dist/chunk-IWIRHUNV.js.map +1 -0
- package/dist/{chunk-U5PWXS3J.js → chunk-O5JZ6ROY.js} +13 -3
- package/dist/chunk-O5JZ6ROY.js.map +1 -0
- package/dist/{chunk-VOXLI66L.js → chunk-OZB2TKGJ.js} +2 -2
- package/dist/{chunk-ET2TAY3Z.js → chunk-RAUYMVUO.js} +279 -15
- package/dist/chunk-RAUYMVUO.js.map +1 -0
- package/dist/{chunk-XUAWD5HK.js → chunk-RKRFJRJ3.js} +10 -10
- package/dist/{chunk-DA3GGICE.js → chunk-RQKMY3JW.js} +2 -2
- package/dist/{chunk-D5KBBTVD.js → chunk-RY6D4EXL.js} +20 -13
- package/dist/chunk-RY6D4EXL.js.map +1 -0
- package/dist/cli/index.js +10 -10
- package/dist/{dev-TW6QD7F3.js → dev-J2XZIENF.js} +8 -8
- package/dist/{dev-emit-T3X6RR7M.js → dev-emit-AXTJK56H.js} +3 -3
- package/dist/{dev-emit-ZK5GCHXN.js → dev-emit-XAPVJBM4.js} +3 -3
- package/dist/{generate-EN6EDITF.js → generate-RW3NO3NR.js} +239 -141
- package/dist/generate-RW3NO3NR.js.map +1 -0
- package/dist/index.js +5 -5
- package/dist/{info-XURFOBRF.js → info-6NAUW5XY.js} +3 -3
- package/dist/{internal-api-XPT4GLYX.js → internal-api-A5HA7TYF.js} +5 -5
- package/dist/{internal-api-ATSPOXI2.js → internal-api-R7TTYMCY.js} +5 -5
- package/dist/{load-config-2DXLI7NW.js → load-config-CLFWJOXN.js} +3 -3
- package/dist/{mcp-LMV3NQEP.js → mcp-MWTG3LRA.js} +4 -4
- package/dist/{openapi-UJSUQPNT.js → openapi-RVFUXXCR.js} +5 -5
- package/dist/{preview-AMNBV2DP.js → preview-ML4CFUD6.js} +3 -3
- package/dist/{routes-ENMU4GAN.js → routes-SMNSI2ZX.js} +3 -3
- package/dist/server/agent/index.d.ts +99 -6
- package/dist/server/agent/index.js +9 -1
- package/dist/server/cron/index.js +2 -2
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +15 -7
- package/dist/server/index.js.map +1 -1
- package/dist/server/jobs/index.js +2 -2
- package/dist/server/scan/index.js +4 -4
- package/dist/{server-boundary-K4YQXDQT.js → server-boundary-HYLYGFZY.js} +5 -5
- package/dist/{server-boundary-JM72DQLA.js → server-boundary-ZT6HN7ON.js} +5 -5
- package/dist/{start-GAULIE5E.js → start-L5TGWGLU.js} +7 -7
- package/dist/vite-plugin/index.js +5 -5
- package/dist/{vite-plugin-4ZMBW3KV.js → vite-plugin-OJND2LU5.js} +8 -8
- package/package.json +2 -2
- package/dist/build-F3O5LJHY.js.map +0 -1
- package/dist/chunk-5KRMDP46.js.map +0 -1
- package/dist/chunk-D5KBBTVD.js.map +0 -1
- package/dist/chunk-ET2TAY3Z.js.map +0 -1
- package/dist/chunk-HKF6YNY4.js.map +0 -1
- package/dist/chunk-U5PWXS3J.js.map +0 -1
- package/dist/generate-EN6EDITF.js.map +0 -1
- /package/dist/{actions-virtual-module-MIQJEHKJ.js.map → actions-virtual-module-MIQPBAZW.js.map} +0 -0
- /package/dist/{actions-virtual-module-4J7Z37Y4.js.map → actions-virtual-module-QEI6QPK4.js.map} +0 -0
- /package/dist/{agent-XPZUWTHR.js.map → agent-IIF6JUWX.js.map} +0 -0
- /package/dist/{app-typed-client-AZMUYIYV.js.map → app-typed-client-CHSITA46.js.map} +0 -0
- /package/dist/{app-typed-client-DSS23KDC.js.map → app-typed-client-XQJXF646.js.map} +0 -0
- /package/dist/{chunk-PZLH4WGU.js.map → chunk-2BMJQMTH.js.map} +0 -0
- /package/dist/{chunk-44E7XIZC.js.map → chunk-3MKRDJQ2.js.map} +0 -0
- /package/dist/{chunk-4ERYQBL6.js.map → chunk-4Z5XO4O4.js.map} +0 -0
- /package/dist/{chunk-FPC6ZEEU.js.map → chunk-6RVWPEKK.js.map} +0 -0
- /package/dist/{chunk-V7ISZGNS.js.map → chunk-7HGZ3CKL.js.map} +0 -0
- /package/dist/{chunk-WR5B2XNT.js.map → chunk-FNAEKJHO.js.map} +0 -0
- /package/dist/{chunk-VD3BCME6.js.map → chunk-I5PDEWZZ.js.map} +0 -0
- /package/dist/{chunk-VOXLI66L.js.map → chunk-OZB2TKGJ.js.map} +0 -0
- /package/dist/{chunk-XUAWD5HK.js.map → chunk-RKRFJRJ3.js.map} +0 -0
- /package/dist/{chunk-DA3GGICE.js.map → chunk-RQKMY3JW.js.map} +0 -0
- /package/dist/{dev-TW6QD7F3.js.map → dev-J2XZIENF.js.map} +0 -0
- /package/dist/{dev-emit-T3X6RR7M.js.map → dev-emit-AXTJK56H.js.map} +0 -0
- /package/dist/{dev-emit-ZK5GCHXN.js.map → dev-emit-XAPVJBM4.js.map} +0 -0
- /package/dist/{info-XURFOBRF.js.map → info-6NAUW5XY.js.map} +0 -0
- /package/dist/{internal-api-XPT4GLYX.js.map → internal-api-A5HA7TYF.js.map} +0 -0
- /package/dist/{internal-api-ATSPOXI2.js.map → internal-api-R7TTYMCY.js.map} +0 -0
- /package/dist/{load-config-2DXLI7NW.js.map → load-config-CLFWJOXN.js.map} +0 -0
- /package/dist/{mcp-LMV3NQEP.js.map → mcp-MWTG3LRA.js.map} +0 -0
- /package/dist/{openapi-UJSUQPNT.js.map → openapi-RVFUXXCR.js.map} +0 -0
- /package/dist/{preview-AMNBV2DP.js.map → preview-ML4CFUD6.js.map} +0 -0
- /package/dist/{routes-ENMU4GAN.js.map → routes-SMNSI2ZX.js.map} +0 -0
- /package/dist/{server-boundary-K4YQXDQT.js.map → server-boundary-HYLYGFZY.js.map} +0 -0
- /package/dist/{server-boundary-JM72DQLA.js.map → server-boundary-ZT6HN7ON.js.map} +0 -0
- /package/dist/{start-GAULIE5E.js.map → start-L5TGWGLU.js.map} +0 -0
- /package/dist/{vite-plugin-4ZMBW3KV.js.map → vite-plugin-OJND2LU5.js.map} +0 -0
|
@@ -11,12 +11,12 @@ import {
|
|
|
11
11
|
} from "./chunk-KTMQUYED.js";
|
|
12
12
|
import {
|
|
13
13
|
theoPluginAsync
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-RKRFJRJ3.js";
|
|
15
|
+
import "./chunk-I5PDEWZZ.js";
|
|
16
16
|
import "./chunk-BDH5GKFZ.js";
|
|
17
17
|
import "./chunk-3PWQQWT6.js";
|
|
18
18
|
import "./chunk-FDOOBTXJ.js";
|
|
19
|
-
import "./chunk-
|
|
19
|
+
import "./chunk-RQKMY3JW.js";
|
|
20
20
|
import "./chunk-BINRCILF.js";
|
|
21
21
|
import "./chunk-FNJVSFEC.js";
|
|
22
22
|
import "./chunk-WSMLSIS5.js";
|
|
@@ -24,17 +24,17 @@ import "./chunk-MX63AWEK.js";
|
|
|
24
24
|
import "./chunk-C27VRUVN.js";
|
|
25
25
|
import "./chunk-7UZZHCRN.js";
|
|
26
26
|
import "./chunk-47MM2JUK.js";
|
|
27
|
-
import "./chunk-
|
|
28
|
-
import "./chunk-
|
|
27
|
+
import "./chunk-FNAEKJHO.js";
|
|
28
|
+
import "./chunk-FU3LEX2I.js";
|
|
29
29
|
import "./chunk-4WP7A7RX.js";
|
|
30
30
|
import "./chunk-Z7CJHDLS.js";
|
|
31
31
|
import {
|
|
32
32
|
loadConfig
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-OZB2TKGJ.js";
|
|
34
34
|
import {
|
|
35
35
|
loadEnv
|
|
36
36
|
} from "./chunk-3QPVEJ7D.js";
|
|
37
|
-
import "./chunk-
|
|
37
|
+
import "./chunk-O5JZ6ROY.js";
|
|
38
38
|
import "./chunk-NX3P5MLH.js";
|
|
39
39
|
import {
|
|
40
40
|
orchestrateDev
|
|
@@ -128,4 +128,4 @@ export {
|
|
|
128
128
|
devCommand,
|
|
129
129
|
startDevServer
|
|
130
130
|
};
|
|
131
|
-
//# sourceMappingURL=dev-
|
|
131
|
+
//# sourceMappingURL=dev-J2XZIENF.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
generateManifest
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-7HGZ3CKL.js";
|
|
4
|
+
import "./chunk-A6UFN6QQ.js";
|
|
5
5
|
import "./chunk-DV34VG3N.js";
|
|
6
6
|
import "./chunk-SOYOYGWY.js";
|
|
7
7
|
import "./chunk-ZWN3AODA.js";
|
|
@@ -339,4 +339,4 @@ export {
|
|
|
339
339
|
_resetInFlightForTests,
|
|
340
340
|
reEmitOpenApi
|
|
341
341
|
};
|
|
342
|
-
//# sourceMappingURL=dev-emit-
|
|
342
|
+
//# sourceMappingURL=dev-emit-AXTJK56H.js.map
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
} from "./chunk-47VNWTL4.js";
|
|
7
7
|
import {
|
|
8
8
|
generateManifest
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-FNAEKJHO.js";
|
|
10
|
+
import "./chunk-FU3LEX2I.js";
|
|
11
11
|
import "./chunk-4WP7A7RX.js";
|
|
12
12
|
import "./chunk-Z7CJHDLS.js";
|
|
13
13
|
|
|
@@ -41,4 +41,4 @@ export {
|
|
|
41
41
|
_resetInFlightForTests,
|
|
42
42
|
reEmitOpenApi
|
|
43
43
|
};
|
|
44
|
-
//# sourceMappingURL=dev-emit-
|
|
44
|
+
//# sourceMappingURL=dev-emit-XAPVJBM4.js.map
|
|
@@ -1,9 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import "tsx/esm";
|
|
3
|
+
import {
|
|
4
|
+
cronScanDirs,
|
|
5
|
+
isDiscoverableCronFile,
|
|
6
|
+
listCronFiles
|
|
7
|
+
} from "./chunk-IWIRHUNV.js";
|
|
8
|
+
import {
|
|
9
|
+
findAgentFile
|
|
10
|
+
} from "./chunk-FU3LEX2I.js";
|
|
11
|
+
import "./chunk-Z7CJHDLS.js";
|
|
12
|
+
import {
|
|
13
|
+
loadConfig
|
|
14
|
+
} from "./chunk-OZB2TKGJ.js";
|
|
15
|
+
import "./chunk-3QPVEJ7D.js";
|
|
16
|
+
import "./chunk-O5JZ6ROY.js";
|
|
17
|
+
import "./chunk-NX3P5MLH.js";
|
|
18
|
+
import "./chunk-L4V5V2TI.js";
|
|
19
|
+
import "./chunk-D2R5SJEL.js";
|
|
3
20
|
|
|
4
21
|
// src/cli/commands/generate.ts
|
|
5
22
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
6
|
-
import { resolve as
|
|
23
|
+
import { resolve as resolve4, dirname as dirname3 } from "path";
|
|
24
|
+
|
|
25
|
+
// src/cli/commands/generate-containment.ts
|
|
26
|
+
import { isAbsolute, relative, resolve, sep } from "path";
|
|
27
|
+
function isPathInside(cwd, filePath) {
|
|
28
|
+
if (filePath.includes("\0")) return false;
|
|
29
|
+
const fromRoot = relative(resolve(cwd), filePath);
|
|
30
|
+
return fromRoot !== "" && !isAbsolute(fromRoot) && fromRoot.split(sep)[0] !== "..";
|
|
31
|
+
}
|
|
32
|
+
function pathTraversalRefusal(cwd, filePath) {
|
|
33
|
+
if (isPathInside(cwd, filePath)) return void 0;
|
|
34
|
+
return {
|
|
35
|
+
status: "invalid_name",
|
|
36
|
+
message: `Path traversal denied: "${filePath}" is outside the project root ${resolve(cwd)}.`
|
|
37
|
+
};
|
|
38
|
+
}
|
|
7
39
|
|
|
8
40
|
// src/cli/commands/generate-policy-placeholder.ts
|
|
9
41
|
var UNDECIDED_POLICY_IDENT = "undecidedPolicy";
|
|
@@ -25,7 +57,7 @@ function undecidedPolicyDeclaration(routePath, what) {
|
|
|
25
57
|
|
|
26
58
|
// src/cli/commands/generate-resource.ts
|
|
27
59
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
28
|
-
import { resolve, dirname } from "path";
|
|
60
|
+
import { resolve as resolve2, dirname } from "path";
|
|
29
61
|
var ALLOWED_FIELD_TYPES = /* @__PURE__ */ new Set(["string", "text", "number", "boolean"]);
|
|
30
62
|
var RESERVED_FIELDS = /* @__PURE__ */ new Set(["id", "createdAt", "created_at"]);
|
|
31
63
|
function parseResourceFields(args) {
|
|
@@ -205,10 +237,10 @@ function generateResource(cwd, name, fieldArgs) {
|
|
|
205
237
|
} catch (err) {
|
|
206
238
|
return { status: "invalid_name", message: err instanceof Error ? err.message : String(err) };
|
|
207
239
|
}
|
|
208
|
-
const schemaPath =
|
|
209
|
-
const routeIndexPath =
|
|
210
|
-
const routeIdPath =
|
|
211
|
-
const testPath =
|
|
240
|
+
const schemaPath = resolve2(cwd, "server/db/schema.ts");
|
|
241
|
+
const routeIndexPath = resolve2(cwd, `server/routes/${name}/index.ts`);
|
|
242
|
+
const routeIdPath = resolve2(cwd, `server/routes/${name}/[id].ts`);
|
|
243
|
+
const testPath = resolve2(cwd, `tests/${name}.test.ts`);
|
|
212
244
|
if (!existsSync(schemaPath)) {
|
|
213
245
|
return {
|
|
214
246
|
status: "not_a_project",
|
|
@@ -239,6 +271,133 @@ function generateResource(cwd, name, fieldArgs) {
|
|
|
239
271
|
return { status: "created", filePath: routeIndexPath, kind: "resource", name };
|
|
240
272
|
}
|
|
241
273
|
|
|
274
|
+
// src/cli/commands/generate-schedule.ts
|
|
275
|
+
import { basename, dirname as dirname2, extname, relative as relative2, resolve as resolve3, sep as sep2 } from "path";
|
|
276
|
+
|
|
277
|
+
// src/server/cron/define-cron.ts
|
|
278
|
+
var NAME_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
279
|
+
var CRON_NAME_RULE = "Must be 1-64 chars, lowercase alphanumeric + hyphen, starting with [a-z0-9].";
|
|
280
|
+
function isValidCronName(name) {
|
|
281
|
+
return typeof name === "string" && NAME_RE.test(name);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// src/cli/commands/generate-schedule.ts
|
|
285
|
+
async function resolveScheduleTarget(cwd, name) {
|
|
286
|
+
const malformed = cronNameRefusal(name);
|
|
287
|
+
if (malformed !== void 0) return malformed;
|
|
288
|
+
let config;
|
|
289
|
+
try {
|
|
290
|
+
config = await loadConfig(cwd);
|
|
291
|
+
} catch (err) {
|
|
292
|
+
return {
|
|
293
|
+
status: "invalid_config",
|
|
294
|
+
message: `Cannot read ${resolve3(cwd, "theo.config.ts")}: ${err.message}`
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
const { agentsDir, serverDir } = config;
|
|
298
|
+
const agentsRoot = resolve3(cwd, agentsDir);
|
|
299
|
+
const cronDirs = cronScanDirs(cwd, serverDir, agentsDir);
|
|
300
|
+
const filePath = resolve3(cronDirs.schedules, `${name}.ts`);
|
|
301
|
+
const escaped = pathTraversalRefusal(cwd, filePath);
|
|
302
|
+
if (escaped !== void 0) return escaped;
|
|
303
|
+
const chatPath = findAgentFile(agentsRoot, "chat");
|
|
304
|
+
if (chatPath === void 0) {
|
|
305
|
+
return {
|
|
306
|
+
status: "agent_not_found",
|
|
307
|
+
message: `No "chat" agent in ${agentsRoot} (the build serves it from chat.{ts,tsx,js,jsx} or chat/index.{ts,tsx,js,jsx}). A schedule runs the chat agent; create it first.`
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
const taken = cronNameTaken(name, filePath, [cronDirs.crons, cronDirs.schedules]);
|
|
311
|
+
if (taken !== void 0) return taken;
|
|
312
|
+
return { filePath, content: generateScheduleTemplate(name, importSpecifier(filePath, chatPath)) };
|
|
313
|
+
}
|
|
314
|
+
function cronNameOf(name) {
|
|
315
|
+
return name.split("/").pop() ?? name;
|
|
316
|
+
}
|
|
317
|
+
function cronNameRefusal(name) {
|
|
318
|
+
const cronName = cronNameOf(name);
|
|
319
|
+
if (!isDiscoverableCronFile(`${cronName}.ts`)) {
|
|
320
|
+
return {
|
|
321
|
+
status: "invalid_name",
|
|
322
|
+
message: `Invalid schedule name "${name}": the build does not discover a cron file named "${cronName}.ts".`
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
if (!isValidCronName(cronName)) {
|
|
326
|
+
return {
|
|
327
|
+
status: "invalid_name",
|
|
328
|
+
message: `Invalid schedule name "${name}": its cron name "${cronName}" is one defineCron rejects. ${CRON_NAME_RULE}`
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
return void 0;
|
|
332
|
+
}
|
|
333
|
+
function cronNameTaken(name, filePath, cronDirs) {
|
|
334
|
+
const cronName = cronNameOf(name);
|
|
335
|
+
const clash = listCronFiles(cronDirs).find(
|
|
336
|
+
(path) => path !== filePath && basename(path, extname(path)) === cronName
|
|
337
|
+
);
|
|
338
|
+
if (clash === void 0) return void 0;
|
|
339
|
+
return {
|
|
340
|
+
status: "invalid_name",
|
|
341
|
+
message: `Invalid schedule name "${name}": the cron name "${cronName}" is already used by ${clash}. Cron names must be unique across server/crons/ and agents/schedules/.`
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
function importSpecifier(fromFile, toFile) {
|
|
345
|
+
const path = relative2(dirname2(fromFile), toFile).split(sep2).join("/").replace(/\.tsx?$/, ".js");
|
|
346
|
+
return path.startsWith(".") ? path : `./${path}`;
|
|
347
|
+
}
|
|
348
|
+
function generateScheduleTemplate(name, chatSpecifier) {
|
|
349
|
+
const base = cronNameOf(name);
|
|
350
|
+
return [
|
|
351
|
+
`import { defineCron } from 'theokit/server/cron'`,
|
|
352
|
+
`import { resolveProvider } from 'theokit/server/agent'`,
|
|
353
|
+
`import { streamAgentTurnInProcess } from '@theokit/agents'`,
|
|
354
|
+
``,
|
|
355
|
+
`import chat from '${chatSpecifier}'`,
|
|
356
|
+
``,
|
|
357
|
+
`/**`,
|
|
358
|
+
` * A scheduled agent run, a first-class TheoKit cron. \`theokit build\` discovers it and translates the`,
|
|
359
|
+
` * schedule to your deploy target's native cron; \`theokit start\` runs it in-process.`,
|
|
360
|
+
` *`,
|
|
361
|
+
` * Each fire is one model run of your \`chat\` agent, so it spends tokens. Nobody is present to approve`,
|
|
362
|
+
` * a gated tool, so the run uses the \`auto-reject\` posture: every approval is answered "no" and the`,
|
|
363
|
+
` * gated tool does not run.`,
|
|
364
|
+
` *`,
|
|
365
|
+
` * Schedules are UTC (https://crontab.guru). \`signal\` aborts when the scheduler stops.`,
|
|
366
|
+
` */`,
|
|
367
|
+
`export default defineCron('${base}', {`,
|
|
368
|
+
` schedule: '0 9 * * *', // every day at 09:00 UTC`,
|
|
369
|
+
` async handler({ traceId, scheduledAt, signal }) {`,
|
|
370
|
+
` let outcome = 'ok'`,
|
|
371
|
+
` try {`,
|
|
372
|
+
` const agent = chat as { model?: string; plugins?: readonly unknown[] }`,
|
|
373
|
+
` const { apiKey } = resolveProvider(agent.model, { plugins: agent.plugins })`,
|
|
374
|
+
` const run = streamAgentTurnInProcess(chat, apiKey, {`,
|
|
375
|
+
` message: \`Scheduled run "${base}" at \${scheduledAt.toISOString()}\`,`,
|
|
376
|
+
` signal,`,
|
|
377
|
+
` approvals: {`,
|
|
378
|
+
` kind: 'auto-reject',`,
|
|
379
|
+
` reason: 'unattended schedule "${base}": nobody is present to approve',`,
|
|
380
|
+
` },`,
|
|
381
|
+
` })`,
|
|
382
|
+
` for await (const chunk of run) {`,
|
|
383
|
+
` // The SDK can report a failed run as a chunk rather than a rejection.`,
|
|
384
|
+
` if (chunk.type === 'error') {`,
|
|
385
|
+
` throw new Error(\`[${base}] agent run failed: \${chunk.errorText ?? 'no error text'}\`)`,
|
|
386
|
+
` }`,
|
|
387
|
+
` }`,
|
|
388
|
+
` } catch (err) {`,
|
|
389
|
+
` outcome = \`failed: \${err instanceof Error ? err.message : String(err)}\``,
|
|
390
|
+
` throw err`,
|
|
391
|
+
` } finally {`,
|
|
392
|
+
` // One traced line per fire, failed fires included: the scheduler's own error line has no trace id.`,
|
|
393
|
+
` console.log(\`[${base}] fire \${outcome} at \${scheduledAt.toISOString()} (trace \${traceId})\`)`,
|
|
394
|
+
` }`,
|
|
395
|
+
` },`,
|
|
396
|
+
`})`,
|
|
397
|
+
``
|
|
398
|
+
].join("\n");
|
|
399
|
+
}
|
|
400
|
+
|
|
242
401
|
// src/cli/commands/generate-types.ts
|
|
243
402
|
var VALID_TYPES = [
|
|
244
403
|
"route",
|
|
@@ -268,16 +427,8 @@ var RESERVED_BASENAMES = /* @__PURE__ */ new Set([
|
|
|
268
427
|
"hasOwnProperty"
|
|
269
428
|
]);
|
|
270
429
|
function hasReservedSegment(name) {
|
|
271
|
-
const
|
|
272
|
-
return RESERVED_BASENAMES.has(
|
|
273
|
-
}
|
|
274
|
-
function isPathInside(cwd, targetSubpath) {
|
|
275
|
-
if (targetSubpath.includes("\0")) return false;
|
|
276
|
-
if (targetSubpath.startsWith("/") || targetSubpath.startsWith("\\")) return false;
|
|
277
|
-
const resolved = resolve2(cwd, targetSubpath);
|
|
278
|
-
const cwdResolved = resolve2(cwd);
|
|
279
|
-
const sep = process.platform === "win32" ? "\\" : "/";
|
|
280
|
-
return resolved === cwdResolved || resolved.startsWith(cwdResolved + sep);
|
|
430
|
+
const basename2 = name.includes("/") ? name.split("/").pop() ?? name : name;
|
|
431
|
+
return RESERVED_BASENAMES.has(basename2);
|
|
281
432
|
}
|
|
282
433
|
function toPascalCase(name) {
|
|
283
434
|
return name.split(/[-/]/).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
|
|
@@ -439,30 +590,6 @@ function generateSandboxTemplate(name) {
|
|
|
439
590
|
``
|
|
440
591
|
].join("\n");
|
|
441
592
|
}
|
|
442
|
-
function generateScheduleTemplate(name) {
|
|
443
|
-
const base = name.split("/").pop() ?? name;
|
|
444
|
-
return [
|
|
445
|
-
`import { defineCron } from 'theokit/server/cron'`,
|
|
446
|
-
``,
|
|
447
|
-
`/**`,
|
|
448
|
-
` * A scheduled agent run \u2014 a first-class TheoKit cron. \`theokit build\` discovers it automatically and`,
|
|
449
|
-
` * translates the schedule to your deploy target's native cron (Vercel / Cloudflare / AWS). No manual`,
|
|
450
|
-
` * scheduler to start. The handler is where you invoke your agent \u2014 POST to \`/api/agents/chat\`, or use`,
|
|
451
|
-
` * \`@theokit/sdk\`'s \`Agent\` with the same model + system prompt as \`agents/chat.ts\`.`,
|
|
452
|
-
` *`,
|
|
453
|
-
` * Schedules are UTC (https://crontab.guru). \`signal\` aborts when the scheduler stops.`,
|
|
454
|
-
` */`,
|
|
455
|
-
`export default defineCron('${base}', {`,
|
|
456
|
-
` schedule: '0 9 * * *', // every day at 09:00 UTC`,
|
|
457
|
-
` async handler({ traceId, scheduledAt, signal }) {`,
|
|
458
|
-
` void signal`,
|
|
459
|
-
` // Invoke your agent here \u2014 e.g. fetch your own \`/api/agents/chat\` endpoint, or call the SDK Agent.`,
|
|
460
|
-
` console.log(\`[${base}] fired at \${scheduledAt.toISOString()} (trace \${traceId})\`)`,
|
|
461
|
-
` },`,
|
|
462
|
-
`})`,
|
|
463
|
-
``
|
|
464
|
-
].join("\n");
|
|
465
|
-
}
|
|
466
593
|
function generateMemoryTemplate(_name) {
|
|
467
594
|
return [
|
|
468
595
|
`/**`,
|
|
@@ -482,71 +609,32 @@ function generateMemoryTemplate(_name) {
|
|
|
482
609
|
``
|
|
483
610
|
].join("\n");
|
|
484
611
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
case "schedule":
|
|
506
|
-
return {
|
|
507
|
-
filePath: resolve2(cwd, "agents/schedules", `${name}.ts`),
|
|
508
|
-
content: generateScheduleTemplate(name)
|
|
509
|
-
};
|
|
510
|
-
case "memory":
|
|
511
|
-
return {
|
|
512
|
-
filePath: resolve2(cwd, "agents/memory", `${name}.ts`),
|
|
513
|
-
content: generateMemoryTemplate(name)
|
|
514
|
-
};
|
|
515
|
-
case "route":
|
|
516
|
-
return {
|
|
517
|
-
filePath: resolve2(cwd, "server/routes", `${name}.ts`),
|
|
518
|
-
content: generateRouteTemplate(name)
|
|
519
|
-
};
|
|
520
|
-
case "action":
|
|
521
|
-
return {
|
|
522
|
-
filePath: resolve2(cwd, "server/actions", `${name}.ts`),
|
|
523
|
-
content: generateActionTemplate(name)
|
|
524
|
-
};
|
|
525
|
-
case "page":
|
|
526
|
-
return { filePath: resolve2(cwd, `app/${name}/page.tsx`), content: generatePageTemplate(name) };
|
|
527
|
-
case "ws":
|
|
528
|
-
return {
|
|
529
|
-
filePath: resolve2(cwd, "server/ws", `${name}.ts`),
|
|
530
|
-
content: generateWsTemplate(name)
|
|
531
|
-
};
|
|
532
|
-
case "controller":
|
|
533
|
-
return {
|
|
534
|
-
filePath: resolve2(cwd, "server/controllers", `${name}.controller.ts`),
|
|
535
|
-
content: generateControllerTemplate(name)
|
|
536
|
-
};
|
|
537
|
-
case "agent":
|
|
538
|
-
return {
|
|
539
|
-
filePath: resolve2(cwd, "server/agents", `${name}.agent.ts`),
|
|
540
|
-
content: generateAgentTemplate(name)
|
|
541
|
-
};
|
|
542
|
-
case "toolbox":
|
|
543
|
-
return {
|
|
544
|
-
filePath: resolve2(cwd, "server/toolboxes", `${name}.tools.ts`),
|
|
545
|
-
content: generateToolboxTemplate(name)
|
|
546
|
-
};
|
|
547
|
-
default:
|
|
548
|
-
return null;
|
|
612
|
+
var SINGLE_FILE_KINDS = {
|
|
613
|
+
// Agent-capability generators. These live UNDER `agents/` — they are facets of the agent domain,
|
|
614
|
+
// not standalone top-level concerns — and the folder-semantic scanner treats each as composition
|
|
615
|
+
// (never a phantom route).
|
|
616
|
+
workflow: { path: (name) => `agents/workflows/${name}.ts`, template: generateWorkflowTemplate },
|
|
617
|
+
eval: { path: (name) => `agents/evals/${name}.ts`, template: generateEvalTemplate },
|
|
618
|
+
sandbox: { path: (name) => `agents/sandbox/${name}.ts`, template: generateSandboxTemplate },
|
|
619
|
+
memory: { path: (name) => `agents/memory/${name}.ts`, template: generateMemoryTemplate },
|
|
620
|
+
route: { path: (name) => `server/routes/${name}.ts`, template: generateRouteTemplate },
|
|
621
|
+
action: { path: (name) => `server/actions/${name}.ts`, template: generateActionTemplate },
|
|
622
|
+
page: { path: (name) => `app/${name}/page.tsx`, template: generatePageTemplate },
|
|
623
|
+
ws: { path: (name) => `server/ws/${name}.ts`, template: generateWsTemplate },
|
|
624
|
+
controller: {
|
|
625
|
+
path: (name) => `server/controllers/${name}.controller.ts`,
|
|
626
|
+
template: generateControllerTemplate
|
|
627
|
+
},
|
|
628
|
+
agent: { path: (name) => `server/agents/${name}.agent.ts`, template: generateAgentTemplate },
|
|
629
|
+
toolbox: {
|
|
630
|
+
path: (name) => `server/toolboxes/${name}.tools.ts`,
|
|
631
|
+
template: generateToolboxTemplate
|
|
549
632
|
}
|
|
633
|
+
};
|
|
634
|
+
function resolveTemplate(cwd, kind, name) {
|
|
635
|
+
const spec = SINGLE_FILE_KINDS[kind];
|
|
636
|
+
if (spec === void 0) return null;
|
|
637
|
+
return { filePath: resolve4(cwd, spec.path(name)), content: spec.template(name) };
|
|
550
638
|
}
|
|
551
639
|
function generateActionTestTemplate(name) {
|
|
552
640
|
const camel = toCamelCase(name);
|
|
@@ -588,15 +676,17 @@ function generateWsTemplate(_name) {
|
|
|
588
676
|
``
|
|
589
677
|
].join("\n");
|
|
590
678
|
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
679
|
+
function isGeneratorType(value) {
|
|
680
|
+
return VALID_TYPES.includes(value);
|
|
681
|
+
}
|
|
682
|
+
function refuseOptions({ cwd, type, name }) {
|
|
683
|
+
if (!existsSync2(resolve4(cwd, "theo.config.ts")) && !existsSync2(resolve4(cwd, "theo.config.js"))) {
|
|
594
684
|
return {
|
|
595
685
|
status: "not_a_project",
|
|
596
686
|
message: "Not a Theo project. cwd has no theo.config.ts or theo.config.js"
|
|
597
687
|
};
|
|
598
688
|
}
|
|
599
|
-
if (!
|
|
689
|
+
if (!isGeneratorType(type)) {
|
|
600
690
|
return {
|
|
601
691
|
status: "invalid_kind",
|
|
602
692
|
message: `Invalid generator type "${type}". Available: ${VALID_TYPES.join(", ")}`
|
|
@@ -605,7 +695,7 @@ async function generate(opts) {
|
|
|
605
695
|
if (!name || !toKebabCase(name)) {
|
|
606
696
|
return {
|
|
607
697
|
status: "invalid_name",
|
|
608
|
-
message: `Invalid name "${name}". Use kebab-case: lowercase letters, numbers, hyphens
|
|
698
|
+
message: `Invalid name "${name}". Use kebab-case: lowercase letters, numbers, hyphens. Example: my-route`
|
|
609
699
|
};
|
|
610
700
|
}
|
|
611
701
|
if (hasReservedSegment(name)) {
|
|
@@ -614,25 +704,21 @@ async function generate(opts) {
|
|
|
614
704
|
message: `Reserved name "${name}" \u2014 basename collides with built-in identifier (index/constructor/__proto__/prototype/hasOwnProperty).`
|
|
615
705
|
};
|
|
616
706
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
status: "invalid_name",
|
|
629
|
-
message: `Path traversal denied: "${name}" would escape project root.`
|
|
630
|
-
};
|
|
631
|
-
}
|
|
707
|
+
return void 0;
|
|
708
|
+
}
|
|
709
|
+
async function resolveTarget(cwd, type, name) {
|
|
710
|
+
if (type === "schedule") return resolveScheduleTarget(cwd, name);
|
|
711
|
+
const target = resolveTemplate(cwd, type, name);
|
|
712
|
+
if (target === null) return { status: "invalid_kind", message: `Unknown type: ${type}` };
|
|
713
|
+
return target;
|
|
714
|
+
}
|
|
715
|
+
function writeTarget(cwd, type, name, { filePath, content }) {
|
|
716
|
+
const escaped = pathTraversalRefusal(cwd, filePath);
|
|
717
|
+
if (escaped !== void 0) return escaped;
|
|
632
718
|
if (existsSync2(filePath)) {
|
|
633
719
|
return { status: "already_exists", filePath, kind: type, name };
|
|
634
720
|
}
|
|
635
|
-
mkdirSync2(
|
|
721
|
+
mkdirSync2(dirname3(filePath), { recursive: true });
|
|
636
722
|
writeFileSync2(filePath, content);
|
|
637
723
|
if (type === "action") {
|
|
638
724
|
const testPath = filePath.replace(/\.ts$/, ".test.ts");
|
|
@@ -642,31 +728,43 @@ async function generate(opts) {
|
|
|
642
728
|
}
|
|
643
729
|
return { status: "created", filePath, kind: type, name };
|
|
644
730
|
}
|
|
731
|
+
async function generate(opts) {
|
|
732
|
+
const refused = refuseOptions(opts);
|
|
733
|
+
if (refused !== void 0) return refused;
|
|
734
|
+
const { cwd, name } = opts;
|
|
735
|
+
const kind = opts.type;
|
|
736
|
+
if (kind === "resource") {
|
|
737
|
+
return generateResource(cwd, name, opts.fields ?? []);
|
|
738
|
+
}
|
|
739
|
+
const resolved = await resolveTarget(cwd, kind, name);
|
|
740
|
+
if ("status" in resolved) return resolved;
|
|
741
|
+
return writeTarget(cwd, kind, name, resolved);
|
|
742
|
+
}
|
|
743
|
+
var CLI_REFUSALS = {
|
|
744
|
+
not_a_project: () => "Not a Theo project. Run this from a project root with theo.config.ts",
|
|
745
|
+
invalid_kind: (result) => result.message ?? "Invalid kind",
|
|
746
|
+
// `generate` returns invalid_name for a malformed name, a reserved name and a path that
|
|
747
|
+
// resolves outside the project; each message says which, so the CLI must not replace it.
|
|
748
|
+
invalid_name: (result, name) => result.message ?? `Invalid name "${name}"`,
|
|
749
|
+
invalid_config: (result) => result.message ?? "Invalid theo.config.ts",
|
|
750
|
+
agent_not_found: (result) => result.message ?? "No chat agent found"
|
|
751
|
+
};
|
|
645
752
|
async function generateCommand(type, name, fields) {
|
|
646
753
|
const result = await generate({ cwd: process.cwd(), type, name, fields });
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
throw new Error("Not a Theo project. Run this from a project root with theo.config.ts");
|
|
650
|
-
case "invalid_kind":
|
|
651
|
-
throw new Error(result.message ?? "Invalid kind");
|
|
652
|
-
case "invalid_name":
|
|
653
|
-
throw new Error(
|
|
654
|
-
`Invalid name "${name}". Use kebab-case: lowercase letters, numbers, hyphens. Example: my-route`
|
|
655
|
-
);
|
|
656
|
-
case "already_exists":
|
|
657
|
-
console.log(`
|
|
754
|
+
if (result.status === "already_exists") {
|
|
755
|
+
console.log(`
|
|
658
756
|
\u26A0 ${result.filePath} already exists. Skipping.
|
|
659
757
|
`);
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
console.log(`
|
|
758
|
+
} else if (result.status === "created") {
|
|
759
|
+
console.log(`
|
|
663
760
|
\u2713 Created ${type}: ${result.filePath}
|
|
664
761
|
`);
|
|
665
|
-
|
|
762
|
+
} else {
|
|
763
|
+
throw new Error(CLI_REFUSALS[result.status](result, name));
|
|
666
764
|
}
|
|
667
765
|
}
|
|
668
766
|
export {
|
|
669
767
|
generate,
|
|
670
768
|
generateCommand
|
|
671
769
|
};
|
|
672
|
-
//# sourceMappingURL=generate-
|
|
770
|
+
//# sourceMappingURL=generate-RW3NO3NR.js.map
|