@ekairos/domain 1.22.81-beta.development.0 → 1.22.83-beta.development.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/README.md +1 -2
- package/dist/cli/bin.d.ts.map +1 -1
- package/dist/cli/bin.js +4 -1
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/create-app.d.ts +5 -0
- package/dist/cli/create-app.d.ts.map +1 -1
- package/dist/cli/create-app.js +737 -66
- package/dist/cli/create-app.js.map +1 -1
- package/dist/cli/http.d.ts.map +1 -1
- package/dist/cli/http.js +1 -5
- package/dist/cli/http.js.map +1 -1
- package/dist/cli/server.d.ts.map +1 -1
- package/dist/cli/server.js +3 -2
- package/dist/cli/server.js.map +1 -1
- package/dist/cli/types.d.ts +1 -0
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/index.d.ts +108 -73
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +96 -51
- package/dist/index.js.map +1 -1
- package/dist/next.d.ts.map +1 -1
- package/dist/next.js +3 -2
- package/dist/next.js.map +1 -1
- package/dist/runtime-handle.d.ts +9 -9
- package/dist/runtime-handle.d.ts.map +1 -1
- package/dist/runtime-handle.js.map +1 -1
- package/dist/runtime.d.ts +6 -6
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +9 -8
- package/dist/runtime.js.map +1 -1
- package/package.json +7 -6
package/dist/cli/create-app.js
CHANGED
|
@@ -5,12 +5,15 @@ import { dirname, join, relative, resolve } from "node:path";
|
|
|
5
5
|
import { PlatformApi } from "@instantdb/platform";
|
|
6
6
|
import { i } from "@instantdb/core";
|
|
7
7
|
import { domain } from "../index.js";
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
8
|
+
export const CREATE_DOMAIN_APP_TEMPLATES = ["empty", "supply-chain", "agent"];
|
|
9
|
+
const TEMPLATE_NEXT_VERSION = "16.2.6";
|
|
10
|
+
const TEMPLATE_REACT_VERSION = "19.2.6";
|
|
11
|
+
const TEMPLATE_TYPESCRIPT_VERSION = "^6.0.3";
|
|
12
|
+
const TEMPLATE_INSTANT_VERSION = "1.0.39";
|
|
13
|
+
const TEMPLATE_INSTANT_REACT_VERSION = "1.0.39";
|
|
14
|
+
const TEMPLATE_WORKFLOW_VERSION = "5.0.0-beta.6";
|
|
15
|
+
const TEMPLATE_VERCEL_OIDC_VERSION = "3.4.1";
|
|
16
|
+
const TEMPLATE_EVENTS_VERSION = "1.22.82-beta.development.0";
|
|
14
17
|
function trimOrEmpty(value) {
|
|
15
18
|
return typeof value === "string" ? value.trim() : "";
|
|
16
19
|
}
|
|
@@ -69,8 +72,30 @@ async function readDomainPackageVersion() {
|
|
|
69
72
|
const parsed = JSON.parse(raw);
|
|
70
73
|
return trimOrEmpty(parsed.version) || "latest";
|
|
71
74
|
}
|
|
72
|
-
function
|
|
73
|
-
|
|
75
|
+
export function normalizeCreateAppTemplate(value) {
|
|
76
|
+
const normalized = trimOrEmpty(value);
|
|
77
|
+
if (!normalized)
|
|
78
|
+
return null;
|
|
79
|
+
if (CREATE_DOMAIN_APP_TEMPLATES.includes(normalized)) {
|
|
80
|
+
return normalized;
|
|
81
|
+
}
|
|
82
|
+
throw new Error(`Unsupported template: ${normalized}. Supported templates: ${CREATE_DOMAIN_APP_TEMPLATES.join(", ")}.`);
|
|
83
|
+
}
|
|
84
|
+
function resolveCreateAppTemplate(params) {
|
|
85
|
+
if (params.template) {
|
|
86
|
+
if (params.demo && params.template !== "supply-chain") {
|
|
87
|
+
throw new Error("--demo only supports --template=supply-chain.");
|
|
88
|
+
}
|
|
89
|
+
return params.template;
|
|
90
|
+
}
|
|
91
|
+
return params.demo ? "supply-chain" : "empty";
|
|
92
|
+
}
|
|
93
|
+
function createScaffoldSchema(template) {
|
|
94
|
+
if (template === "supply-chain")
|
|
95
|
+
return createSupplyChainScaffoldSchema();
|
|
96
|
+
if (template === "agent")
|
|
97
|
+
return createAgentScaffoldSchema();
|
|
98
|
+
return createEmptyScaffoldSchema();
|
|
74
99
|
}
|
|
75
100
|
function createEmptyScaffoldSchema() {
|
|
76
101
|
const scaffoldDomain = domain("app").withSchema({
|
|
@@ -178,8 +203,189 @@ function createSupplyChainScaffoldSchema() {
|
|
|
178
203
|
.withSchema({ entities: {}, links: {}, rooms: {} });
|
|
179
204
|
return scaffoldDomain.toInstantSchema();
|
|
180
205
|
}
|
|
181
|
-
function
|
|
182
|
-
return
|
|
206
|
+
function createAgentScaffoldSchema() {
|
|
207
|
+
return domain("events")
|
|
208
|
+
.withSchema({
|
|
209
|
+
entities: {
|
|
210
|
+
event_contexts: i.entity({
|
|
211
|
+
createdAt: i.date(),
|
|
212
|
+
updatedAt: i.date().optional(),
|
|
213
|
+
key: i.string().optional().indexed().unique(),
|
|
214
|
+
name: i.string().optional(),
|
|
215
|
+
status: i.string().optional().indexed(),
|
|
216
|
+
content: i.any().optional(),
|
|
217
|
+
reactor: i.json().optional(),
|
|
218
|
+
}),
|
|
219
|
+
event_items: i.entity({
|
|
220
|
+
channel: i.string().indexed(),
|
|
221
|
+
createdAt: i.date().indexed(),
|
|
222
|
+
type: i.string().optional().indexed(),
|
|
223
|
+
content: i.any().optional(),
|
|
224
|
+
status: i.string().optional().indexed(),
|
|
225
|
+
}),
|
|
226
|
+
event_executions: i.entity({
|
|
227
|
+
createdAt: i.date(),
|
|
228
|
+
updatedAt: i.date().optional(),
|
|
229
|
+
status: i.string().optional().indexed(),
|
|
230
|
+
workflowRunId: i.string().optional().indexed(),
|
|
231
|
+
activeStreamId: i.string().optional().indexed(),
|
|
232
|
+
activeStreamClientId: i.string().optional().indexed(),
|
|
233
|
+
lastStreamId: i.string().optional().indexed(),
|
|
234
|
+
lastStreamClientId: i.string().optional().indexed(),
|
|
235
|
+
}),
|
|
236
|
+
event_steps: i.entity({
|
|
237
|
+
createdAt: i.date().indexed(),
|
|
238
|
+
updatedAt: i.date().optional(),
|
|
239
|
+
status: i.string().optional().indexed(),
|
|
240
|
+
iteration: i.number().indexed(),
|
|
241
|
+
errorText: i.string().optional(),
|
|
242
|
+
streamId: i.string().optional().indexed(),
|
|
243
|
+
streamClientId: i.string().optional().indexed(),
|
|
244
|
+
streamStartedAt: i.date().optional().indexed(),
|
|
245
|
+
streamFinishedAt: i.date().optional().indexed(),
|
|
246
|
+
streamAbortReason: i.string().optional(),
|
|
247
|
+
}),
|
|
248
|
+
event_parts: i.entity({
|
|
249
|
+
key: i.string().unique().indexed(),
|
|
250
|
+
stepId: i.string().indexed(),
|
|
251
|
+
idx: i.number().indexed(),
|
|
252
|
+
type: i.string().optional().indexed(),
|
|
253
|
+
part: i.json().optional(),
|
|
254
|
+
metadata: i.json().optional(),
|
|
255
|
+
updatedAt: i.date().optional(),
|
|
256
|
+
}),
|
|
257
|
+
event_trace_events: i.entity({
|
|
258
|
+
key: i.string().unique().indexed(),
|
|
259
|
+
workflowRunId: i.string().indexed(),
|
|
260
|
+
seq: i.number().indexed(),
|
|
261
|
+
eventId: i.string().indexed(),
|
|
262
|
+
eventKind: i.string().indexed(),
|
|
263
|
+
eventAt: i.date().optional(),
|
|
264
|
+
ingestedAt: i.date().optional(),
|
|
265
|
+
orgId: i.string().optional().indexed(),
|
|
266
|
+
projectId: i.string().optional().indexed(),
|
|
267
|
+
contextKey: i.string().optional().indexed(),
|
|
268
|
+
contextId: i.string().optional().indexed(),
|
|
269
|
+
executionId: i.string().optional().indexed(),
|
|
270
|
+
stepId: i.string().optional().indexed(),
|
|
271
|
+
contextEventId: i.string().optional().indexed(),
|
|
272
|
+
toolCallId: i.string().optional().indexed(),
|
|
273
|
+
partKey: i.string().optional().indexed(),
|
|
274
|
+
partIdx: i.number().optional().indexed(),
|
|
275
|
+
spanId: i.string().optional().indexed(),
|
|
276
|
+
parentSpanId: i.string().optional().indexed(),
|
|
277
|
+
isDeleted: i.boolean().optional(),
|
|
278
|
+
aiProvider: i.string().optional().indexed(),
|
|
279
|
+
aiModel: i.string().optional().indexed(),
|
|
280
|
+
promptTokens: i.number().optional(),
|
|
281
|
+
promptTokensCached: i.number().optional(),
|
|
282
|
+
promptTokensUncached: i.number().optional(),
|
|
283
|
+
completionTokens: i.number().optional(),
|
|
284
|
+
totalTokens: i.number().optional(),
|
|
285
|
+
latencyMs: i.number().optional(),
|
|
286
|
+
cacheCostUsd: i.number().optional(),
|
|
287
|
+
computeCostUsd: i.number().optional(),
|
|
288
|
+
costUsd: i.number().optional(),
|
|
289
|
+
payload: i.any().optional(),
|
|
290
|
+
}),
|
|
291
|
+
event_trace_runs: i.entity({
|
|
292
|
+
workflowRunId: i.string().unique().indexed(),
|
|
293
|
+
orgId: i.string().optional().indexed(),
|
|
294
|
+
projectId: i.string().optional().indexed(),
|
|
295
|
+
firstEventAt: i.date().optional().indexed(),
|
|
296
|
+
lastEventAt: i.date().optional().indexed(),
|
|
297
|
+
lastIngestedAt: i.date().optional().indexed(),
|
|
298
|
+
eventsCount: i.number().optional(),
|
|
299
|
+
status: i.string().optional().indexed(),
|
|
300
|
+
payload: i.any().optional(),
|
|
301
|
+
}),
|
|
302
|
+
event_trace_spans: i.entity({
|
|
303
|
+
spanId: i.string().unique().indexed(),
|
|
304
|
+
parentSpanId: i.string().optional().indexed(),
|
|
305
|
+
workflowRunId: i.string().indexed(),
|
|
306
|
+
executionId: i.string().optional().indexed(),
|
|
307
|
+
stepId: i.string().optional().indexed(),
|
|
308
|
+
kind: i.string().optional().indexed(),
|
|
309
|
+
name: i.string().optional().indexed(),
|
|
310
|
+
status: i.string().optional().indexed(),
|
|
311
|
+
startedAt: i.date().optional().indexed(),
|
|
312
|
+
endedAt: i.date().optional().indexed(),
|
|
313
|
+
durationMs: i.number().optional(),
|
|
314
|
+
payload: i.any().optional(),
|
|
315
|
+
}),
|
|
316
|
+
document_documents: i.entity({
|
|
317
|
+
name: i.string().optional().indexed(),
|
|
318
|
+
mimeType: i.string().optional(),
|
|
319
|
+
size: i.number().optional(),
|
|
320
|
+
ownerId: i.string().optional().indexed(),
|
|
321
|
+
orgId: i.string().optional().indexed(),
|
|
322
|
+
createdAt: i.date().optional().indexed(),
|
|
323
|
+
processedAt: i.date().optional().indexed(),
|
|
324
|
+
updatedAt: i.date().optional(),
|
|
325
|
+
lastJobId: i.string().optional(),
|
|
326
|
+
content: i.json().optional(),
|
|
327
|
+
}),
|
|
328
|
+
},
|
|
329
|
+
links: {
|
|
330
|
+
contextItemsContext: {
|
|
331
|
+
forward: { on: "event_items", has: "one", label: "context" },
|
|
332
|
+
reverse: { on: "event_contexts", has: "many", label: "items" },
|
|
333
|
+
},
|
|
334
|
+
contextExecutionsContext: {
|
|
335
|
+
forward: { on: "event_executions", has: "one", label: "context" },
|
|
336
|
+
reverse: { on: "event_contexts", has: "many", label: "executions" },
|
|
337
|
+
},
|
|
338
|
+
contextCurrentExecution: {
|
|
339
|
+
forward: { on: "event_contexts", has: "one", label: "currentExecution" },
|
|
340
|
+
reverse: { on: "event_executions", has: "one", label: "currentOf" },
|
|
341
|
+
},
|
|
342
|
+
contextExecutionsTrigger: {
|
|
343
|
+
forward: { on: "event_executions", has: "one", label: "trigger" },
|
|
344
|
+
reverse: { on: "event_items", has: "many", label: "executionsAsTrigger" },
|
|
345
|
+
},
|
|
346
|
+
contextExecutionsReaction: {
|
|
347
|
+
forward: { on: "event_executions", has: "one", label: "reaction" },
|
|
348
|
+
reverse: { on: "event_items", has: "many", label: "executionsAsReaction" },
|
|
349
|
+
},
|
|
350
|
+
contextStepsExecution: {
|
|
351
|
+
forward: { on: "event_steps", has: "one", label: "execution" },
|
|
352
|
+
reverse: { on: "event_executions", has: "many", label: "steps" },
|
|
353
|
+
},
|
|
354
|
+
contextExecutionItems: {
|
|
355
|
+
forward: { on: "event_items", has: "one", label: "execution" },
|
|
356
|
+
reverse: { on: "event_executions", has: "many", label: "items" },
|
|
357
|
+
},
|
|
358
|
+
contextPartsStep: {
|
|
359
|
+
forward: { on: "event_parts", has: "one", label: "step" },
|
|
360
|
+
reverse: { on: "event_steps", has: "many", label: "parts" },
|
|
361
|
+
},
|
|
362
|
+
contextStepStream: {
|
|
363
|
+
forward: { on: "event_steps", has: "one", label: "stream" },
|
|
364
|
+
reverse: { on: "$streams", has: "many", label: "step" },
|
|
365
|
+
},
|
|
366
|
+
contextExecutionActiveStream: {
|
|
367
|
+
forward: { on: "event_executions", has: "one", label: "activeStream" },
|
|
368
|
+
reverse: { on: "$streams", has: "many", label: "activeOf" },
|
|
369
|
+
},
|
|
370
|
+
contextExecutionLastStream: {
|
|
371
|
+
forward: { on: "event_executions", has: "one", label: "lastStream" },
|
|
372
|
+
reverse: { on: "$streams", has: "many", label: "lastOf" },
|
|
373
|
+
},
|
|
374
|
+
documentFile: {
|
|
375
|
+
forward: { on: "document_documents", has: "one", label: "file" },
|
|
376
|
+
reverse: { on: "$files", has: "one", label: "document" },
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
rooms: {},
|
|
380
|
+
})
|
|
381
|
+
.toInstantSchema();
|
|
382
|
+
}
|
|
383
|
+
function createScaffoldPerms(template) {
|
|
384
|
+
if (template === "supply-chain")
|
|
385
|
+
return createSupplyChainScaffoldPerms();
|
|
386
|
+
if (template === "agent")
|
|
387
|
+
return createAgentScaffoldPerms();
|
|
388
|
+
return createEmptyScaffoldPerms();
|
|
183
389
|
}
|
|
184
390
|
function createEmptyScaffoldPerms() {
|
|
185
391
|
return {
|
|
@@ -209,6 +415,30 @@ function createSupplyChainScaffoldPerms() {
|
|
|
209
415
|
qualityControl_inspection: entityRules,
|
|
210
416
|
};
|
|
211
417
|
}
|
|
418
|
+
function createAgentScaffoldPerms() {
|
|
419
|
+
const entityRules = {
|
|
420
|
+
allow: {
|
|
421
|
+
view: "true",
|
|
422
|
+
create: "true",
|
|
423
|
+
update: "true",
|
|
424
|
+
delete: "false",
|
|
425
|
+
},
|
|
426
|
+
};
|
|
427
|
+
return {
|
|
428
|
+
attrs: {
|
|
429
|
+
allow: { create: "true" },
|
|
430
|
+
},
|
|
431
|
+
event_contexts: entityRules,
|
|
432
|
+
event_items: entityRules,
|
|
433
|
+
event_executions: entityRules,
|
|
434
|
+
event_steps: entityRules,
|
|
435
|
+
event_parts: entityRules,
|
|
436
|
+
event_trace_events: entityRules,
|
|
437
|
+
event_trace_runs: entityRules,
|
|
438
|
+
event_trace_spans: entityRules,
|
|
439
|
+
document_documents: entityRules,
|
|
440
|
+
};
|
|
441
|
+
}
|
|
212
442
|
function installCommandFor(packageManager) {
|
|
213
443
|
if (packageManager === "pnpm")
|
|
214
444
|
return "pnpm install";
|
|
@@ -556,8 +786,8 @@ async function provisionInstantApp(params) {
|
|
|
556
786
|
const created = await api.createApp({
|
|
557
787
|
title: `ekairos-${trimOrEmpty(params.directory.split(/[\\/]/).pop()) || "app"}`,
|
|
558
788
|
orgId: trimOrEmpty(params.orgId) || undefined,
|
|
559
|
-
schema: createScaffoldSchema(),
|
|
560
|
-
perms: createScaffoldPerms(),
|
|
789
|
+
schema: createScaffoldSchema(params.template),
|
|
790
|
+
perms: createScaffoldPerms(params.template),
|
|
561
791
|
});
|
|
562
792
|
const appId = trimOrEmpty(created?.app?.id);
|
|
563
793
|
const adminToken = trimOrEmpty(created?.app?.adminToken);
|
|
@@ -635,20 +865,27 @@ async function writeScaffoldFiles(targetDir, files) {
|
|
|
635
865
|
await writeFile(absolutePath, content, "utf8");
|
|
636
866
|
}
|
|
637
867
|
}
|
|
638
|
-
function
|
|
868
|
+
function resolveWorkspacePackageDependencyVersion(packageName, version, targetDir, workspacePath) {
|
|
639
869
|
const workspaceRoot = trimOrEmpty(workspacePath);
|
|
640
870
|
if (!workspaceRoot) {
|
|
641
871
|
return version;
|
|
642
872
|
}
|
|
643
|
-
const packageRoot = resolve(workspaceRoot, "packages/
|
|
873
|
+
const packageRoot = resolve(workspaceRoot, "packages", packageName.split("/").pop() || packageName);
|
|
644
874
|
const relativePath = toPosix(relative(targetDir, packageRoot));
|
|
645
875
|
if (!relativePath)
|
|
646
876
|
return "file:.";
|
|
647
877
|
const prefixed = relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
648
878
|
return `file:${prefixed}`;
|
|
649
879
|
}
|
|
880
|
+
function resolveDomainDependencyVersion(version, targetDir, workspacePath) {
|
|
881
|
+
return resolveWorkspacePackageDependencyVersion("@ekairos/domain", version, targetDir, workspacePath);
|
|
882
|
+
}
|
|
650
883
|
function buildNextTemplateFiles(params) {
|
|
651
|
-
const
|
|
884
|
+
const workspaceRoot = trimOrEmpty(params.workspacePath);
|
|
885
|
+
const domainDependency = params.template === "agent" && !workspaceRoot
|
|
886
|
+
? TEMPLATE_EVENTS_VERSION
|
|
887
|
+
: resolveDomainDependencyVersion(params.domainVersion, params.targetDir, params.workspacePath);
|
|
888
|
+
const eventsDependency = resolveWorkspacePackageDependencyVersion("@ekairos/events", TEMPLATE_EVENTS_VERSION, params.targetDir, params.workspacePath);
|
|
652
889
|
const packageJson = {
|
|
653
890
|
name: trimOrEmpty(params.targetDir.split(/[\\/]/).pop()) || "ekairos-app",
|
|
654
891
|
private: true,
|
|
@@ -662,6 +899,7 @@ function buildNextTemplateFiles(params) {
|
|
|
662
899
|
},
|
|
663
900
|
dependencies: {
|
|
664
901
|
"@ekairos/domain": domainDependency,
|
|
902
|
+
"@vercel/oidc": TEMPLATE_VERCEL_OIDC_VERSION,
|
|
665
903
|
"@instantdb/admin": TEMPLATE_INSTANT_VERSION,
|
|
666
904
|
"@instantdb/core": TEMPLATE_INSTANT_VERSION,
|
|
667
905
|
"@instantdb/react": TEMPLATE_INSTANT_REACT_VERSION,
|
|
@@ -669,6 +907,7 @@ function buildNextTemplateFiles(params) {
|
|
|
669
907
|
react: TEMPLATE_REACT_VERSION,
|
|
670
908
|
"react-dom": TEMPLATE_REACT_VERSION,
|
|
671
909
|
workflow: TEMPLATE_WORKFLOW_VERSION,
|
|
910
|
+
zod: "^4.3.6",
|
|
672
911
|
},
|
|
673
912
|
devDependencies: {
|
|
674
913
|
"@types/node": "^24.5.0",
|
|
@@ -682,7 +921,21 @@ function buildNextTemplateFiles(params) {
|
|
|
682
921
|
? "yarn@1"
|
|
683
922
|
: undefined,
|
|
684
923
|
};
|
|
685
|
-
if (
|
|
924
|
+
if (params.template === "agent") {
|
|
925
|
+
;
|
|
926
|
+
packageJson.dependencies["@ekairos/events"] = eventsDependency;
|
|
927
|
+
if (params.packageManager === "pnpm") {
|
|
928
|
+
;
|
|
929
|
+
packageJson.pnpm = {
|
|
930
|
+
overrides: {
|
|
931
|
+
"@ekairos/domain": domainDependency,
|
|
932
|
+
"@instantdb/admin": TEMPLATE_INSTANT_VERSION,
|
|
933
|
+
"@instantdb/core": TEMPLATE_INSTANT_VERSION,
|
|
934
|
+
},
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
if (params.template === "empty") {
|
|
686
939
|
return {
|
|
687
940
|
".gitignore": [".next", "node_modules", ".env.local", ".workflow-data"].join("\n"),
|
|
688
941
|
".env.example": [
|
|
@@ -750,14 +1003,16 @@ function buildNextTemplateFiles(params) {
|
|
|
750
1003
|
' "moduleResolution": "bundler",',
|
|
751
1004
|
' "resolveJsonModule": true,',
|
|
752
1005
|
' "isolatedModules": true,',
|
|
753
|
-
' "jsx": "
|
|
1006
|
+
' "jsx": "react-jsx",',
|
|
754
1007
|
' "incremental": true,',
|
|
755
|
-
' "baseUrl": ".",',
|
|
756
1008
|
' "paths": {',
|
|
757
1009
|
' "@/*": ["./src/*"]',
|
|
758
|
-
" }",
|
|
1010
|
+
" },",
|
|
1011
|
+
' "plugins": [',
|
|
1012
|
+
' { "name": "next" }',
|
|
1013
|
+
" ]",
|
|
759
1014
|
" },",
|
|
760
|
-
' "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],',
|
|
1015
|
+
' "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts"],',
|
|
761
1016
|
' "exclude": ["node_modules"]',
|
|
762
1017
|
"}",
|
|
763
1018
|
].join("\n"),
|
|
@@ -919,6 +1174,398 @@ function buildNextTemplateFiles(params) {
|
|
|
919
1174
|
].join("\n"),
|
|
920
1175
|
};
|
|
921
1176
|
}
|
|
1177
|
+
if (params.template === "agent") {
|
|
1178
|
+
return {
|
|
1179
|
+
".gitignore": [".next", "node_modules", ".env.local", ".workflow-data"].join("\n"),
|
|
1180
|
+
".env.example": [
|
|
1181
|
+
"NEXT_PUBLIC_INSTANT_APP_ID=",
|
|
1182
|
+
"INSTANT_ADMIN_TOKEN=",
|
|
1183
|
+
"",
|
|
1184
|
+
"# Optional: use this only while provisioning new apps with the CLI.",
|
|
1185
|
+
"INSTANT_PERSONAL_ACCESS_TOKEN=",
|
|
1186
|
+
].join("\n"),
|
|
1187
|
+
"DOMAIN.md": [
|
|
1188
|
+
"# Ekairos Agent Template",
|
|
1189
|
+
"",
|
|
1190
|
+
"This app is the minimal loop for Ekairos event contexts:",
|
|
1191
|
+
"",
|
|
1192
|
+
"1. create the app",
|
|
1193
|
+
"2. start an agent context through `/api/agent/react`",
|
|
1194
|
+
"3. open the Instant app in Workbench v2",
|
|
1195
|
+
"4. iterate on `src/agent.ts`",
|
|
1196
|
+
"",
|
|
1197
|
+
"The scaffold uses the canonical `@ekairos/events` schema so Workbench v2 can inspect `event_contexts`.",
|
|
1198
|
+
"It includes an Ekairos registry alias so domain UI components can be installed with shadcn and use `@ekairos/events` directly.",
|
|
1199
|
+
].join("\n"),
|
|
1200
|
+
"components.json": [
|
|
1201
|
+
"{",
|
|
1202
|
+
' "$schema": "https://ui.shadcn.com/schema.json",',
|
|
1203
|
+
' "style": "default",',
|
|
1204
|
+
' "rsc": false,',
|
|
1205
|
+
' "tsx": true,',
|
|
1206
|
+
' "tailwind": {',
|
|
1207
|
+
' "config": "",',
|
|
1208
|
+
' "css": "src/app/globals.css",',
|
|
1209
|
+
' "baseColor": "zinc",',
|
|
1210
|
+
' "cssVariables": true,',
|
|
1211
|
+
' "prefix": ""',
|
|
1212
|
+
" },",
|
|
1213
|
+
' "iconLibrary": "lucide",',
|
|
1214
|
+
' "aliases": {',
|
|
1215
|
+
' "components": "@/components",',
|
|
1216
|
+
' "utils": "@/lib/utils",',
|
|
1217
|
+
' "ui": "@/components/ui",',
|
|
1218
|
+
' "lib": "@/lib",',
|
|
1219
|
+
' "hooks": "@/hooks"',
|
|
1220
|
+
" },",
|
|
1221
|
+
' "registries": {',
|
|
1222
|
+
' "@ekairos": "https://registry.ekairos.dev/r/{name}.json"',
|
|
1223
|
+
" }",
|
|
1224
|
+
"}",
|
|
1225
|
+
].join("\n"),
|
|
1226
|
+
"instant.schema.ts": [
|
|
1227
|
+
'import { eventsDomain } from "@ekairos/events/schema";',
|
|
1228
|
+
"",
|
|
1229
|
+
"const schema = eventsDomain.toInstantSchema();",
|
|
1230
|
+
"",
|
|
1231
|
+
"export default schema;",
|
|
1232
|
+
].join("\n"),
|
|
1233
|
+
"next-env.d.ts": [
|
|
1234
|
+
'/// <reference types="next" />',
|
|
1235
|
+
'/// <reference types="next/image-types/global" />',
|
|
1236
|
+
"",
|
|
1237
|
+
"// This file is managed by Next.js.",
|
|
1238
|
+
].join("\n"),
|
|
1239
|
+
"next.config.ts": [
|
|
1240
|
+
'import type { NextConfig } from "next";',
|
|
1241
|
+
'import { withWorkflow } from "workflow/next";',
|
|
1242
|
+
"",
|
|
1243
|
+
"const nextConfig: NextConfig = {",
|
|
1244
|
+
" transpilePackages: [\"@ekairos/domain\", \"@ekairos/events\"],",
|
|
1245
|
+
"};",
|
|
1246
|
+
"",
|
|
1247
|
+
"export default withWorkflow(nextConfig) as NextConfig;",
|
|
1248
|
+
].join("\n"),
|
|
1249
|
+
"package.json": `${JSON.stringify(packageJson, null, 2)}\n`,
|
|
1250
|
+
"tsconfig.json": [
|
|
1251
|
+
"{",
|
|
1252
|
+
' "compilerOptions": {',
|
|
1253
|
+
' "target": "ES2022",',
|
|
1254
|
+
' "lib": ["dom", "dom.iterable", "es2022"],',
|
|
1255
|
+
' "allowJs": false,',
|
|
1256
|
+
' "skipLibCheck": true,',
|
|
1257
|
+
' "strict": true,',
|
|
1258
|
+
' "noEmit": true,',
|
|
1259
|
+
' "esModuleInterop": true,',
|
|
1260
|
+
' "module": "esnext",',
|
|
1261
|
+
' "moduleResolution": "bundler",',
|
|
1262
|
+
' "resolveJsonModule": true,',
|
|
1263
|
+
' "isolatedModules": true,',
|
|
1264
|
+
' "jsx": "react-jsx",',
|
|
1265
|
+
' "incremental": true,',
|
|
1266
|
+
' "paths": {',
|
|
1267
|
+
' "@/*": ["./src/*"]',
|
|
1268
|
+
" },",
|
|
1269
|
+
' "plugins": [',
|
|
1270
|
+
' { "name": "next" }',
|
|
1271
|
+
" ]",
|
|
1272
|
+
" },",
|
|
1273
|
+
' "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts"],',
|
|
1274
|
+
' "exclude": ["node_modules"]',
|
|
1275
|
+
"}",
|
|
1276
|
+
].join("\n"),
|
|
1277
|
+
"src/app/globals.css": [
|
|
1278
|
+
":root {",
|
|
1279
|
+
" color-scheme: light;",
|
|
1280
|
+
" --background: #f7f8f6;",
|
|
1281
|
+
" --foreground: #171a18;",
|
|
1282
|
+
" --muted: #626a63;",
|
|
1283
|
+
" --border: #d9ded7;",
|
|
1284
|
+
" --surface: #ffffff;",
|
|
1285
|
+
" --accent: #26715f;",
|
|
1286
|
+
"}",
|
|
1287
|
+
"* { box-sizing: border-box; }",
|
|
1288
|
+
"html, body { margin: 0; min-height: 100%; }",
|
|
1289
|
+
"body { min-height: 100dvh; background: var(--background); color: var(--foreground); font-family: \"Segoe UI\", sans-serif; }",
|
|
1290
|
+
"button, textarea, input { font: inherit; }",
|
|
1291
|
+
"main { width: min(980px, calc(100% - 32px)); margin: 0 auto; padding: 44px 0; }",
|
|
1292
|
+
".shell { display: grid; gap: 22px; }",
|
|
1293
|
+
".eyebrow { color: var(--accent); font-size: 12px; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; }",
|
|
1294
|
+
"h1 { max-width: 760px; margin: 0; font-size: clamp(2.1rem, 5vw, 4.4rem); line-height: 1; }",
|
|
1295
|
+
"p { max-width: 68ch; margin: 0; color: var(--muted); line-height: 1.65; }",
|
|
1296
|
+
".panel { display: grid; gap: 16px; border: 1px solid var(--border); background: var(--surface); padding: 20px; }",
|
|
1297
|
+
".grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border: 1px solid var(--border); }",
|
|
1298
|
+
".grid div { display: grid; gap: 6px; padding: 14px; border-right: 1px solid var(--border); }",
|
|
1299
|
+
".grid div:last-child { border-right: 0; }",
|
|
1300
|
+
".grid span { color: var(--muted); font-size: 11px; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; }",
|
|
1301
|
+
".grid strong { font-size: 1rem; overflow-wrap: anywhere; }",
|
|
1302
|
+
"textarea { width: 100%; min-height: 120px; resize: vertical; border: 1px solid var(--border); padding: 12px; }",
|
|
1303
|
+
"button { width: fit-content; border: 0; background: var(--accent); color: white; padding: 10px 14px; font-weight: 700; cursor: pointer; }",
|
|
1304
|
+
"button:disabled { cursor: wait; opacity: 0.65; }",
|
|
1305
|
+
"pre { overflow: auto; margin: 0; border: 1px solid var(--border); background: #f2f4f1; padding: 14px; }",
|
|
1306
|
+
"code { font-family: \"Cascadia Code\", monospace; }",
|
|
1307
|
+
"@media (max-width: 720px) { .grid { grid-template-columns: 1fr; } .grid div { border-right: 0; border-bottom: 1px solid var(--border); } }",
|
|
1308
|
+
].join("\n"),
|
|
1309
|
+
"src/app/layout.tsx": [
|
|
1310
|
+
'import "./globals.css";',
|
|
1311
|
+
'import type { ReactNode } from "react";',
|
|
1312
|
+
"",
|
|
1313
|
+
"export const metadata = {",
|
|
1314
|
+
' title: "Ekairos Agent",',
|
|
1315
|
+
' description: "Scaffolded Ekairos agent context app",',
|
|
1316
|
+
"};",
|
|
1317
|
+
"",
|
|
1318
|
+
"export default function RootLayout({ children }: { children: ReactNode }) {",
|
|
1319
|
+
" return (",
|
|
1320
|
+
' <html lang="en">',
|
|
1321
|
+
" <body>{children}</body>",
|
|
1322
|
+
" </html>",
|
|
1323
|
+
" );",
|
|
1324
|
+
"}",
|
|
1325
|
+
].join("\n"),
|
|
1326
|
+
"src/app/page.tsx": [
|
|
1327
|
+
'import AgentWorkbench from "./agent-workbench";',
|
|
1328
|
+
"",
|
|
1329
|
+
'export const dynamic = "force-dynamic";',
|
|
1330
|
+
"",
|
|
1331
|
+
"export default function HomePage() {",
|
|
1332
|
+
" return (",
|
|
1333
|
+
" <main>",
|
|
1334
|
+
' <section className="shell">',
|
|
1335
|
+
' <div className="eyebrow">Ekairos Agent Template</div>',
|
|
1336
|
+
" <h1>Start a context, inspect it in Workbench v2, iterate.</h1>",
|
|
1337
|
+
" <p>",
|
|
1338
|
+
" This template writes canonical @ekairos/events rows and returns the context id immediately.",
|
|
1339
|
+
" </p>",
|
|
1340
|
+
" <AgentWorkbench />",
|
|
1341
|
+
" </section>",
|
|
1342
|
+
" </main>",
|
|
1343
|
+
" );",
|
|
1344
|
+
"}",
|
|
1345
|
+
].join("\n"),
|
|
1346
|
+
"src/app/agent-workbench.tsx": [
|
|
1347
|
+
'"use client";',
|
|
1348
|
+
"",
|
|
1349
|
+
"import { useMemo, useState } from \"react\";",
|
|
1350
|
+
"",
|
|
1351
|
+
"type AgentResult = {",
|
|
1352
|
+
" ok: boolean;",
|
|
1353
|
+
" appId?: string;",
|
|
1354
|
+
" contextId?: string;",
|
|
1355
|
+
" contextKey?: string | null;",
|
|
1356
|
+
" triggerEventId?: string;",
|
|
1357
|
+
" error?: string;",
|
|
1358
|
+
"};",
|
|
1359
|
+
"",
|
|
1360
|
+
"export default function AgentWorkbench() {",
|
|
1361
|
+
" const [prompt, setPrompt] = useState(\"Create a deterministic template context.\");",
|
|
1362
|
+
" const [result, setResult] = useState<AgentResult | null>(null);",
|
|
1363
|
+
" const [pending, setPending] = useState(false);",
|
|
1364
|
+
"",
|
|
1365
|
+
" const workbenchPath = useMemo(() => {",
|
|
1366
|
+
" if (!result?.appId || !result?.contextId) return \"\";",
|
|
1367
|
+
" return `/app/${result.appId}/contexts/${result.contextId}`;",
|
|
1368
|
+
" }, [result]);",
|
|
1369
|
+
"",
|
|
1370
|
+
" async function startContext() {",
|
|
1371
|
+
" setPending(true);",
|
|
1372
|
+
" setResult(null);",
|
|
1373
|
+
" try {",
|
|
1374
|
+
" const response = await fetch(\"/api/agent/react\", {",
|
|
1375
|
+
" method: \"POST\",",
|
|
1376
|
+
" headers: { \"content-type\": \"application/json\" },",
|
|
1377
|
+
" body: JSON.stringify({ prompt }),",
|
|
1378
|
+
" });",
|
|
1379
|
+
" const data = (await response.json().catch(() => ({}))) as AgentResult;",
|
|
1380
|
+
" setResult(response.ok ? data : { ok: false, error: data.error || response.statusText });",
|
|
1381
|
+
" } catch (error) {",
|
|
1382
|
+
" setResult({ ok: false, error: error instanceof Error ? error.message : String(error) });",
|
|
1383
|
+
" } finally {",
|
|
1384
|
+
" setPending(false);",
|
|
1385
|
+
" }",
|
|
1386
|
+
" }",
|
|
1387
|
+
"",
|
|
1388
|
+
" return (",
|
|
1389
|
+
' <section className="panel">',
|
|
1390
|
+
' <div className="grid">',
|
|
1391
|
+
" <div><span>Schema</span><strong>@ekairos/events</strong></div>",
|
|
1392
|
+
" <div><span>Route</span><strong>/api/agent/react</strong></div>",
|
|
1393
|
+
" <div><span>Mode</span><strong>scripted reactor</strong></div>",
|
|
1394
|
+
" </div>",
|
|
1395
|
+
" <textarea value={prompt} onChange={(event) => setPrompt(event.target.value)} />",
|
|
1396
|
+
" <button type=\"button\" disabled={pending} onClick={startContext}>",
|
|
1397
|
+
" {pending ? \"Starting context...\" : \"Start context\"}",
|
|
1398
|
+
" </button>",
|
|
1399
|
+
" {workbenchPath ? <p>Workbench v2 path: <code>{workbenchPath}</code></p> : null}",
|
|
1400
|
+
" {result ? <pre>{JSON.stringify(result, null, 2)}</pre> : null}",
|
|
1401
|
+
" </section>",
|
|
1402
|
+
" );",
|
|
1403
|
+
"}",
|
|
1404
|
+
].join("\n"),
|
|
1405
|
+
"src/app/api/agent/react/route.ts": [
|
|
1406
|
+
'import { NextRequest, NextResponse } from "next/server";',
|
|
1407
|
+
'import { agentContext, createTriggerEvent } from "@/agent";',
|
|
1408
|
+
'import { createRuntime } from "@/runtime";',
|
|
1409
|
+
"",
|
|
1410
|
+
"export const maxDuration = 60;",
|
|
1411
|
+
"",
|
|
1412
|
+
"function readTrimmed(value: unknown) {",
|
|
1413
|
+
" return typeof value === \"string\" ? value.trim() : \"\";",
|
|
1414
|
+
"}",
|
|
1415
|
+
"",
|
|
1416
|
+
"export async function POST(req: NextRequest) {",
|
|
1417
|
+
" try {",
|
|
1418
|
+
" const body = await req.json().catch(() => ({}));",
|
|
1419
|
+
" const prompt = readTrimmed((body as any).prompt) || \"Create a deterministic template context.\";",
|
|
1420
|
+
" const contextKey = readTrimmed((body as any).contextKey) || `agent-template:${Date.now()}`;",
|
|
1421
|
+
" const triggerEvent = createTriggerEvent(prompt);",
|
|
1422
|
+
" const reaction = await agentContext.react(triggerEvent, {",
|
|
1423
|
+
" runtime: createRuntime({ actorId: \"template-user\" }),",
|
|
1424
|
+
" context: { key: contextKey },",
|
|
1425
|
+
" durable: false,",
|
|
1426
|
+
" });",
|
|
1427
|
+
" if (reaction.run) await reaction.run;",
|
|
1428
|
+
" return NextResponse.json({",
|
|
1429
|
+
" ok: true,",
|
|
1430
|
+
" appId: process.env.NEXT_PUBLIC_INSTANT_APP_ID || null,",
|
|
1431
|
+
" contextId: String(reaction.context.id || \"\"),",
|
|
1432
|
+
" contextKey: reaction.context.key ?? contextKey,",
|
|
1433
|
+
" triggerEventId: triggerEvent.id,",
|
|
1434
|
+
" });",
|
|
1435
|
+
" } catch (error) {",
|
|
1436
|
+
" return NextResponse.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, { status: 500 });",
|
|
1437
|
+
" }",
|
|
1438
|
+
"}",
|
|
1439
|
+
].join("\n"),
|
|
1440
|
+
"src/agent.ts": [
|
|
1441
|
+
"import {",
|
|
1442
|
+
" createContext,",
|
|
1443
|
+
" createScriptedReactor,",
|
|
1444
|
+
" defineAction,",
|
|
1445
|
+
" eventsDomain,",
|
|
1446
|
+
" type ContextItem,",
|
|
1447
|
+
"} from \"@ekairos/events\";",
|
|
1448
|
+
"import { z } from \"zod\";",
|
|
1449
|
+
"",
|
|
1450
|
+
"export type AgentEnv = {",
|
|
1451
|
+
" actorId?: string;",
|
|
1452
|
+
"};",
|
|
1453
|
+
"",
|
|
1454
|
+
"const createMessageInput = z.object({",
|
|
1455
|
+
" message: z.string(),",
|
|
1456
|
+
" marker: z.string().optional(),",
|
|
1457
|
+
"});",
|
|
1458
|
+
"",
|
|
1459
|
+
"const createMessageOutput = z.object({",
|
|
1460
|
+
" message: z.string(),",
|
|
1461
|
+
" marker: z.string(),",
|
|
1462
|
+
"});",
|
|
1463
|
+
"",
|
|
1464
|
+
"async function createMessage(input: z.infer<typeof createMessageInput>) {",
|
|
1465
|
+
" \"use step\";",
|
|
1466
|
+
" return {",
|
|
1467
|
+
" message: input.message,",
|
|
1468
|
+
" marker: input.marker ?? \"AGENT_TEMPLATE_OK\",",
|
|
1469
|
+
" };",
|
|
1470
|
+
"}",
|
|
1471
|
+
"",
|
|
1472
|
+
"function randomId() {",
|
|
1473
|
+
" return globalThis.crypto?.randomUUID?.() ?? `evt_${Date.now()}_${Math.random().toString(16).slice(2)}`;",
|
|
1474
|
+
"}",
|
|
1475
|
+
"",
|
|
1476
|
+
"export function createTriggerEvent(text: string): ContextItem {",
|
|
1477
|
+
" return {",
|
|
1478
|
+
" id: randomId(),",
|
|
1479
|
+
" type: \"user_message_created\",",
|
|
1480
|
+
" channel: \"web\",",
|
|
1481
|
+
" createdAt: new Date().toISOString(),",
|
|
1482
|
+
" content: { parts: [{ type: \"text\", text }] },",
|
|
1483
|
+
" } as any;",
|
|
1484
|
+
"}",
|
|
1485
|
+
"",
|
|
1486
|
+
"export const agentContext = createContext<AgentEnv>(\"agent.template\")",
|
|
1487
|
+
" .context((stored, env) => ({ ...(stored.content ?? {}), actorId: env.actorId ?? null }))",
|
|
1488
|
+
" .narrative(() => \"You are the minimal Ekairos agent template. Create one deterministic message.\")",
|
|
1489
|
+
" .actions(() => ({",
|
|
1490
|
+
" createMessage: defineAction<any, any, Record<string, never>, AgentEnv, typeof eventsDomain>({",
|
|
1491
|
+
" description: \"Create the deterministic template message.\",",
|
|
1492
|
+
" input: createMessageInput as any,",
|
|
1493
|
+
" output: createMessageOutput as any,",
|
|
1494
|
+
" execute: async ({ input }) => await createMessage(input),",
|
|
1495
|
+
" }),",
|
|
1496
|
+
" }))",
|
|
1497
|
+
" .reactor(",
|
|
1498
|
+
" createScriptedReactor({",
|
|
1499
|
+
" steps: [",
|
|
1500
|
+
" {",
|
|
1501
|
+
" assistantEvent: {",
|
|
1502
|
+
" content: {",
|
|
1503
|
+
" parts: [",
|
|
1504
|
+
" { type: \"text\", text: \"AGENT_TEMPLATE_OK context ready.\" },",
|
|
1505
|
+
" {",
|
|
1506
|
+
" type: \"tool-createMessage\",",
|
|
1507
|
+
" toolCallId: \"agent-template-create-message\",",
|
|
1508
|
+
" input: { message: \"AGENT_TEMPLATE_OK context ready.\", marker: \"AGENT_TEMPLATE_OK\" },",
|
|
1509
|
+
" },",
|
|
1510
|
+
" ],",
|
|
1511
|
+
" },",
|
|
1512
|
+
" },",
|
|
1513
|
+
" actionRequests: [",
|
|
1514
|
+
" {",
|
|
1515
|
+
" actionRef: \"agent-template-create-message\",",
|
|
1516
|
+
" actionName: \"createMessage\",",
|
|
1517
|
+
" input: { message: \"AGENT_TEMPLATE_OK context ready.\", marker: \"AGENT_TEMPLATE_OK\" },",
|
|
1518
|
+
" },",
|
|
1519
|
+
" ],",
|
|
1520
|
+
" messagesForModel: [],",
|
|
1521
|
+
" llm: { provider: \"scripted\", model: \"agent-template\" },",
|
|
1522
|
+
" },",
|
|
1523
|
+
" ],",
|
|
1524
|
+
" repeatLast: true,",
|
|
1525
|
+
" }),",
|
|
1526
|
+
" )",
|
|
1527
|
+
" .shouldContinue(() => false)",
|
|
1528
|
+
" .build();",
|
|
1529
|
+
].join("\n"),
|
|
1530
|
+
"src/runtime.ts": [
|
|
1531
|
+
'import { init } from "@instantdb/admin";',
|
|
1532
|
+
'import { EkairosRuntime } from "@ekairos/domain/runtime-handle";',
|
|
1533
|
+
'import { eventsDomain } from "@ekairos/events/schema";',
|
|
1534
|
+
"",
|
|
1535
|
+
"export type AgentRuntimeEnv = {",
|
|
1536
|
+
" actorId?: string | null;",
|
|
1537
|
+
" adminToken?: string;",
|
|
1538
|
+
" appId?: string;",
|
|
1539
|
+
"};",
|
|
1540
|
+
"",
|
|
1541
|
+
"function resolveRuntimeEnv(env: AgentRuntimeEnv = {}): Required<Pick<AgentRuntimeEnv, \"appId\" | \"adminToken\">> & AgentRuntimeEnv {",
|
|
1542
|
+
" const appId = String(env.appId ?? process.env.NEXT_PUBLIC_INSTANT_APP_ID ?? \"\").trim();",
|
|
1543
|
+
" const adminToken = String(env.adminToken ?? process.env.INSTANT_ADMIN_TOKEN ?? \"\").trim();",
|
|
1544
|
+
" if (!appId || !adminToken) {",
|
|
1545
|
+
" throw new Error(\"Missing NEXT_PUBLIC_INSTANT_APP_ID or INSTANT_ADMIN_TOKEN. Copy .env.example to .env.local and fill both values.\");",
|
|
1546
|
+
" }",
|
|
1547
|
+
" return { ...env, appId, adminToken };",
|
|
1548
|
+
"}",
|
|
1549
|
+
"",
|
|
1550
|
+
"export class AgentRuntime extends EkairosRuntime<AgentRuntimeEnv, typeof eventsDomain, any> {",
|
|
1551
|
+
" protected getDomain() { return eventsDomain; }",
|
|
1552
|
+
" protected async resolveDb(env: AgentRuntimeEnv) {",
|
|
1553
|
+
" const resolved = resolveRuntimeEnv(env);",
|
|
1554
|
+
" return init({",
|
|
1555
|
+
" appId: resolved.appId,",
|
|
1556
|
+
" adminToken: resolved.adminToken,",
|
|
1557
|
+
" schema: eventsDomain.toInstantSchema(),",
|
|
1558
|
+
" useDateObjects: true,",
|
|
1559
|
+
" } as any) as any;",
|
|
1560
|
+
" }",
|
|
1561
|
+
"}",
|
|
1562
|
+
"",
|
|
1563
|
+
"export function createRuntime(env: AgentRuntimeEnv = {}) {",
|
|
1564
|
+
" return new AgentRuntime(resolveRuntimeEnv(env));",
|
|
1565
|
+
"}",
|
|
1566
|
+
].join("\n"),
|
|
1567
|
+
};
|
|
1568
|
+
}
|
|
922
1569
|
return {
|
|
923
1570
|
".gitignore": [".next", "node_modules", ".env.local", ".workflow-data"].join("\n"),
|
|
924
1571
|
".env.example": [
|
|
@@ -988,14 +1635,16 @@ function buildNextTemplateFiles(params) {
|
|
|
988
1635
|
' "moduleResolution": "bundler",',
|
|
989
1636
|
' "resolveJsonModule": true,',
|
|
990
1637
|
' "isolatedModules": true,',
|
|
991
|
-
' "jsx": "
|
|
1638
|
+
' "jsx": "react-jsx",',
|
|
992
1639
|
' "incremental": true,',
|
|
993
|
-
' "baseUrl": ".",',
|
|
994
1640
|
' "paths": {',
|
|
995
1641
|
' "@/*": ["./src/*"]',
|
|
996
|
-
" }",
|
|
1642
|
+
" },",
|
|
1643
|
+
' "plugins": [',
|
|
1644
|
+
' { "name": "next" }',
|
|
1645
|
+
" ]",
|
|
997
1646
|
" },",
|
|
998
|
-
' "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],',
|
|
1647
|
+
' "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts"],',
|
|
999
1648
|
' "exclude": ["node_modules"]',
|
|
1000
1649
|
"}",
|
|
1001
1650
|
].join("\n"),
|
|
@@ -1804,6 +2453,7 @@ function buildNextTemplateFiles(params) {
|
|
|
1804
2453
|
"src/domain.ts": [
|
|
1805
2454
|
"import { defineAction, domain } from \"@ekairos/domain\";",
|
|
1806
2455
|
"import { i } from \"@instantdb/core\";",
|
|
2456
|
+
"import { z } from \"zod\";",
|
|
1807
2457
|
"",
|
|
1808
2458
|
"export const supplierNetworkDomain = domain(\"supplierNetwork\").withSchema({",
|
|
1809
2459
|
" entities: {",
|
|
@@ -1906,13 +2556,20 @@ function buildNextTemplateFiles(params) {
|
|
|
1906
2556
|
" .includes(qualityControlDomain)",
|
|
1907
2557
|
" .withSchema({ entities: {}, links: {}, rooms: {} });",
|
|
1908
2558
|
"",
|
|
1909
|
-
"export const launchOrderAction = defineAction
|
|
1910
|
-
" Record<string, unknown>,",
|
|
1911
|
-
" { reference?: string; supplierName?: string; sku?: string },",
|
|
1912
|
-
" { supplierId: string; orderId: string; stockItemId: string; shipmentId: string; inspectionId: string },",
|
|
1913
|
-
" any",
|
|
1914
|
-
">({",
|
|
2559
|
+
"export const launchOrderAction = defineAction({",
|
|
1915
2560
|
" name: \"supplyChain.order.launch\",",
|
|
2561
|
+
" input: z.object({",
|
|
2562
|
+
" reference: z.string().optional(),",
|
|
2563
|
+
" supplierName: z.string().optional(),",
|
|
2564
|
+
" sku: z.string().optional(),",
|
|
2565
|
+
" }),",
|
|
2566
|
+
" output: z.object({",
|
|
2567
|
+
" supplierId: z.string(),",
|
|
2568
|
+
" orderId: z.string(),",
|
|
2569
|
+
" stockItemId: z.string(),",
|
|
2570
|
+
" shipmentId: z.string(),",
|
|
2571
|
+
" inspectionId: z.string(),",
|
|
2572
|
+
" }),",
|
|
1916
2573
|
" async execute({ runtime, input }): Promise<{",
|
|
1917
2574
|
" supplierId: string;",
|
|
1918
2575
|
" orderId: string;",
|
|
@@ -1920,8 +2577,6 @@ function buildNextTemplateFiles(params) {
|
|
|
1920
2577
|
" shipmentId: string;",
|
|
1921
2578
|
" inspectionId: string;",
|
|
1922
2579
|
" }> {",
|
|
1923
|
-
" \"use step\";",
|
|
1924
|
-
" const scoped = await runtime.use(appDomain);",
|
|
1925
2580
|
" const now = Date.now();",
|
|
1926
2581
|
" const supplierId = globalThis.crypto.randomUUID();",
|
|
1927
2582
|
" const orderId = globalThis.crypto.randomUUID();",
|
|
@@ -1929,65 +2584,60 @@ function buildNextTemplateFiles(params) {
|
|
|
1929
2584
|
" const shipmentId = globalThis.crypto.randomUUID();",
|
|
1930
2585
|
" const inspectionId = globalThis.crypto.randomUUID();",
|
|
1931
2586
|
"",
|
|
1932
|
-
" await
|
|
1933
|
-
"
|
|
2587
|
+
" await runtime.db.transact([",
|
|
2588
|
+
" runtime.db.tx.supplierNetwork_supplier[supplierId].update({",
|
|
1934
2589
|
" name: String(input?.supplierName ?? \"\").trim() || \"Marula Components\",",
|
|
1935
2590
|
" region: \"Pacific North\",",
|
|
1936
2591
|
" risk: \"watch\",",
|
|
1937
2592
|
" score: 82,",
|
|
1938
2593
|
" createdAt: now,",
|
|
1939
2594
|
" }),",
|
|
1940
|
-
"
|
|
2595
|
+
" runtime.db.tx.procurement_order[orderId].update({",
|
|
1941
2596
|
" reference: String(input?.reference ?? \"\").trim() || \"PO-7842\",",
|
|
1942
2597
|
" status: \"released\",",
|
|
1943
2598
|
" spend: 184700,",
|
|
1944
2599
|
" createdAt: now + 1,",
|
|
1945
2600
|
" }),",
|
|
1946
|
-
"
|
|
1947
|
-
"
|
|
2601
|
+
" runtime.db.tx.procurement_order[orderId].link({ supplier: supplierId }),",
|
|
2602
|
+
" runtime.db.tx.inventory_stockItem[stockItemId].update({",
|
|
1948
2603
|
" sku: String(input?.sku ?? \"\").trim() || \"DRV-2048\",",
|
|
1949
2604
|
" warehouse: \"Reno DC\",",
|
|
1950
2605
|
" available: 320,",
|
|
1951
2606
|
" safetyStock: 140,",
|
|
1952
2607
|
" createdAt: now + 2,",
|
|
1953
2608
|
" }),",
|
|
1954
|
-
"
|
|
1955
|
-
"
|
|
2609
|
+
" runtime.db.tx.inventory_stockItem[stockItemId].link({ order: orderId }),",
|
|
2610
|
+
" runtime.db.tx.transportation_shipment[shipmentId].update({",
|
|
1956
2611
|
" carrier: \"Northstar Freight\",",
|
|
1957
2612
|
" lane: \"Reno -> Austin\",",
|
|
1958
2613
|
" status: \"in-transit\",",
|
|
1959
2614
|
" etaHours: 38,",
|
|
1960
2615
|
" createdAt: now + 3,",
|
|
1961
2616
|
" }),",
|
|
1962
|
-
"
|
|
1963
|
-
"
|
|
2617
|
+
" runtime.db.tx.transportation_shipment[shipmentId].link({ order: orderId }),",
|
|
2618
|
+
" runtime.db.tx.qualityControl_inspection[inspectionId].update({",
|
|
1964
2619
|
" result: \"pending\",",
|
|
1965
2620
|
" severity: \"medium\",",
|
|
1966
2621
|
" note: \"Inspect seal integrity on arrival.\",",
|
|
1967
2622
|
" createdAt: now + 4,",
|
|
1968
2623
|
" }),",
|
|
1969
|
-
"
|
|
2624
|
+
" runtime.db.tx.qualityControl_inspection[inspectionId].link({ shipment: shipmentId }),",
|
|
1970
2625
|
" ]);",
|
|
1971
2626
|
"",
|
|
1972
2627
|
" return { supplierId, orderId, stockItemId, shipmentId, inspectionId };",
|
|
1973
2628
|
" },",
|
|
1974
2629
|
"});",
|
|
1975
2630
|
"",
|
|
1976
|
-
"export const expediteShipmentAction = defineAction
|
|
1977
|
-
" Record<string, unknown>,",
|
|
1978
|
-
" { shipmentId?: string },",
|
|
1979
|
-
" { shipmentId: string },",
|
|
1980
|
-
" any",
|
|
1981
|
-
">({",
|
|
2631
|
+
"export const expediteShipmentAction = defineAction({",
|
|
1982
2632
|
" name: \"supplyChain.shipment.expedite\",",
|
|
2633
|
+
" input: z.object({ shipmentId: z.string().optional() }),",
|
|
2634
|
+
" output: z.object({ shipmentId: z.string() }),",
|
|
1983
2635
|
" async execute({ runtime, input }): Promise<{ shipmentId: string }> {",
|
|
1984
|
-
" \"use step\";",
|
|
1985
|
-
" const scoped = await runtime.use(appDomain);",
|
|
1986
2636
|
" const shipmentId = String(input?.shipmentId ?? \"\").trim();",
|
|
1987
2637
|
" if (!shipmentId) throw new Error(\"shipmentId is required\");",
|
|
1988
2638
|
"",
|
|
1989
|
-
" await
|
|
1990
|
-
"
|
|
2639
|
+
" await runtime.db.transact([",
|
|
2640
|
+
" runtime.db.tx.transportation_shipment[shipmentId].update({",
|
|
1991
2641
|
" status: \"expedited\",",
|
|
1992
2642
|
" etaHours: 16,",
|
|
1993
2643
|
" }),",
|
|
@@ -2061,6 +2711,7 @@ function buildNextTemplateFiles(params) {
|
|
|
2061
2711
|
"});",
|
|
2062
2712
|
].join("\n"),
|
|
2063
2713
|
"src/workflows/demo.workflow.ts": [
|
|
2714
|
+
"import type { ActiveDomain } from \"@ekairos/domain\";",
|
|
2064
2715
|
"import appDomain from \"../domain\";",
|
|
2065
2716
|
"import { createRuntime } from \"../runtime\";",
|
|
2066
2717
|
"",
|
|
@@ -2074,7 +2725,7 @@ function buildNextTemplateFiles(params) {
|
|
|
2074
2725
|
"export async function runDemoWorkflow(input: DemoWorkflowInput) {",
|
|
2075
2726
|
" \"use workflow\";",
|
|
2076
2727
|
" const runtime = createRuntime();",
|
|
2077
|
-
" const scoped = await runtime.use(appDomain)
|
|
2728
|
+
" const scoped = (await runtime.use(appDomain)) as ActiveDomain<typeof appDomain>;",
|
|
2078
2729
|
" const created = await scoped.actions.launchOrder({",
|
|
2079
2730
|
" reference: input.reference,",
|
|
2080
2731
|
" sku: input.sku,",
|
|
@@ -2096,6 +2747,7 @@ export async function createDomainApp(params) {
|
|
|
2096
2747
|
if (params.framework !== "next") {
|
|
2097
2748
|
throw new Error("Only --next is supported right now.");
|
|
2098
2749
|
}
|
|
2750
|
+
const template = resolveCreateAppTemplate(params);
|
|
2099
2751
|
if (params.smoke && !params.install) {
|
|
2100
2752
|
throw new Error("--smoke requires dependencies. Remove --no-install or run smoke after installing.");
|
|
2101
2753
|
}
|
|
@@ -2156,6 +2808,7 @@ export async function createDomainApp(params) {
|
|
|
2156
2808
|
});
|
|
2157
2809
|
provisioned = await provisionInstantApp({
|
|
2158
2810
|
directory: targetDir,
|
|
2811
|
+
template,
|
|
2159
2812
|
instantToken: trimOrEmpty(params.instantToken),
|
|
2160
2813
|
orgId: params.orgId,
|
|
2161
2814
|
});
|
|
@@ -2181,6 +2834,7 @@ export async function createDomainApp(params) {
|
|
|
2181
2834
|
});
|
|
2182
2835
|
const files = buildNextTemplateFiles({
|
|
2183
2836
|
targetDir,
|
|
2837
|
+
template,
|
|
2184
2838
|
domainVersion,
|
|
2185
2839
|
packageManager,
|
|
2186
2840
|
workspacePath: params.workspacePath,
|
|
@@ -2229,7 +2883,7 @@ export async function createDomainApp(params) {
|
|
|
2229
2883
|
}
|
|
2230
2884
|
const smoke = params.smoke
|
|
2231
2885
|
? await runSmoke({
|
|
2232
|
-
demo:
|
|
2886
|
+
demo: template === "supply-chain",
|
|
2233
2887
|
targetDir,
|
|
2234
2888
|
packageManager,
|
|
2235
2889
|
keepServer: Boolean(params.keepServer),
|
|
@@ -2239,22 +2893,39 @@ export async function createDomainApp(params) {
|
|
|
2239
2893
|
: null;
|
|
2240
2894
|
const cliCommand = packageBinCommandFor(packageManager, "domain");
|
|
2241
2895
|
const reviewUrl = smoke?.baseUrl ?? "http://localhost:3000";
|
|
2242
|
-
const
|
|
2243
|
-
`
|
|
2244
|
-
|
|
2245
|
-
?
|
|
2246
|
-
:
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2896
|
+
const startStep = smoke?.keepServer
|
|
2897
|
+
? `Open ${reviewUrl} for review`
|
|
2898
|
+
: params.install
|
|
2899
|
+
? runScriptCommandFor(packageManager, "dev")
|
|
2900
|
+
: `${installCommandFor(packageManager)} && ${runScriptCommandFor(packageManager, "dev")}`;
|
|
2901
|
+
const nextSteps = template === "supply-chain"
|
|
2902
|
+
? [
|
|
2903
|
+
`cd ${targetDir}`,
|
|
2904
|
+
startStep,
|
|
2905
|
+
`Open ${reviewUrl} and launch a purchase order from the control tower UI`,
|
|
2906
|
+
`${cliCommand} inspect --baseUrl=${reviewUrl} --admin --pretty`,
|
|
2907
|
+
`${cliCommand} "supplyChain.order.launch" "{ reference: 'PO-7842', supplierName: 'Marula Components', sku: 'DRV-2048' }" --baseUrl=${reviewUrl} --admin --pretty`,
|
|
2908
|
+
`${cliCommand} query "{ procurement_order: { supplier: {}, stockItems: {}, shipments: { inspections: {} } } }" --baseUrl=${reviewUrl} --admin --pretty`,
|
|
2909
|
+
]
|
|
2910
|
+
: template === "agent"
|
|
2911
|
+
? [
|
|
2912
|
+
`cd ${targetDir}`,
|
|
2913
|
+
startStep,
|
|
2914
|
+
`Open ${reviewUrl} and start a context through /api/agent/react`,
|
|
2915
|
+
`Inspect the returned context id in Workbench v2 for app ${appId || "<instant-app-id>"}`,
|
|
2916
|
+
`Iterate on src/agent.ts`,
|
|
2917
|
+
]
|
|
2918
|
+
: [
|
|
2919
|
+
`cd ${targetDir}`,
|
|
2920
|
+
startStep,
|
|
2921
|
+
`Open ${reviewUrl} and add your first domain in src/domain.ts`,
|
|
2922
|
+
`${cliCommand} inspect --baseUrl=${reviewUrl} --admin --pretty`,
|
|
2923
|
+
];
|
|
2254
2924
|
const result = {
|
|
2255
2925
|
ok: true,
|
|
2256
2926
|
directory: targetDir,
|
|
2257
2927
|
framework: params.framework,
|
|
2928
|
+
template,
|
|
2258
2929
|
installed: params.install,
|
|
2259
2930
|
packageManager,
|
|
2260
2931
|
provisioned: Boolean(provisioned),
|