@wopr-network/defcon 0.2.0 → 0.2.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.
- package/dist/src/execution/cli.js +0 -0
- package/package.json +3 -2
- package/dist/api/router.d.ts +0 -24
- package/dist/api/router.js +0 -44
- package/dist/api/server.d.ts +0 -13
- package/dist/api/server.js +0 -280
- package/dist/api/wire-types.d.ts +0 -46
- package/dist/api/wire-types.js +0 -5
- package/dist/config/db-path.d.ts +0 -1
- package/dist/config/db-path.js +0 -1
- package/dist/config/exporter.d.ts +0 -3
- package/dist/config/exporter.js +0 -87
- package/dist/config/index.d.ts +0 -4
- package/dist/config/index.js +0 -4
- package/dist/config/seed-loader.d.ts +0 -10
- package/dist/config/seed-loader.js +0 -108
- package/dist/config/zod-schemas.d.ts +0 -165
- package/dist/config/zod-schemas.js +0 -283
- package/dist/cors.d.ts +0 -8
- package/dist/cors.js +0 -21
- package/dist/engine/constants.d.ts +0 -1
- package/dist/engine/constants.js +0 -1
- package/dist/engine/engine.d.ts +0 -69
- package/dist/engine/engine.js +0 -485
- package/dist/engine/event-emitter.d.ts +0 -9
- package/dist/engine/event-emitter.js +0 -19
- package/dist/engine/event-types.d.ts +0 -105
- package/dist/engine/event-types.js +0 -1
- package/dist/engine/flow-spawner.d.ts +0 -8
- package/dist/engine/flow-spawner.js +0 -28
- package/dist/engine/gate-command-validator.d.ts +0 -6
- package/dist/engine/gate-command-validator.js +0 -46
- package/dist/engine/gate-evaluator.d.ts +0 -12
- package/dist/engine/gate-evaluator.js +0 -233
- package/dist/engine/handlebars.d.ts +0 -9
- package/dist/engine/handlebars.js +0 -51
- package/dist/engine/index.d.ts +0 -12
- package/dist/engine/index.js +0 -7
- package/dist/engine/invocation-builder.d.ts +0 -18
- package/dist/engine/invocation-builder.js +0 -58
- package/dist/engine/on-enter.d.ts +0 -8
- package/dist/engine/on-enter.js +0 -102
- package/dist/engine/ssrf-guard.d.ts +0 -22
- package/dist/engine/ssrf-guard.js +0 -159
- package/dist/engine/state-machine.d.ts +0 -12
- package/dist/engine/state-machine.js +0 -74
- package/dist/execution/active-runner.d.ts +0 -45
- package/dist/execution/active-runner.js +0 -165
- package/dist/execution/admin-schemas.d.ts +0 -116
- package/dist/execution/admin-schemas.js +0 -125
- package/dist/execution/cli.d.ts +0 -57
- package/dist/execution/cli.js +0 -498
- package/dist/execution/handlers/admin.d.ts +0 -67
- package/dist/execution/handlers/admin.js +0 -200
- package/dist/execution/handlers/flow.d.ts +0 -25
- package/dist/execution/handlers/flow.js +0 -289
- package/dist/execution/handlers/query.d.ts +0 -31
- package/dist/execution/handlers/query.js +0 -64
- package/dist/execution/index.d.ts +0 -4
- package/dist/execution/index.js +0 -3
- package/dist/execution/mcp-helpers.d.ts +0 -42
- package/dist/execution/mcp-helpers.js +0 -23
- package/dist/execution/mcp-server.d.ts +0 -33
- package/dist/execution/mcp-server.js +0 -1020
- package/dist/execution/provision-worktree.d.ts +0 -16
- package/dist/execution/provision-worktree.js +0 -123
- package/dist/execution/tool-schemas.d.ts +0 -40
- package/dist/execution/tool-schemas.js +0 -44
- package/dist/logger.d.ts +0 -8
- package/dist/logger.js +0 -12
- package/dist/main.d.ts +0 -14
- package/dist/main.js +0 -28
- package/dist/repositories/drizzle/entity.repo.d.ts +0 -27
- package/dist/repositories/drizzle/entity.repo.js +0 -190
- package/dist/repositories/drizzle/event.repo.d.ts +0 -12
- package/dist/repositories/drizzle/event.repo.js +0 -24
- package/dist/repositories/drizzle/flow.repo.d.ts +0 -22
- package/dist/repositories/drizzle/flow.repo.js +0 -364
- package/dist/repositories/drizzle/gate.repo.d.ts +0 -16
- package/dist/repositories/drizzle/gate.repo.js +0 -98
- package/dist/repositories/drizzle/index.d.ts +0 -6
- package/dist/repositories/drizzle/index.js +0 -7
- package/dist/repositories/drizzle/invocation.repo.d.ts +0 -23
- package/dist/repositories/drizzle/invocation.repo.js +0 -199
- package/dist/repositories/drizzle/schema.d.ts +0 -1932
- package/dist/repositories/drizzle/schema.js +0 -155
- package/dist/repositories/drizzle/transition-log.repo.d.ts +0 -11
- package/dist/repositories/drizzle/transition-log.repo.js +0 -42
- package/dist/repositories/interfaces.d.ts +0 -321
- package/dist/repositories/interfaces.js +0 -2
- package/dist/utils/redact.d.ts +0 -2
- package/dist/utils/redact.js +0 -62
- package/gates/blocking-graph.d.ts +0 -26
- package/gates/blocking-graph.js +0 -102
- package/gates/test/bad-return-gate.d.ts +0 -1
- package/gates/test/bad-return-gate.js +0 -4
- package/gates/test/passing-gate.d.ts +0 -2
- package/gates/test/passing-gate.js +0 -3
- package/gates/test/slow-gate.d.ts +0 -2
- package/gates/test/slow-gate.js +0 -5
- package/gates/test/throwing-gate.d.ts +0 -1
- package/gates/test/throwing-gate.js +0 -3
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export interface ProvisionWorktreeResult {
|
|
2
|
-
worktreePath: string;
|
|
3
|
-
branch: string;
|
|
4
|
-
repo: string;
|
|
5
|
-
}
|
|
6
|
-
export declare function parseIssueNumber(issueKey: string): string;
|
|
7
|
-
export declare function repoName(repo: string): string;
|
|
8
|
-
export declare function validateRepoName(name: string): string;
|
|
9
|
-
export declare function buildBranch(issueKey: string): string;
|
|
10
|
-
export declare function buildWorktreePath(repo: string, issueKey: string, basePath: string): string;
|
|
11
|
-
export declare function provisionWorktree(opts: {
|
|
12
|
-
repo: string;
|
|
13
|
-
issueKey: string;
|
|
14
|
-
basePath?: string;
|
|
15
|
-
cloneRoot?: string;
|
|
16
|
-
}): ProvisionWorktreeResult;
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { execFileSync } from "node:child_process";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { homedir } from "node:os";
|
|
4
|
-
import { join, resolve } from "node:path";
|
|
5
|
-
export function parseIssueNumber(issueKey) {
|
|
6
|
-
const match = issueKey.match(/^[A-Za-z]+[-](\d+)$/);
|
|
7
|
-
if (!match) {
|
|
8
|
-
throw new Error(`Invalid issue key: ${issueKey}. Expected format: WOP-123`);
|
|
9
|
-
}
|
|
10
|
-
return match[1];
|
|
11
|
-
}
|
|
12
|
-
export function repoName(repo) {
|
|
13
|
-
const parts = repo.replace(/\/$/, "").split("/");
|
|
14
|
-
return parts[parts.length - 1] || repo;
|
|
15
|
-
}
|
|
16
|
-
export function validateRepoName(name) {
|
|
17
|
-
if (!/^[a-zA-Z0-9._-]+$/.test(name)) {
|
|
18
|
-
throw new Error(`Invalid repo name: ${name}`);
|
|
19
|
-
}
|
|
20
|
-
if (name === "." || name === "..") {
|
|
21
|
-
throw new Error(`Invalid repo name: ${name}`);
|
|
22
|
-
}
|
|
23
|
-
return name;
|
|
24
|
-
}
|
|
25
|
-
export function buildBranch(issueKey) {
|
|
26
|
-
const num = parseIssueNumber(issueKey);
|
|
27
|
-
return `agent/coder-${num}/${issueKey.toLowerCase()}`;
|
|
28
|
-
}
|
|
29
|
-
export function buildWorktreePath(repo, issueKey, basePath) {
|
|
30
|
-
const name = repoName(repo);
|
|
31
|
-
const num = parseIssueNumber(issueKey);
|
|
32
|
-
return join(basePath, `wopr-${name}-coder-${num}`);
|
|
33
|
-
}
|
|
34
|
-
function run(cmd, args, cwd) {
|
|
35
|
-
try {
|
|
36
|
-
return execFileSync(cmd, args, {
|
|
37
|
-
cwd,
|
|
38
|
-
encoding: "utf-8",
|
|
39
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
40
|
-
}).trim();
|
|
41
|
-
}
|
|
42
|
-
catch (err) {
|
|
43
|
-
const e = err;
|
|
44
|
-
throw new Error(`${cmd} ${args.join(" ")} failed: ${e.stderr ?? e.message ?? String(err)}`);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
export function provisionWorktree(opts) {
|
|
48
|
-
const basePath = opts.basePath ?? join(homedir(), "worktrees");
|
|
49
|
-
const cloneRoot = opts.cloneRoot ?? homedir();
|
|
50
|
-
const name = validateRepoName(repoName(opts.repo));
|
|
51
|
-
const clonePath = join(cloneRoot, name);
|
|
52
|
-
if (!resolve(clonePath).startsWith(`${resolve(cloneRoot)}/`) && resolve(clonePath) !== resolve(cloneRoot)) {
|
|
53
|
-
throw new Error(`Repo name escapes cloneRoot: ${name}`);
|
|
54
|
-
}
|
|
55
|
-
const worktreePath = buildWorktreePath(opts.repo, opts.issueKey, basePath);
|
|
56
|
-
const branch = buildBranch(opts.issueKey);
|
|
57
|
-
// Idempotent: if worktree already exists, verify and return
|
|
58
|
-
if (existsSync(worktreePath)) {
|
|
59
|
-
try {
|
|
60
|
-
run("git", ["rev-parse", "--git-dir"], worktreePath);
|
|
61
|
-
const currentBranch = run("git", ["rev-parse", "--abbrev-ref", "HEAD"], worktreePath);
|
|
62
|
-
if (currentBranch !== branch) {
|
|
63
|
-
throw new Error(`Worktree at ${worktreePath} is on branch ${currentBranch}, expected ${branch}`);
|
|
64
|
-
}
|
|
65
|
-
const remoteUrl = run("git", ["remote", "get-url", "origin"], worktreePath);
|
|
66
|
-
const repoPath = opts.repo.replace(/\.git$/, "");
|
|
67
|
-
const urlMatchesRepo = remoteUrl.endsWith(`/${repoPath}`) ||
|
|
68
|
-
remoteUrl.endsWith(`/${repoPath}.git`) ||
|
|
69
|
-
remoteUrl.endsWith(`:${repoPath}`) ||
|
|
70
|
-
remoteUrl.endsWith(`:${repoPath}.git`);
|
|
71
|
-
if (!urlMatchesRepo) {
|
|
72
|
-
throw new Error(`Worktree at ${worktreePath} has unexpected remote: ${remoteUrl} (expected to contain ${opts.repo})`);
|
|
73
|
-
}
|
|
74
|
-
return { worktreePath, branch, repo: opts.repo };
|
|
75
|
-
}
|
|
76
|
-
catch (err) {
|
|
77
|
-
if (err instanceof Error && err.message.startsWith("Worktree at")) {
|
|
78
|
-
throw err;
|
|
79
|
-
}
|
|
80
|
-
throw new Error(`Path ${worktreePath} exists but is not a git worktree`);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
// Clone if repo not present
|
|
84
|
-
if (!existsSync(clonePath)) {
|
|
85
|
-
const cloneUrl = `https://github.com/${opts.repo}.git`;
|
|
86
|
-
process.stderr.write(`Cloning ${cloneUrl} to ${clonePath}...\n`);
|
|
87
|
-
run("git", ["clone", cloneUrl, clonePath]);
|
|
88
|
-
}
|
|
89
|
-
// Fetch latest
|
|
90
|
-
process.stderr.write(`Fetching origin in ${clonePath}...\n`);
|
|
91
|
-
run("git", ["fetch", "origin"], clonePath);
|
|
92
|
-
// Create worktree
|
|
93
|
-
process.stderr.write(`Creating worktree at ${worktreePath}...\n`);
|
|
94
|
-
const defaultBranchRef = run("git", ["symbolic-ref", "refs/remotes/origin/HEAD", "--short"], clonePath);
|
|
95
|
-
const defaultBranch = defaultBranchRef.replace("origin/", "");
|
|
96
|
-
try {
|
|
97
|
-
run("git", ["worktree", "add", worktreePath, "-b", branch, `origin/${defaultBranch}`], clonePath);
|
|
98
|
-
}
|
|
99
|
-
catch (err) {
|
|
100
|
-
// Branch may already exist — check if a worktree with the right branch is now present
|
|
101
|
-
if (existsSync(worktreePath)) {
|
|
102
|
-
try {
|
|
103
|
-
run("git", ["rev-parse", "--git-dir"], worktreePath);
|
|
104
|
-
const currentBranch = run("git", ["rev-parse", "--abbrev-ref", "HEAD"], worktreePath);
|
|
105
|
-
if (currentBranch === branch) {
|
|
106
|
-
// Worktree already exists on the correct branch — idempotent success
|
|
107
|
-
return { worktreePath, branch, repo: opts.repo };
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
catch {
|
|
111
|
-
// fall through to rethrow original error
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
throw err;
|
|
115
|
-
}
|
|
116
|
-
// Install dependencies
|
|
117
|
-
const hasPnpmLock = existsSync(join(worktreePath, "pnpm-lock.yaml"));
|
|
118
|
-
const hasYarnLock = existsSync(join(worktreePath, "yarn.lock"));
|
|
119
|
-
const installCmd = hasPnpmLock ? "pnpm" : hasYarnLock ? "yarn" : "npm";
|
|
120
|
-
process.stderr.write(`Running ${installCmd} install in ${worktreePath}...\n`);
|
|
121
|
-
execFileSync(installCmd, ["install"], { cwd: worktreePath, stdio: "inherit" });
|
|
122
|
-
return { worktreePath, branch, repo: opts.repo };
|
|
123
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v4";
|
|
2
|
-
export declare const FlowClaimSchema: z.ZodObject<{
|
|
3
|
-
worker_id: z.ZodOptional<z.ZodString>;
|
|
4
|
-
role: z.ZodString;
|
|
5
|
-
flow: z.ZodOptional<z.ZodString>;
|
|
6
|
-
}, z.core.$strip>;
|
|
7
|
-
export declare const FlowGetPromptSchema: z.ZodObject<{
|
|
8
|
-
entity_id: z.ZodString;
|
|
9
|
-
}, z.core.$strip>;
|
|
10
|
-
export declare const FlowReportSchema: z.ZodObject<{
|
|
11
|
-
entity_id: z.ZodString;
|
|
12
|
-
signal: z.ZodString;
|
|
13
|
-
artifacts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
14
|
-
worker_id: z.ZodOptional<z.ZodString>;
|
|
15
|
-
}, z.core.$strip>;
|
|
16
|
-
export declare const FlowFailSchema: z.ZodObject<{
|
|
17
|
-
entity_id: z.ZodString;
|
|
18
|
-
error: z.ZodString;
|
|
19
|
-
}, z.core.$strip>;
|
|
20
|
-
export declare const QueryEntitySchema: z.ZodObject<{
|
|
21
|
-
id: z.ZodString;
|
|
22
|
-
}, z.core.$strip>;
|
|
23
|
-
export declare const QueryEntitiesSchema: z.ZodObject<{
|
|
24
|
-
flow: z.ZodString;
|
|
25
|
-
state: z.ZodString;
|
|
26
|
-
limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
27
|
-
}, z.core.$strip>;
|
|
28
|
-
export declare const QueryInvocationsSchema: z.ZodObject<{
|
|
29
|
-
entity_id: z.ZodString;
|
|
30
|
-
}, z.core.$strip>;
|
|
31
|
-
export declare const QueryFlowSchema: z.ZodObject<{
|
|
32
|
-
name: z.ZodString;
|
|
33
|
-
}, z.core.$strip>;
|
|
34
|
-
export declare const FlowSeedSchema: z.ZodObject<{
|
|
35
|
-
flow: z.ZodString;
|
|
36
|
-
refs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
37
|
-
adapter: z.ZodString;
|
|
38
|
-
id: z.ZodString;
|
|
39
|
-
}, z.core.$loose>>>;
|
|
40
|
-
}, z.core.$strip>;
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v4";
|
|
2
|
-
export const FlowClaimSchema = z.object({
|
|
3
|
-
worker_id: z.string().min(1).optional(),
|
|
4
|
-
role: z.string().min(1),
|
|
5
|
-
flow: z.string().min(1).optional(),
|
|
6
|
-
});
|
|
7
|
-
export const FlowGetPromptSchema = z.object({
|
|
8
|
-
entity_id: z.string().min(1),
|
|
9
|
-
});
|
|
10
|
-
export const FlowReportSchema = z.object({
|
|
11
|
-
entity_id: z.string().min(1),
|
|
12
|
-
signal: z.string().min(1),
|
|
13
|
-
artifacts: z.record(z.string(), z.unknown()).optional(),
|
|
14
|
-
worker_id: z.string().min(1).optional(),
|
|
15
|
-
});
|
|
16
|
-
export const FlowFailSchema = z.object({
|
|
17
|
-
entity_id: z.string().min(1),
|
|
18
|
-
error: z.string().min(1),
|
|
19
|
-
});
|
|
20
|
-
export const QueryEntitySchema = z.object({
|
|
21
|
-
id: z.string().min(1),
|
|
22
|
-
});
|
|
23
|
-
export const QueryEntitiesSchema = z.object({
|
|
24
|
-
flow: z.string().min(1),
|
|
25
|
-
state: z.string().min(1),
|
|
26
|
-
limit: z.coerce.number().int().min(1).max(100).optional(),
|
|
27
|
-
});
|
|
28
|
-
export const QueryInvocationsSchema = z.object({
|
|
29
|
-
entity_id: z.string().min(1),
|
|
30
|
-
});
|
|
31
|
-
export const QueryFlowSchema = z.object({
|
|
32
|
-
name: z.string().min(1),
|
|
33
|
-
});
|
|
34
|
-
export const FlowSeedSchema = z.object({
|
|
35
|
-
flow: z.string().min(1),
|
|
36
|
-
refs: z
|
|
37
|
-
.record(z.string(), z
|
|
38
|
-
.object({
|
|
39
|
-
adapter: z.string().min(1),
|
|
40
|
-
id: z.string().min(1),
|
|
41
|
-
})
|
|
42
|
-
.passthrough())
|
|
43
|
-
.optional(),
|
|
44
|
-
});
|
package/dist/logger.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export interface Logger {
|
|
2
|
-
error(msg: string, ...args: unknown[]): void;
|
|
3
|
-
warn(msg: string, ...args: unknown[]): void;
|
|
4
|
-
info(msg: string, ...args: unknown[]): void;
|
|
5
|
-
debug(msg: string, ...args: unknown[]): void;
|
|
6
|
-
}
|
|
7
|
-
export declare const consoleLogger: Logger;
|
|
8
|
-
export declare const noopLogger: Logger;
|
package/dist/logger.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export const consoleLogger = {
|
|
2
|
-
error: (msg, ...args) => console.error(msg, ...args),
|
|
3
|
-
warn: (msg, ...args) => console.warn(msg, ...args),
|
|
4
|
-
info: (msg, ...args) => console.info(msg, ...args),
|
|
5
|
-
debug: (msg, ...args) => console.debug(msg, ...args),
|
|
6
|
-
};
|
|
7
|
-
export const noopLogger = {
|
|
8
|
-
error: () => { },
|
|
9
|
-
warn: () => { },
|
|
10
|
-
info: () => { },
|
|
11
|
-
debug: () => { },
|
|
12
|
-
};
|
package/dist/main.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import Database from "better-sqlite3";
|
|
2
|
-
import { drizzle } from "drizzle-orm/better-sqlite3";
|
|
3
|
-
import * as schema from "./repositories/drizzle/schema.js";
|
|
4
|
-
export declare function createDatabase(dbPath?: string): {
|
|
5
|
-
db: ReturnType<typeof drizzle<typeof schema>>;
|
|
6
|
-
sqlite: Database.Database;
|
|
7
|
-
};
|
|
8
|
-
export declare function runMigrations(db: ReturnType<typeof drizzle>, migrationsFolder?: string): void;
|
|
9
|
-
export declare function bootstrap(dbPath?: string): {
|
|
10
|
-
db: ReturnType<typeof drizzle>;
|
|
11
|
-
sqlite: Database.Database;
|
|
12
|
-
};
|
|
13
|
-
export * from "./api/wire-types.js";
|
|
14
|
-
export * from "./engine/index.js";
|
package/dist/main.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import Database from "better-sqlite3";
|
|
2
|
-
import { drizzle } from "drizzle-orm/better-sqlite3";
|
|
3
|
-
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
|
|
4
|
-
import { DB_PATH } from "./config/db-path.js";
|
|
5
|
-
import * as schema from "./repositories/drizzle/schema.js";
|
|
6
|
-
export function createDatabase(dbPath = DB_PATH) {
|
|
7
|
-
const sqlite = new Database(dbPath);
|
|
8
|
-
sqlite.pragma("journal_mode = WAL");
|
|
9
|
-
sqlite.pragma("foreign_keys = ON");
|
|
10
|
-
const db = drizzle(sqlite, { schema });
|
|
11
|
-
return { db, sqlite };
|
|
12
|
-
}
|
|
13
|
-
export function runMigrations(db, migrationsFolder = "./drizzle") {
|
|
14
|
-
migrate(db, { migrationsFolder });
|
|
15
|
-
}
|
|
16
|
-
export function bootstrap(dbPath = DB_PATH) {
|
|
17
|
-
const { db, sqlite } = createDatabase(dbPath);
|
|
18
|
-
try {
|
|
19
|
-
runMigrations(db);
|
|
20
|
-
}
|
|
21
|
-
catch (err) {
|
|
22
|
-
sqlite.close();
|
|
23
|
-
throw err;
|
|
24
|
-
}
|
|
25
|
-
return { db, sqlite };
|
|
26
|
-
}
|
|
27
|
-
export * from "./api/wire-types.js";
|
|
28
|
-
export * from "./engine/index.js";
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { BetterSQLite3Database } from "drizzle-orm/better-sqlite3";
|
|
2
|
-
import type { Artifacts, Entity, IEntityRepository, Refs } from "../interfaces.js";
|
|
3
|
-
import type * as schema from "./schema.js";
|
|
4
|
-
type Db = BetterSQLite3Database<typeof schema>;
|
|
5
|
-
export declare class DrizzleEntityRepository implements IEntityRepository {
|
|
6
|
-
private db;
|
|
7
|
-
constructor(db: Db);
|
|
8
|
-
private toEntity;
|
|
9
|
-
create(flowId: string, initialState: string, refs?: Refs): Promise<Entity>;
|
|
10
|
-
get(id: string): Promise<Entity | null>;
|
|
11
|
-
findByFlowAndState(flowId: string, state: string, limit?: number): Promise<Entity[]>;
|
|
12
|
-
hasAnyInFlowAndState(flowId: string, stateNames: string[]): Promise<boolean>;
|
|
13
|
-
transition(id: string, toState: string, _trigger: string, artifacts?: Partial<Artifacts>, _invocationId?: string | null): Promise<Entity>;
|
|
14
|
-
updateArtifacts(id: string, artifacts: Partial<Artifacts>): Promise<void>;
|
|
15
|
-
claim(flowId: string, state: string, agentId: string): Promise<Entity | null>;
|
|
16
|
-
claimById(entityId: string, agentId: string): Promise<Entity | null>;
|
|
17
|
-
release(entityId: string, agentId: string): Promise<void>;
|
|
18
|
-
appendSpawnedChild(parentId: string, entry: {
|
|
19
|
-
childId: string;
|
|
20
|
-
childFlow: string;
|
|
21
|
-
spawnedAt: string;
|
|
22
|
-
}): Promise<void>;
|
|
23
|
-
reapExpired(ttlMs: number): Promise<string[]>;
|
|
24
|
-
setAffinity(entityId: string, workerId: string, role: string, expiresAt: Date): Promise<void>;
|
|
25
|
-
clearExpiredAffinity(): Promise<string[]>;
|
|
26
|
-
}
|
|
27
|
-
export {};
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import { and, eq, inArray, isNull, lt, not } from "drizzle-orm";
|
|
2
|
-
import { entities } from "./schema.js";
|
|
3
|
-
export class DrizzleEntityRepository {
|
|
4
|
-
db;
|
|
5
|
-
constructor(db) {
|
|
6
|
-
this.db = db;
|
|
7
|
-
}
|
|
8
|
-
toEntity(row) {
|
|
9
|
-
return {
|
|
10
|
-
id: row.id,
|
|
11
|
-
flowId: row.flowId,
|
|
12
|
-
state: row.state,
|
|
13
|
-
refs: row.refs,
|
|
14
|
-
artifacts: row.artifacts,
|
|
15
|
-
claimedBy: row.claimedBy,
|
|
16
|
-
claimedAt: row.claimedAt ? new Date(row.claimedAt) : null,
|
|
17
|
-
flowVersion: row.flowVersion ?? 1,
|
|
18
|
-
priority: row.priority ?? 0,
|
|
19
|
-
createdAt: new Date(row.createdAt ?? 0),
|
|
20
|
-
updatedAt: new Date(row.updatedAt ?? 0),
|
|
21
|
-
affinityWorkerId: row.affinityWorkerId ?? null,
|
|
22
|
-
affinityRole: row.affinityRole ?? null,
|
|
23
|
-
affinityExpiresAt: row.affinityExpiresAt ? new Date(row.affinityExpiresAt) : null,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
async create(flowId, initialState, refs) {
|
|
27
|
-
const now = Date.now();
|
|
28
|
-
const id = crypto.randomUUID();
|
|
29
|
-
const row = {
|
|
30
|
-
id,
|
|
31
|
-
flowId,
|
|
32
|
-
state: initialState,
|
|
33
|
-
refs: refs ?? null,
|
|
34
|
-
artifacts: null,
|
|
35
|
-
claimedBy: null,
|
|
36
|
-
claimedAt: null,
|
|
37
|
-
flowVersion: 1,
|
|
38
|
-
createdAt: now,
|
|
39
|
-
updatedAt: now,
|
|
40
|
-
affinityWorkerId: null,
|
|
41
|
-
affinityRole: null,
|
|
42
|
-
affinityExpiresAt: null,
|
|
43
|
-
};
|
|
44
|
-
await this.db.insert(entities).values(row);
|
|
45
|
-
return this.toEntity(row);
|
|
46
|
-
}
|
|
47
|
-
async get(id) {
|
|
48
|
-
const rows = await this.db.select().from(entities).where(eq(entities.id, id)).limit(1);
|
|
49
|
-
return rows.length > 0 ? this.toEntity(rows[0]) : null;
|
|
50
|
-
}
|
|
51
|
-
async findByFlowAndState(flowId, state, limit) {
|
|
52
|
-
const query = this.db
|
|
53
|
-
.select()
|
|
54
|
-
.from(entities)
|
|
55
|
-
.where(and(eq(entities.flowId, flowId), eq(entities.state, state)));
|
|
56
|
-
const rows = await (limit !== undefined ? query.limit(limit) : query);
|
|
57
|
-
return rows.map((r) => this.toEntity(r));
|
|
58
|
-
}
|
|
59
|
-
async hasAnyInFlowAndState(flowId, stateNames) {
|
|
60
|
-
if (stateNames.length === 0)
|
|
61
|
-
return false;
|
|
62
|
-
const rows = await this.db
|
|
63
|
-
.select({ id: entities.id })
|
|
64
|
-
.from(entities)
|
|
65
|
-
.where(and(eq(entities.flowId, flowId), inArray(entities.state, stateNames)))
|
|
66
|
-
.limit(1);
|
|
67
|
-
return rows.length > 0;
|
|
68
|
-
}
|
|
69
|
-
async transition(id, toState, _trigger, artifacts, _invocationId) {
|
|
70
|
-
return this.db.transaction((tx) => {
|
|
71
|
-
const rows = tx.select().from(entities).where(eq(entities.id, id)).limit(1).all();
|
|
72
|
-
if (rows.length === 0)
|
|
73
|
-
throw new Error(`Entity not found: ${id}`);
|
|
74
|
-
const row = rows[0];
|
|
75
|
-
const now = Date.now();
|
|
76
|
-
const mergedArtifacts = artifacts
|
|
77
|
-
? { ...(row.artifacts ?? {}), ...artifacts }
|
|
78
|
-
: row.artifacts;
|
|
79
|
-
tx.update(entities)
|
|
80
|
-
.set({ state: toState, artifacts: mergedArtifacts, updatedAt: now })
|
|
81
|
-
.where(eq(entities.id, id))
|
|
82
|
-
.run();
|
|
83
|
-
return this.toEntity({
|
|
84
|
-
...row,
|
|
85
|
-
state: toState,
|
|
86
|
-
artifacts: mergedArtifacts,
|
|
87
|
-
updatedAt: now,
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
async updateArtifacts(id, artifacts) {
|
|
92
|
-
const rows = await this.db.select().from(entities).where(eq(entities.id, id)).limit(1);
|
|
93
|
-
if (rows.length === 0)
|
|
94
|
-
throw new Error(`Entity not found: ${id}`);
|
|
95
|
-
const existing = rows[0].artifacts ?? {};
|
|
96
|
-
await this.db
|
|
97
|
-
.update(entities)
|
|
98
|
-
.set({ artifacts: { ...existing, ...artifacts }, updatedAt: Date.now() })
|
|
99
|
-
.where(eq(entities.id, id));
|
|
100
|
-
}
|
|
101
|
-
async claim(flowId, state, agentId) {
|
|
102
|
-
return this.db.transaction((tx) => {
|
|
103
|
-
const rows = tx
|
|
104
|
-
.select()
|
|
105
|
-
.from(entities)
|
|
106
|
-
.where(and(eq(entities.flowId, flowId), eq(entities.state, state), isNull(entities.claimedBy)))
|
|
107
|
-
.limit(1)
|
|
108
|
-
.all();
|
|
109
|
-
if (rows.length === 0)
|
|
110
|
-
return null;
|
|
111
|
-
const row = rows[0];
|
|
112
|
-
const now = Date.now();
|
|
113
|
-
tx.update(entities)
|
|
114
|
-
.set({ claimedBy: agentId, claimedAt: now, updatedAt: now })
|
|
115
|
-
.where(eq(entities.id, row.id))
|
|
116
|
-
.run();
|
|
117
|
-
return this.toEntity({
|
|
118
|
-
...row,
|
|
119
|
-
claimedBy: agentId,
|
|
120
|
-
claimedAt: now,
|
|
121
|
-
updatedAt: now,
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
async claimById(entityId, agentId) {
|
|
126
|
-
const now = Date.now();
|
|
127
|
-
const result = this.db
|
|
128
|
-
.update(entities)
|
|
129
|
-
.set({ claimedBy: agentId, claimedAt: now, updatedAt: now })
|
|
130
|
-
.where(and(eq(entities.id, entityId), isNull(entities.claimedBy)))
|
|
131
|
-
.run();
|
|
132
|
-
if (result.changes === 0)
|
|
133
|
-
return null;
|
|
134
|
-
const rows = this.db.select().from(entities).where(eq(entities.id, entityId)).limit(1).all();
|
|
135
|
-
return rows.length > 0 ? this.toEntity(rows[0]) : null;
|
|
136
|
-
}
|
|
137
|
-
async release(entityId, agentId) {
|
|
138
|
-
await this.db
|
|
139
|
-
.update(entities)
|
|
140
|
-
.set({ claimedBy: null, claimedAt: null, updatedAt: Date.now() })
|
|
141
|
-
.where(and(eq(entities.id, entityId), eq(entities.claimedBy, agentId)))
|
|
142
|
-
.run();
|
|
143
|
-
}
|
|
144
|
-
async appendSpawnedChild(parentId, entry) {
|
|
145
|
-
this.db.transaction((tx) => {
|
|
146
|
-
const rows = tx.select().from(entities).where(eq(entities.id, parentId)).limit(1).all();
|
|
147
|
-
if (rows.length === 0)
|
|
148
|
-
throw new Error(`Entity ${parentId} not found`);
|
|
149
|
-
const row = rows[0];
|
|
150
|
-
const artifacts = row.artifacts ?? {};
|
|
151
|
-
const existing = (Array.isArray(artifacts.spawnedChildren) ? artifacts.spawnedChildren : []);
|
|
152
|
-
tx.update(entities)
|
|
153
|
-
.set({ artifacts: { ...artifacts, spawnedChildren: [...existing, entry] }, updatedAt: Date.now() })
|
|
154
|
-
.where(eq(entities.id, parentId))
|
|
155
|
-
.run();
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
async reapExpired(ttlMs) {
|
|
159
|
-
const cutoff = Date.now() - ttlMs;
|
|
160
|
-
const rows = this.db
|
|
161
|
-
.update(entities)
|
|
162
|
-
.set({ claimedBy: null, claimedAt: null, updatedAt: Date.now() })
|
|
163
|
-
.where(and(not(isNull(entities.claimedBy)), lt(entities.claimedAt, cutoff)))
|
|
164
|
-
.returning({ id: entities.id })
|
|
165
|
-
.all();
|
|
166
|
-
return rows.map((r) => r.id);
|
|
167
|
-
}
|
|
168
|
-
async setAffinity(entityId, workerId, role, expiresAt) {
|
|
169
|
-
await this.db
|
|
170
|
-
.update(entities)
|
|
171
|
-
.set({
|
|
172
|
-
affinityWorkerId: workerId,
|
|
173
|
-
affinityRole: role,
|
|
174
|
-
affinityExpiresAt: expiresAt.getTime(),
|
|
175
|
-
updatedAt: Date.now(),
|
|
176
|
-
})
|
|
177
|
-
.where(eq(entities.id, entityId))
|
|
178
|
-
.run();
|
|
179
|
-
}
|
|
180
|
-
async clearExpiredAffinity() {
|
|
181
|
-
const now = Date.now();
|
|
182
|
-
const rows = this.db
|
|
183
|
-
.update(entities)
|
|
184
|
-
.set({ affinityWorkerId: null, affinityRole: null, affinityExpiresAt: null, updatedAt: now })
|
|
185
|
-
.where(and(not(isNull(entities.affinityWorkerId)), lt(entities.affinityExpiresAt, now)))
|
|
186
|
-
.returning({ id: entities.id })
|
|
187
|
-
.all();
|
|
188
|
-
return rows.map((r) => r.id);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { BetterSQLite3Database } from "drizzle-orm/better-sqlite3";
|
|
2
|
-
import type { IEventRepository } from "../interfaces.js";
|
|
3
|
-
import type * as schema from "./schema.js";
|
|
4
|
-
import { events } from "./schema.js";
|
|
5
|
-
type Db = BetterSQLite3Database<typeof schema>;
|
|
6
|
-
export declare class DrizzleEventRepository implements IEventRepository {
|
|
7
|
-
private readonly db;
|
|
8
|
-
constructor(db: Db);
|
|
9
|
-
emitDefinitionChanged(flowId: string | null, tool: string, payload: Record<string, unknown>): Promise<void>;
|
|
10
|
-
findAll(): (typeof events.$inferSelect)[];
|
|
11
|
-
}
|
|
12
|
-
export {};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { events } from "./schema.js";
|
|
3
|
-
export class DrizzleEventRepository {
|
|
4
|
-
db;
|
|
5
|
-
constructor(db) {
|
|
6
|
-
this.db = db;
|
|
7
|
-
}
|
|
8
|
-
async emitDefinitionChanged(flowId, tool, payload) {
|
|
9
|
-
this.db
|
|
10
|
-
.insert(events)
|
|
11
|
-
.values({
|
|
12
|
-
id: randomUUID(),
|
|
13
|
-
type: "definition.changed",
|
|
14
|
-
entityId: null,
|
|
15
|
-
flowId: flowId || null,
|
|
16
|
-
payload: { tool, ...payload },
|
|
17
|
-
emittedAt: Date.now(),
|
|
18
|
-
})
|
|
19
|
-
.run();
|
|
20
|
-
}
|
|
21
|
-
findAll() {
|
|
22
|
-
return this.db.select().from(events).all();
|
|
23
|
-
}
|
|
24
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { BetterSQLite3Database } from "drizzle-orm/better-sqlite3";
|
|
2
|
-
import type { CreateFlowInput, CreateStateInput, CreateTransitionInput, Flow, FlowVersion, IFlowRepository, State, Transition, UpdateFlowInput, UpdateStateInput, UpdateTransitionInput } from "../interfaces.js";
|
|
3
|
-
import type * as schema from "./schema.js";
|
|
4
|
-
type Db = BetterSQLite3Database<typeof schema>;
|
|
5
|
-
export declare class DrizzleFlowRepository implements IFlowRepository {
|
|
6
|
-
private db;
|
|
7
|
-
constructor(db: Db);
|
|
8
|
-
private hydrateFlow;
|
|
9
|
-
create(input: CreateFlowInput): Promise<Flow>;
|
|
10
|
-
get(id: string): Promise<Flow | null>;
|
|
11
|
-
getByName(name: string): Promise<Flow | null>;
|
|
12
|
-
list(): Promise<Flow[]>;
|
|
13
|
-
listAll(): Promise<Flow[]>;
|
|
14
|
-
update(id: string, changes: UpdateFlowInput): Promise<Flow>;
|
|
15
|
-
addState(flowId: string, state: CreateStateInput): Promise<State>;
|
|
16
|
-
updateState(stateId: string, changes: UpdateStateInput): Promise<State>;
|
|
17
|
-
addTransition(flowId: string, transition: CreateTransitionInput): Promise<Transition>;
|
|
18
|
-
updateTransition(transitionId: string, changes: UpdateTransitionInput): Promise<Transition>;
|
|
19
|
-
snapshot(flowId: string): Promise<FlowVersion>;
|
|
20
|
-
restore(flowId: string, version: number): Promise<void>;
|
|
21
|
-
}
|
|
22
|
-
export {};
|