@wopr-network/defcon 1.0.0 → 1.0.2

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.
@@ -138,10 +138,11 @@ export function createHttpServer(deps) {
138
138
  router.add("POST", "/api/entities", async (req) => {
139
139
  const flowName = req.body?.flow;
140
140
  const refs = req.body?.refs;
141
+ const payload = req.body?.payload;
141
142
  if (!flowName)
142
143
  return { status: 400, body: { error: "Missing required field: flow" } };
143
144
  try {
144
- const entity = await deps.engine.createEntity(flowName, refs);
145
+ const entity = await deps.engine.createEntity(flowName, refs, payload);
145
146
  return { status: 201, body: entity };
146
147
  }
147
148
  catch (err) {
@@ -54,7 +54,7 @@ export declare class Engine {
54
54
  adapter: string;
55
55
  id: string;
56
56
  [key: string]: unknown;
57
- }>): Promise<Entity>;
57
+ }>, payload?: Record<string, unknown>): Promise<Entity>;
58
58
  claimWork(role: string, flowName?: string, worker_id?: string): Promise<ClaimWorkResult | "all_claimed" | null>;
59
59
  private buildPromptForEntity;
60
60
  getStatus(): Promise<EngineStatus>;
@@ -241,11 +241,19 @@ export class Engine {
241
241
  }
242
242
  return result;
243
243
  }
244
- async createEntity(flowName, refs) {
244
+ async createEntity(flowName, refs, payload) {
245
245
  const flow = await this.flowRepo.getByName(flowName);
246
246
  if (!flow)
247
247
  throw new NotFoundError(`Flow "${flowName}" not found`);
248
- const entity = await this.entityRepo.create(flow.id, flow.initialState, refs);
248
+ let entity = await this.entityRepo.create(flow.id, flow.initialState, refs);
249
+ // Store any caller-supplied payload as initial artifacts so prompt templates
250
+ // can access refs like {{entity.artifacts.refs.linear.id}}.
251
+ if (payload && Object.keys(payload).length > 0) {
252
+ await this.entityRepo.updateArtifacts(entity.id, payload);
253
+ const refreshed = await this.entityRepo.get(entity.id);
254
+ if (refreshed)
255
+ entity = refreshed;
256
+ }
249
257
  await this.eventEmitter.emit({
250
258
  type: "entity.created",
251
259
  entityId: entity.id,
@@ -30,7 +30,18 @@ export async function buildInvocation(state, entity, adapters, flow, logger = co
30
30
  }
31
31
  }
32
32
  }));
33
- const context = { entity, state, refs: resolvedRefs, flow: flow ?? null };
33
+ // Merge payload-stored refs (entity.artifacts.refs) into entity.refs for template context,
34
+ // so {{entity.refs.linear.id}} works whether refs were set via formal adapters or via payload.
35
+ // Normalize to empty object so Handlebars strict mode doesn't throw on missing paths.
36
+ const artifactRefs = entity.artifacts !== null &&
37
+ typeof entity.artifacts === "object" &&
38
+ "refs" in entity.artifacts &&
39
+ entity.artifacts.refs !== null &&
40
+ typeof entity.artifacts.refs === "object"
41
+ ? entity.artifacts.refs
42
+ : {};
43
+ const entityForContext = { ...entity, refs: { ...artifactRefs, ...(entity.refs ?? {}) } };
44
+ const context = { entity: entityForContext, state, refs: resolvedRefs, flow: flow ?? null };
34
45
  let prompt = "";
35
46
  let systemPrompt = "";
36
47
  let userContent = "";
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createHash, timingSafeEqual } from "node:crypto";
3
- import { writeFileSync } from "node:fs";
3
+ import { readdirSync, writeFileSync } from "node:fs";
4
4
  import { homedir } from "node:os";
5
5
  import { join, resolve } from "node:path";
6
6
  import { pathToFileURL } from "node:url";
@@ -55,7 +55,22 @@ export function validateWorkerToken(opts) {
55
55
  "Set DEFCON_WORKER_TOKEN in your environment or use stdio transport for local-only access.");
56
56
  }
57
57
  }
58
- const MIGRATIONS_FOLDER = new URL("../../drizzle", import.meta.url).pathname;
58
+ // Resolve drizzle migrations folder. Works for both tsx (src/) and compiled (dist/src/) contexts.
59
+ const MIGRATIONS_FOLDER = (() => {
60
+ const candidates = ["../../drizzle", "../../../drizzle"].map((rel) => new URL(rel, import.meta.url).pathname);
61
+ const found = candidates.find((p) => {
62
+ try {
63
+ readdirSync(p);
64
+ return true;
65
+ }
66
+ catch {
67
+ return false;
68
+ }
69
+ });
70
+ if (!found)
71
+ throw new Error(`Cannot find drizzle migrations folder (tried: ${candidates.join(", ")})`);
72
+ return found;
73
+ })();
59
74
  const REAPER_INTERVAL_DEFAULT = "30000"; // 30s
60
75
  const CLAIM_TTL_DEFAULT = "300000"; // 5min
61
76
  function openDb(dbPath) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wopr-network/defcon",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "packageManager": "pnpm@9.15.4",
6
6
  "engines": {