@loomwork/scaffold 0.0.0-stage → 0.1.1
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/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +54 -2
- package/dist/codegen.d.ts +23 -0
- package/dist/codegen.d.ts.map +1 -0
- package/dist/codegen.js +62 -0
- package/dist/codegen.js.map +1 -0
- package/dist/emit.d.ts +18 -0
- package/dist/emit.d.ts.map +1 -0
- package/dist/emit.js +74 -0
- package/dist/emit.js.map +1 -0
- package/dist/flowTemplates.d.ts +23 -0
- package/dist/flowTemplates.d.ts.map +1 -0
- package/dist/flowTemplates.js +348 -0
- package/dist/flowTemplates.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/names.d.ts +16 -0
- package/dist/names.d.ts.map +1 -0
- package/dist/names.js +45 -0
- package/dist/names.js.map +1 -0
- package/dist/plugin.d.ts +45 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +1819 -0
- package/dist/plugin.js.map +1 -0
- package/dist/templates.d.ts +42 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +536 -0
- package/dist/templates.js.map +1 -0
- package/package.json +48 -3
- package/src/codegen.ts +69 -0
- package/src/emit.ts +72 -0
- package/src/flowTemplates.ts +353 -0
- package/src/index.ts +30 -0
- package/src/names.ts +43 -0
- package/src/plugin.ts +1920 -0
- package/src/templates.ts +566 -0
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.THIRD_PARTY_SPECS = void 0;
|
|
4
|
+
exports.flowFile = flowFile;
|
|
5
|
+
exports.flowTestFile = flowTestFile;
|
|
6
|
+
exports.sentinelFile = sentinelFile;
|
|
7
|
+
exports.toolFile = toolFile;
|
|
8
|
+
exports.agentFile = agentFile;
|
|
9
|
+
exports.skillFile = skillFile;
|
|
10
|
+
exports.scheduleFile = scheduleFile;
|
|
11
|
+
exports.memoryFile = memoryFile;
|
|
12
|
+
exports.projectionFile = projectionFile;
|
|
13
|
+
exports.newFile = newFile;
|
|
14
|
+
exports.newFiles = newFiles;
|
|
15
|
+
exports.importedPackages = importedPackages;
|
|
16
|
+
exports.appFiles = appFiles;
|
|
17
|
+
const codegen_1 = require("./codegen");
|
|
18
|
+
const emit_1 = require("./emit");
|
|
19
|
+
const flowTemplates_1 = require("./flowTemplates");
|
|
20
|
+
// ── Per-file templates (used by `loom new`, following the folder convention) ──
|
|
21
|
+
/** `app/flows/<name>/flow.ts` — a self-contained echo flow. */
|
|
22
|
+
function flowFile(name) {
|
|
23
|
+
const P = (0, codegen_1.pascalIdent)(name);
|
|
24
|
+
return [
|
|
25
|
+
'import { flow$, handler$, step$ } from "@loomwork/core";',
|
|
26
|
+
'import type { FlowRunner, RegisteredFlow } from "@loomwork/workflow-runtime";',
|
|
27
|
+
'import { z } from "zod";',
|
|
28
|
+
"",
|
|
29
|
+
`const ${P}Step = step$({`,
|
|
30
|
+
` id: ${(0, emit_1.tsStringLiteral)(`${name}-step`)},`,
|
|
31
|
+
` name: "${P}",`,
|
|
32
|
+
" inputSchema: z.object({ input: z.string() }),",
|
|
33
|
+
" outputSchema: z.object({ output: z.string() }),",
|
|
34
|
+
" handler: handler$(async (i: { input: string }) => ({ output: i.input })),",
|
|
35
|
+
"});",
|
|
36
|
+
"",
|
|
37
|
+
"const runner: FlowRunner<{ input: string }, { output: string }> = (ctx, input) =>",
|
|
38
|
+
` ctx.run(${P}Step, input) as Promise<{ output: string }>;`,
|
|
39
|
+
"",
|
|
40
|
+
`export const ${P}Flow: RegisteredFlow = {`,
|
|
41
|
+
" definition: flow$({",
|
|
42
|
+
` id: ${(0, emit_1.tsStringLiteral)(name)},`,
|
|
43
|
+
` name: "${P}",`,
|
|
44
|
+
' version: "1.0.0",',
|
|
45
|
+
" inputSchema: z.object({ input: z.string() }),",
|
|
46
|
+
" outputSchema: z.object({ output: z.string() }),",
|
|
47
|
+
` steps: [${P}Step],`,
|
|
48
|
+
" }),",
|
|
49
|
+
" runner: runner as FlowRunner<unknown, unknown>,",
|
|
50
|
+
"};",
|
|
51
|
+
"",
|
|
52
|
+
].join("\n");
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* `app/flows/<name>/flow.test.ts` — runs the `loom new flow` echo flow through `@loomwork/testing`'s
|
|
56
|
+
* `createTestApp` (in-memory, permissive defaults: no principal or grants to wire). It passes on a
|
|
57
|
+
* fresh scaffold; replace the input/assertion as you change the flow.
|
|
58
|
+
*/
|
|
59
|
+
function flowTestFile(name) {
|
|
60
|
+
const P = (0, codegen_1.pascalIdent)(name);
|
|
61
|
+
return [
|
|
62
|
+
'import { createTestApp } from "@loomwork/testing";',
|
|
63
|
+
'import { describe, expect, it } from "vitest";',
|
|
64
|
+
`import { ${P}Flow } from "./flow";`,
|
|
65
|
+
"",
|
|
66
|
+
`describe(${(0, emit_1.tsStringLiteral)(name)}, () => {`,
|
|
67
|
+
' it("runs the flow end to end", async () => {',
|
|
68
|
+
` const app = createTestApp({ flows: [${P}Flow] });`,
|
|
69
|
+
" try {",
|
|
70
|
+
` const handle = await app.runtime.start(${P}Flow, { input: "hello" });`,
|
|
71
|
+
" const state = await handle.waitForCompletion();",
|
|
72
|
+
' expect(state.variables._output).toEqual({ output: "hello" });',
|
|
73
|
+
" } finally {",
|
|
74
|
+
" await app.close();",
|
|
75
|
+
" }",
|
|
76
|
+
" });",
|
|
77
|
+
"});",
|
|
78
|
+
"",
|
|
79
|
+
].join("\n");
|
|
80
|
+
}
|
|
81
|
+
/** `app/flows/<name>/flow.ts` — a schedule-driven sentinel starter (@loomwork/plugin-sentinel). */
|
|
82
|
+
function sentinelFile(name) {
|
|
83
|
+
const P = (0, codegen_1.pascalIdent)(name);
|
|
84
|
+
return [
|
|
85
|
+
"// The perpetual-agent pattern (ADRs 0051-0057): a schedule over bounded runs.",
|
|
86
|
+
"// Wire preset.schedule into defineConfig({ timers }), preset.middleware into",
|
|
87
|
+
"// effectMiddleware, call preset.register(app.effectRuntime), and feed",
|
|
88
|
+
"// preset.pinnedEventTypes to `loom sweep content --pin`.",
|
|
89
|
+
'import { flow$ } from "@loomwork/core";',
|
|
90
|
+
'import { isClaimCheck } from "@loomwork/middleware";',
|
|
91
|
+
'import { sentinelPreset } from "@loomwork/plugin-sentinel";',
|
|
92
|
+
'import type { FlowRunner, RegisteredFlow } from "@loomwork/workflow-runtime";',
|
|
93
|
+
'import { z } from "zod";',
|
|
94
|
+
"",
|
|
95
|
+
"const stateSchema = z.object({ wakes: z.number() }); // TODO: your carry-state contract",
|
|
96
|
+
"",
|
|
97
|
+
`export const ${P}Preset = sentinelPreset<z.infer<typeof stateSchema>>({`,
|
|
98
|
+
` id: ${(0, emit_1.tsStringLiteral)(name)},`,
|
|
99
|
+
' cron: "0 */6 * * *", // TODO: cadence',
|
|
100
|
+
" state: { schema: stateSchema },",
|
|
101
|
+
" stateStore: undefined as never, // TODO: durable-state backend (sqlite/postgres)",
|
|
102
|
+
" contentStore: undefined as never, // TODO: content backend (SqliteContentStore)",
|
|
103
|
+
"});",
|
|
104
|
+
"",
|
|
105
|
+
"const io = z.object({}).passthrough();",
|
|
106
|
+
"",
|
|
107
|
+
"const runner: FlowRunner<Record<string, unknown>, Record<string, unknown>> = async (ctx) => {",
|
|
108
|
+
` const carried = await ${P}Preset.state.load(ctx);`,
|
|
109
|
+
" // TODO: observe via your tool$ (recorded; over-cap results go by reference):",
|
|
110
|
+
" // const read = await ctx.execute(readTask, { at: Preset.occurrenceOf(ctx.executionId) });",
|
|
111
|
+
" // if (isClaimCheck(read) && (read.digest as YourDigest).metric > threshold) {",
|
|
112
|
+
' // ctx.emit("FINDING_RECORDED", { evidence: [read.ref] /* + your schema */ });',
|
|
113
|
+
" // }",
|
|
114
|
+
" void isClaimCheck;",
|
|
115
|
+
` await ${P}Preset.state.save(ctx, { wakes: (carried.value?.wakes ?? 0) + 1 }, carried.revision);`,
|
|
116
|
+
" return { ok: true };",
|
|
117
|
+
"};",
|
|
118
|
+
"",
|
|
119
|
+
`export const ${P}Flow: RegisteredFlow = {`,
|
|
120
|
+
" definition: flow$({",
|
|
121
|
+
` id: ${(0, emit_1.tsStringLiteral)(`${name}-flow`)},`,
|
|
122
|
+
` name: "${P} sentinel",`,
|
|
123
|
+
' version: "1.0.0",',
|
|
124
|
+
" inputSchema: io,",
|
|
125
|
+
" outputSchema: io,",
|
|
126
|
+
" steps: [],",
|
|
127
|
+
" }),",
|
|
128
|
+
" runner: runner as FlowRunner<unknown, unknown>,",
|
|
129
|
+
"};",
|
|
130
|
+
"",
|
|
131
|
+
].join("\n");
|
|
132
|
+
}
|
|
133
|
+
/** `app/tools/<name>.ts` — a tool definition stub. */
|
|
134
|
+
function toolFile(name) {
|
|
135
|
+
const P = (0, codegen_1.pascalIdent)(name);
|
|
136
|
+
return [
|
|
137
|
+
'import { tool$ } from "@loomwork/core";',
|
|
138
|
+
'import { z } from "zod";',
|
|
139
|
+
"",
|
|
140
|
+
`export const ${P}Tool = tool$({`,
|
|
141
|
+
` id: ${(0, emit_1.tsStringLiteral)(name)},`,
|
|
142
|
+
` name: "${P}",`,
|
|
143
|
+
` description: ${(0, emit_1.tsStringLiteral)(`TODO: describe ${name}.`)},`,
|
|
144
|
+
' kind: "tool",',
|
|
145
|
+
" inputSchema: z.object({}),",
|
|
146
|
+
" outputSchema: z.object({}),",
|
|
147
|
+
" // Typed failure channels (ADR 0060) — declare EXPECTED failure modes so the",
|
|
148
|
+
' // effect can `fail("notFound", { id })`: the failure is recorded with its',
|
|
149
|
+
" // validated payload, flows branch on it deterministically, and replay",
|
|
150
|
+
" // substitutes it without re-invoking the effect. Undeclared failures keep",
|
|
151
|
+
" // legacy retry semantics. Pass the same map to the registered effect:",
|
|
152
|
+
" // new ToolEffect(fn, { errors: { notFound: z.object({ id: z.string() }) } })",
|
|
153
|
+
" // errors: { notFound: z.object({ id: z.string() }) },",
|
|
154
|
+
"});",
|
|
155
|
+
"",
|
|
156
|
+
].join("\n");
|
|
157
|
+
}
|
|
158
|
+
/** `app/agents/<name>.ts` — an agent definition stub. */
|
|
159
|
+
function agentFile(name) {
|
|
160
|
+
const P = (0, codegen_1.pascalIdent)(name);
|
|
161
|
+
return [
|
|
162
|
+
'import { agent$ } from "@loomwork/core";',
|
|
163
|
+
"",
|
|
164
|
+
`export const ${P}Agent = agent$({`,
|
|
165
|
+
` id: ${(0, emit_1.tsStringLiteral)(name)},`,
|
|
166
|
+
` name: "${P}",`,
|
|
167
|
+
` description: ${(0, emit_1.tsStringLiteral)(`TODO: describe ${name}.`)},`,
|
|
168
|
+
" tools: [],",
|
|
169
|
+
"});",
|
|
170
|
+
"",
|
|
171
|
+
].join("\n");
|
|
172
|
+
}
|
|
173
|
+
/** `app/skills/<name>.ts` — a skill definition stub (instructions stay lazy). */
|
|
174
|
+
function skillFile(name) {
|
|
175
|
+
const P = (0, codegen_1.pascalIdent)(name);
|
|
176
|
+
return [
|
|
177
|
+
'import { instructions$, skill$ } from "@loomwork/core";',
|
|
178
|
+
"",
|
|
179
|
+
`export const ${P}Skill = skill$({`,
|
|
180
|
+
` id: ${(0, emit_1.tsStringLiteral)(name)},`,
|
|
181
|
+
` name: "${P}",`,
|
|
182
|
+
` description: ${(0, emit_1.tsStringLiteral)(`TODO: describe ${name}.`)},`,
|
|
183
|
+
" tags: [],",
|
|
184
|
+
` instructions: instructions$(${(0, emit_1.tsStringLiteral)(`TODO: write the ${name} instructions.`)}),`,
|
|
185
|
+
"});",
|
|
186
|
+
"",
|
|
187
|
+
].join("\n");
|
|
188
|
+
}
|
|
189
|
+
/** `app/schedules/<name>.ts` — a cron schedule stub (points at a flow to start). */
|
|
190
|
+
function scheduleFile(name) {
|
|
191
|
+
const P = (0, codegen_1.pascalIdent)(name);
|
|
192
|
+
return [
|
|
193
|
+
'import { schedule$ } from "@loomwork/core";',
|
|
194
|
+
"",
|
|
195
|
+
`export const ${P}Schedule = schedule$({`,
|
|
196
|
+
` id: ${(0, emit_1.tsStringLiteral)(name)},`,
|
|
197
|
+
' cron: "0 * * * *", // hourly (UTC); 5-field cron',
|
|
198
|
+
` flowId: "TODO-flow-id", // the registered flow each occurrence starts`,
|
|
199
|
+
"});",
|
|
200
|
+
"",
|
|
201
|
+
].join("\n");
|
|
202
|
+
}
|
|
203
|
+
/** `app/memories/<name>.ts` — a named memory definition stub. */
|
|
204
|
+
function memoryFile(name) {
|
|
205
|
+
const P = (0, codegen_1.pascalIdent)(name);
|
|
206
|
+
return [
|
|
207
|
+
'import { memory$ } from "@loomwork/core";',
|
|
208
|
+
"",
|
|
209
|
+
`export const ${P}Memory = memory$({`,
|
|
210
|
+
` id: ${(0, emit_1.tsStringLiteral)(name)},`,
|
|
211
|
+
` name: "${P}",`,
|
|
212
|
+
" // ttlMs / maxEntries bound each scope; omit for unbounded.",
|
|
213
|
+
"});",
|
|
214
|
+
"",
|
|
215
|
+
].join("\n");
|
|
216
|
+
}
|
|
217
|
+
/** `app/projections/<name>.ts` — a projection stub (handlers fold events; loaded on demand). */
|
|
218
|
+
function projectionFile(name) {
|
|
219
|
+
const P = (0, codegen_1.pascalIdent)(name);
|
|
220
|
+
return [
|
|
221
|
+
'import { projection$ } from "@loomwork/core";',
|
|
222
|
+
"",
|
|
223
|
+
`export const ${P}Projection = projection$({`,
|
|
224
|
+
` id: ${(0, emit_1.tsStringLiteral)(name)},`,
|
|
225
|
+
` name: "${P}",`,
|
|
226
|
+
" initialState: { count: 0 },",
|
|
227
|
+
" // The fold map: one reducer per event type. The @loomwork/compiler plugin extracts this",
|
|
228
|
+
" // into its own chunk, loaded on demand the first time a handled event fires.",
|
|
229
|
+
" handlers: {",
|
|
230
|
+
" STEP_COMPLETED: (state, _event) => ({ count: state.count + 1 }),",
|
|
231
|
+
" },",
|
|
232
|
+
"});",
|
|
233
|
+
"",
|
|
234
|
+
].join("\n");
|
|
235
|
+
}
|
|
236
|
+
/** Route `loom new <kind> <name>` to the file it generates (path + contents). */
|
|
237
|
+
function newFile(kind, name, template = "echo") {
|
|
238
|
+
switch (kind) {
|
|
239
|
+
case "sentinel":
|
|
240
|
+
return { path: `app/flows/${name}/flow.ts`, content: sentinelFile(name) };
|
|
241
|
+
case "flow":
|
|
242
|
+
return {
|
|
243
|
+
path: `app/flows/${name}/flow.ts`,
|
|
244
|
+
content: template === "echo" ? flowFile(name) : (0, flowTemplates_1.templateFiles)(template, name).flow,
|
|
245
|
+
};
|
|
246
|
+
case "agent":
|
|
247
|
+
return { path: `app/agents/${name}.ts`, content: agentFile(name) };
|
|
248
|
+
case "tool":
|
|
249
|
+
return { path: `app/tools/${name}.ts`, content: toolFile(name) };
|
|
250
|
+
case "skill":
|
|
251
|
+
return { path: `app/skills/${name}.ts`, content: skillFile(name) };
|
|
252
|
+
case "schedule":
|
|
253
|
+
return { path: `app/schedules/${name}.ts`, content: scheduleFile(name) };
|
|
254
|
+
case "memory":
|
|
255
|
+
return { path: `app/memories/${name}.ts`, content: memoryFile(name) };
|
|
256
|
+
case "projection":
|
|
257
|
+
return { path: `app/projections/${name}.ts`, content: projectionFile(name) };
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Every file `loom new <kind> <name>` writes: the construct itself first, then (where a test is
|
|
262
|
+
* natural — a flow) a sibling `*.test.ts`. `newFile` stays the single-file router.
|
|
263
|
+
*/
|
|
264
|
+
function newFiles(kind, name, template = "echo") {
|
|
265
|
+
const files = [newFile(kind, name, template)];
|
|
266
|
+
if (kind === "flow") {
|
|
267
|
+
files.push({
|
|
268
|
+
path: `app/flows/${name}/flow.test.ts`,
|
|
269
|
+
content: template === "echo" ? flowTestFile(name) : (0, flowTemplates_1.templateFiles)(template, name).test,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
return files;
|
|
273
|
+
}
|
|
274
|
+
/** Version spec for a non-`@loom` dependency a template imports. */
|
|
275
|
+
exports.THIRD_PARTY_SPECS = {
|
|
276
|
+
zod: "^3.23.8",
|
|
277
|
+
vitest: "^2.1.8",
|
|
278
|
+
};
|
|
279
|
+
/** Package names a generated file imports (bare specifiers only; `node:` and relative excluded). */
|
|
280
|
+
function importedPackages(content) {
|
|
281
|
+
const out = new Set();
|
|
282
|
+
for (const m of content.matchAll(/^\s*import\b[^"']*?from\s+["']([^"']+)["']/gm)) {
|
|
283
|
+
const spec = m[1];
|
|
284
|
+
if (spec.startsWith(".") || spec.startsWith("node:"))
|
|
285
|
+
continue;
|
|
286
|
+
const parts = spec.split("/");
|
|
287
|
+
out.add(spec.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0]);
|
|
288
|
+
}
|
|
289
|
+
return [...out].sort();
|
|
290
|
+
}
|
|
291
|
+
// ── Whole-app scaffold (used by create-loom-app), following the convention ────
|
|
292
|
+
/**
|
|
293
|
+
* `JSON.stringify` leaves bidi, zero-width, line-separator and tag characters raw (all legal
|
|
294
|
+
* in JSON); rewrite them as `\\uXXXX` escapes (still valid JSON, same value) so the manifest
|
|
295
|
+
* reads as what it parses to.
|
|
296
|
+
*/
|
|
297
|
+
function jsonText(json) {
|
|
298
|
+
return json.replace(/[\u007f-\u009f\u00ad\u200b-\u200f\u2028-\u202e\u2060-\u206f\ufeff\u{e0000}-\u{e007f}]/gu, (c) => {
|
|
299
|
+
const cp = c.codePointAt(0);
|
|
300
|
+
if (cp <= 0xffff)
|
|
301
|
+
return `\\u${cp.toString(16).padStart(4, "0")}`;
|
|
302
|
+
const v = cp - 0x10000;
|
|
303
|
+
return `\\u${(0xd800 + (v >> 10)).toString(16)}\\u${(0xdc00 + (v & 0x3ff)).toString(16)}`;
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
function appFiles(appName) {
|
|
307
|
+
return {
|
|
308
|
+
"package.json": `${jsonText(JSON.stringify({
|
|
309
|
+
name: appName,
|
|
310
|
+
private: true,
|
|
311
|
+
// CommonJS (no "type": "module") — @loomwork/* publish require-only exports, so
|
|
312
|
+
// `tsx app/main.ts` must resolve them via CJS (matches the loom-starter example).
|
|
313
|
+
scripts: {
|
|
314
|
+
start: "tsx app/main.ts",
|
|
315
|
+
test: "vitest run",
|
|
316
|
+
gen: "loom gen --dir app",
|
|
317
|
+
},
|
|
318
|
+
dependencies: {
|
|
319
|
+
// `surface(ctx)` / the typing of `ctx.ui` (ADR 0114): a flow that drives a UI surface imports it.
|
|
320
|
+
"@loomwork/agent-surface": "workspace:*",
|
|
321
|
+
"@loomwork/app": "workspace:*",
|
|
322
|
+
"@loomwork/core": "workspace:*",
|
|
323
|
+
"@loomwork/effect-runtime": "workspace:*",
|
|
324
|
+
"@loomwork/middleware": "workspace:*",
|
|
325
|
+
"@loomwork/workflow-runtime": "workspace:*",
|
|
326
|
+
zod: "^3.23.8",
|
|
327
|
+
},
|
|
328
|
+
devDependencies: {
|
|
329
|
+
"@loomwork/cli": "workspace:*",
|
|
330
|
+
"@loomwork/testing": "workspace:*", // `loom new flow` emits a createTestApp test
|
|
331
|
+
tsx: "^4.19.2",
|
|
332
|
+
typescript: "^5.6.3",
|
|
333
|
+
vitest: "^2.1.8",
|
|
334
|
+
},
|
|
335
|
+
}, null, 2))}\n`,
|
|
336
|
+
"loom.config.ts": ['export { app as default } from "./app/config";', ""].join("\n"),
|
|
337
|
+
"app/flows/greet/flow.ts": flowFile("greet"),
|
|
338
|
+
// Pre-generated so the app runs out of the box; re-run `pnpm gen` after
|
|
339
|
+
// adding flows with `loom new flow <name>`.
|
|
340
|
+
"app/loom.gen.ts": (0, codegen_1.generateRegistration)(["./flows/greet/flow"]),
|
|
341
|
+
"app/middleware.ts": [
|
|
342
|
+
'import { retryMiddleware } from "@loomwork/middleware";',
|
|
343
|
+
"",
|
|
344
|
+
"// Cross-cutting effect middleware, applied in order (middleware[0] outermost).",
|
|
345
|
+
"export const middleware = [retryMiddleware({ maxRetries: 2 })];",
|
|
346
|
+
"",
|
|
347
|
+
].join("\n"),
|
|
348
|
+
"app/security.ts": [
|
|
349
|
+
'import { createHash } from "node:crypto";',
|
|
350
|
+
'import { GrantTable, type PrincipalChain } from "@loomwork/effect-runtime";',
|
|
351
|
+
"import {",
|
|
352
|
+
" type ExecutionAuthorizer,",
|
|
353
|
+
" type PrincipalCodec,",
|
|
354
|
+
" executionAccessPolicy,",
|
|
355
|
+
" signedResumeAuthenticator,",
|
|
356
|
+
'} from "@loomwork/workflow-runtime";',
|
|
357
|
+
"",
|
|
358
|
+
"// The pieces `security.strict` REFUSES to start without. They are yours: they",
|
|
359
|
+
"// encode who may do what, which a framework cannot guess. These are deliberately small",
|
|
360
|
+
"// stubs — read them, then tighten them.",
|
|
361
|
+
"",
|
|
362
|
+
"// Which effects each flow may run (the K2 capability ring). An effect not listed here is",
|
|
363
|
+
"// DENIED (CapabilityDeniedError) — so when you add a flow with `loom new flow <name>`,",
|
|
364
|
+
"// add its tool ids here too. Step ids double as tool ids unless a step sets `toolId`.",
|
|
365
|
+
"export const authorizer = new GrantTable({",
|
|
366
|
+
' greet: ["greet-step"],',
|
|
367
|
+
"});",
|
|
368
|
+
"",
|
|
369
|
+
"// Who may start / resume / cancel / query an execution. Under `security.strict` a call with",
|
|
370
|
+
"// NO principal is refused (attach an authenticated one at your API edge: `start(flow, input,",
|
|
371
|
+
"// { principal })`); the kernel's own machinery (timers, recovery, child spawn) is exempt.",
|
|
372
|
+
"// `executionAccessPolicy` is loom's reference policy: the actor that starts an execution owns",
|
|
373
|
+
"// it, and only that actor — in the same tenant — may resume, cancel or read it. The kernel",
|
|
374
|
+
"// records who started an execution (ADR 0111) and hands it to the policy, so ownership",
|
|
375
|
+
"// survives restarts; a flow's effects keep running as that owner after an approval, a timer",
|
|
376
|
+
"// wake or a recovery.",
|
|
377
|
+
"export const executionAuthorizer: ExecutionAuthorizer = executionAccessPolicy({",
|
|
378
|
+
" requireTenant: true,",
|
|
379
|
+
' rules: { start: "any", resume: "owner", cancel: "owner", query: "owner" },',
|
|
380
|
+
"});",
|
|
381
|
+
"",
|
|
382
|
+
"// How a principal is written into the log. Under `security.strict` the log must never carry",
|
|
383
|
+
"// a principal's identity (tenant / actor) verbatim — a permanent log cannot be redacted — so",
|
|
384
|
+
"// it records an OPAQUE ref and the runtime asks this codec to turn the ref back into the",
|
|
385
|
+
"// principal whenever the execution resumes (after an approval, a timer, a crash). THIS STUB",
|
|
386
|
+
'// keeps the table in memory, which matches `storage: { kind: "memory" }`: back it with your',
|
|
387
|
+
"// user table the day you move to a durable store. (Alternatively compose crypto and pass",
|
|
388
|
+
"// `security.crypto` so the identity is encrypted at rest and shredded with the subject.)",
|
|
389
|
+
"const principals = new Map<string, PrincipalChain>();",
|
|
390
|
+
"export const principalCodec: PrincipalCodec = {",
|
|
391
|
+
" toRef(chain) {",
|
|
392
|
+
" const { tenant, actor, onBehalfOf } = chain;",
|
|
393
|
+
' const ref = "p:" + createHash("sha256").update(JSON.stringify([tenant, actor, onBehalfOf])).digest("hex").slice(0, 32);',
|
|
394
|
+
" principals.set(ref, { ...(tenant !== undefined && { tenant }), ...(actor !== undefined && { actor }), ...(onBehalfOf !== undefined && { onBehalfOf }) });",
|
|
395
|
+
" return ref;",
|
|
396
|
+
" },",
|
|
397
|
+
" fromRef: (ref) => principals.get(ref),",
|
|
398
|
+
"};",
|
|
399
|
+
"",
|
|
400
|
+
"// Who APPROVED a parked gate (R13). With no authenticator ANY caller of `resume()` approves,",
|
|
401
|
+
"// and nobody is on record as having done so. An approver signs the resume event for ONE park:",
|
|
402
|
+
"// signResume(answerApproval(state, { approved: true }), {",
|
|
403
|
+
"// actor, secret, exp: Date.now() + 60_000,",
|
|
404
|
+
"// executionId, parkedAtSequence: await runtime.parkedAtSequence(executionId),",
|
|
405
|
+
"// })",
|
|
406
|
+
"// The runtime verifies it, records APPROVAL_GRANTED { actor, verifiedBy }, refuses a stale view",
|
|
407
|
+
"// (the echoed viewDigest) and a replayed signature (another execution, another park), all",
|
|
408
|
+
"// before anything is appended. Keys come from YOUR secret store; this reads one env var per",
|
|
409
|
+
"// approver (LOOM_APPROVER_KEY_<ACTOR>, 16+ bytes) and FAILS CLOSED: an actor with odd",
|
|
410
|
+
"// characters, an unset or empty variable is simply not an approver. Add your own gate names.",
|
|
411
|
+
"export const resumeAuthenticator = signedResumeAuthenticator({",
|
|
412
|
+
' gates: ["AgentToolApproval", "ApprovalGranted"],',
|
|
413
|
+
" keys: (actor) => {",
|
|
414
|
+
" if (!/^[A-Za-z0-9_]+$/.test(actor)) return undefined;",
|
|
415
|
+
' const key = process.env["LOOM_APPROVER_KEY_" + actor.toUpperCase()];',
|
|
416
|
+
' return key === undefined || key === "" ? undefined : key;',
|
|
417
|
+
" },",
|
|
418
|
+
"});",
|
|
419
|
+
"",
|
|
420
|
+
].join("\n"),
|
|
421
|
+
"app/config.ts": [
|
|
422
|
+
'import { defineConfig } from "@loomwork/app";',
|
|
423
|
+
'import { agentModules, flowModules, projectionModules, skillModules, toolModules } from "./loom.gen";',
|
|
424
|
+
'import { middleware } from "./middleware";',
|
|
425
|
+
'import { authorizer, executionAuthorizer, principalCodec, resumeAuthenticator } from "./security";',
|
|
426
|
+
"",
|
|
427
|
+
"// The whole app, declared once. Flows/agents/tools/skills/projections are discovered",
|
|
428
|
+
"// from app/{flows,agents,tools,skills,projections} via `loom gen` (app/loom.gen.ts). Set",
|
|
429
|
+
"// `a2a: true` to auto-expose agents on the A2A bus. Swap storage to sqlite for durability.",
|
|
430
|
+
"//",
|
|
431
|
+
"// `security.strict` flips loom's permissive defaults to a safe baseline (R9): both",
|
|
432
|
+
"// authorizers and the resumeAuthenticator are REQUIRED (see ./security), flows without a `deadlineMs` get a default",
|
|
433
|
+
"// deadline, child spawns are depth/breadth-capped, each execution has a token budget, and",
|
|
434
|
+
"// `app.killSwitch` can stop effects system-wide / per tenant / per flow. It is on here so",
|
|
435
|
+
"// you start safe; set `strict: false` to opt out explicitly (no advisory is then logged).",
|
|
436
|
+
"// For agents, pass `requireEffectRing: true` to `agentLoop$` so no model call bypasses it.",
|
|
437
|
+
"export const app = defineConfig({",
|
|
438
|
+
' storage: { kind: "memory" },',
|
|
439
|
+
" flowModules,",
|
|
440
|
+
" agentModules, // set a2a: true / agentSurface: true to auto-wire discovered agents",
|
|
441
|
+
" toolModules, // discovered tool definitions on app.tools; register effects yourself",
|
|
442
|
+
" skillModules, // discovered skills registered into app.skills (app.skills.find(query))",
|
|
443
|
+
" projectionModules, // discovered projections folded into the projection runtime",
|
|
444
|
+
" security: { strict: true, authorizer, executionAuthorizer, resumeAuthenticator, principalCodec },",
|
|
445
|
+
" execution: { effectMiddleware: middleware },",
|
|
446
|
+
"});",
|
|
447
|
+
"",
|
|
448
|
+
].join("\n"),
|
|
449
|
+
"app/main.ts": [
|
|
450
|
+
'import { app } from "./config";',
|
|
451
|
+
'import { GreetFlow } from "./flows/greet/flow";',
|
|
452
|
+
"",
|
|
453
|
+
"async function main() {",
|
|
454
|
+
" // Under `security.strict` every call names who is acting (see ./security).",
|
|
455
|
+
' const principal = { actor: "demo-user", tenant: "demo" };',
|
|
456
|
+
' const handle = await app.runtime.start(GreetFlow, { input: "world" }, { principal });',
|
|
457
|
+
" const state = await handle.waitForCompletion();",
|
|
458
|
+
" console.log(state.variables._output);",
|
|
459
|
+
" await app.close();",
|
|
460
|
+
"}",
|
|
461
|
+
"",
|
|
462
|
+
"void main();",
|
|
463
|
+
"",
|
|
464
|
+
].join("\n"),
|
|
465
|
+
"app/greet.test.ts": [
|
|
466
|
+
'import { describe, expect, it } from "vitest";',
|
|
467
|
+
'import { app } from "./config";',
|
|
468
|
+
'import { GreetFlow } from "./flows/greet/flow";',
|
|
469
|
+
"",
|
|
470
|
+
"// A minimal eval. For log-as-fixture / scoring evals, see @loomwork/eval and",
|
|
471
|
+
"// `loom eval`.",
|
|
472
|
+
'describe("greet", () => {',
|
|
473
|
+
' it("runs the flow end to end", async () => {',
|
|
474
|
+
' const principal = { actor: "demo-user", tenant: "demo" };',
|
|
475
|
+
' const handle = await app.runtime.start(GreetFlow, { input: "world" }, { principal });',
|
|
476
|
+
" const state = await handle.waitForCompletion();",
|
|
477
|
+
' expect((state.variables._output as { output: string }).output).toBe("world");',
|
|
478
|
+
" await app.close();",
|
|
479
|
+
" });",
|
|
480
|
+
"});",
|
|
481
|
+
"",
|
|
482
|
+
].join("\n"),
|
|
483
|
+
"vitest.config.ts": [
|
|
484
|
+
'import { defineConfig } from "vitest/config";',
|
|
485
|
+
"",
|
|
486
|
+
"export default defineConfig({",
|
|
487
|
+
" // @loomwork/* publish require-only exports — resolve them the same way under Vite.",
|
|
488
|
+
' resolve: { conditions: ["require", "default"] },',
|
|
489
|
+
' test: { environment: "node" },',
|
|
490
|
+
"});",
|
|
491
|
+
"",
|
|
492
|
+
].join("\n"),
|
|
493
|
+
"tsconfig.json": `${JSON.stringify({
|
|
494
|
+
compilerOptions: {
|
|
495
|
+
target: "ES2022",
|
|
496
|
+
module: "CommonJS",
|
|
497
|
+
moduleResolution: "Node",
|
|
498
|
+
strict: true,
|
|
499
|
+
esModuleInterop: true,
|
|
500
|
+
skipLibCheck: true,
|
|
501
|
+
},
|
|
502
|
+
include: ["app/**/*"],
|
|
503
|
+
}, null, 2)}\n`,
|
|
504
|
+
"README.md": [
|
|
505
|
+
// One line of plain heading text: line breaks, control/bidi characters and markdown/HTML
|
|
506
|
+
// metacharacters in the name are neutralised, so it can never open a section or a tag.
|
|
507
|
+
`# ${(0, emit_1.markdownText)(appName)}`,
|
|
508
|
+
"",
|
|
509
|
+
"A Loom app scaffolded with `create-loom-app`, following the folder convention:",
|
|
510
|
+
"",
|
|
511
|
+
"```",
|
|
512
|
+
"app/",
|
|
513
|
+
" flows/<name>/flow.ts your flows (add with: loom new flow <name>)",
|
|
514
|
+
" tools/<name>.ts tools (loom new tool <name>)",
|
|
515
|
+
" agents/<name>.ts agents (loom new agent <name>)",
|
|
516
|
+
" skills/<name>.ts skills (loom new skill <name>)",
|
|
517
|
+
" schedules/<name>.ts schedules (loom new schedule <name>)",
|
|
518
|
+
" memories/<name>.ts memories (loom new memory <name>)",
|
|
519
|
+
" projections/<name>.ts projections (loom new projection <name>)",
|
|
520
|
+
" middleware.ts cross-cutting effect middleware",
|
|
521
|
+
" security.ts the authorizers `security.strict` requires (edit these)",
|
|
522
|
+
" config.ts the app (defineConfig)",
|
|
523
|
+
" loom.gen.ts generated flow registration (pnpm gen)",
|
|
524
|
+
"```",
|
|
525
|
+
"",
|
|
526
|
+
"```sh",
|
|
527
|
+
"pnpm install",
|
|
528
|
+
"pnpm start # run the flow once",
|
|
529
|
+
"pnpm test # run the eval",
|
|
530
|
+
"pnpm gen # regenerate app/loom.gen.ts after adding flows",
|
|
531
|
+
"```",
|
|
532
|
+
"",
|
|
533
|
+
].join("\n"),
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,51 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loomwork/scaffold",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Shared code templates + registration codegen for Loom — used by create-loom-app (whole app) and `loom new`/`loom gen` (single files + generated registration)",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"require": "./dist/index.js",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/node": "^22.0.0",
|
|
16
|
+
"typescript": "^5.6.3",
|
|
17
|
+
"vitest": "^2.1.8"
|
|
18
|
+
},
|
|
19
|
+
"license": "Apache-2.0",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/chhetrisushil/loom.git",
|
|
23
|
+
"directory": "tools/scaffold"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"src",
|
|
28
|
+
"!src/**/*.test.ts",
|
|
29
|
+
"!src/**/*.test.tsx",
|
|
30
|
+
"!src/**/__tests__",
|
|
31
|
+
"!src/**/__fixtures__",
|
|
32
|
+
"!src/**/__snapshots__",
|
|
33
|
+
"!src/**/__golden__",
|
|
34
|
+
"LICENSE",
|
|
35
|
+
"NOTICE"
|
|
36
|
+
],
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public",
|
|
39
|
+
"tag": "next"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=20.0.0"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsc --build",
|
|
46
|
+
"dev": "tsc --build --watch",
|
|
47
|
+
"test": "vitest run",
|
|
48
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
49
|
+
"typecheck:tests": "tsc -p tsconfig.test.json"
|
|
50
|
+
}
|
|
6
51
|
}
|