@mastra/factory 0.2.1-alpha.3 → 0.2.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/factory.d.ts.map +1 -1
  3. package/dist/factory.js +3503 -3585
  4. package/dist/factory.js.map +1 -1
  5. package/dist/index.js +3503 -3585
  6. package/dist/index.js.map +1 -1
  7. package/dist/integrations/base.d.ts +13 -25
  8. package/dist/integrations/base.d.ts.map +1 -1
  9. package/dist/integrations/github/integration.d.ts.map +1 -1
  10. package/dist/integrations/github/integration.js +625 -217
  11. package/dist/integrations/github/integration.js.map +1 -1
  12. package/dist/integrations/github/routes.d.ts +1 -4
  13. package/dist/integrations/github/routes.d.ts.map +1 -1
  14. package/dist/integrations/github/routes.js +113 -203
  15. package/dist/integrations/github/routes.js.map +1 -1
  16. package/dist/integrations/github/rules.d.ts +30 -0
  17. package/dist/integrations/github/rules.d.ts.map +1 -0
  18. package/dist/{rules/github-service.js → integrations/github/rules.js} +27 -8
  19. package/dist/integrations/github/rules.js.map +1 -0
  20. package/dist/integrations/linear/agent-tools.js.map +1 -1
  21. package/dist/integrations/linear/integration.d.ts.map +1 -1
  22. package/dist/integrations/linear/integration.js +352 -3
  23. package/dist/integrations/linear/integration.js.map +1 -1
  24. package/dist/integrations/linear/routes.d.ts +2 -2
  25. package/dist/integrations/linear/routes.d.ts.map +1 -1
  26. package/dist/integrations/linear/routes.js +2 -2
  27. package/dist/integrations/linear/routes.js.map +1 -1
  28. package/dist/integrations/linear/rules.d.ts +42 -0
  29. package/dist/integrations/linear/rules.d.ts.map +1 -0
  30. package/dist/{rules/linear-service.js → integrations/linear/rules.js} +14 -4
  31. package/dist/integrations/linear/rules.js.map +1 -0
  32. package/dist/integrations/platform/github/integration.d.ts.map +1 -1
  33. package/dist/integrations/platform/github/integration.js +626 -218
  34. package/dist/integrations/platform/github/integration.js.map +1 -1
  35. package/dist/integrations/platform/linear/integration.d.ts.map +1 -1
  36. package/dist/integrations/platform/linear/integration.js +353 -3
  37. package/dist/integrations/platform/linear/integration.js.map +1 -1
  38. package/dist/routes/oauth.js +47 -41
  39. package/dist/routes/oauth.js.map +1 -1
  40. package/dist/routes/surface.d.ts +3 -1
  41. package/dist/routes/surface.d.ts.map +1 -1
  42. package/dist/routes/surface.js +271 -621
  43. package/dist/routes/surface.js.map +1 -1
  44. package/dist/routes/work-items.js.map +1 -1
  45. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  46. package/dist/storage/domains/work-items/base.js +74 -75
  47. package/dist/storage/domains/work-items/base.js.map +1 -1
  48. package/dist/storage/domains/work-items/metrics.js.map +1 -1
  49. package/package.json +7 -7
  50. package/dist/integrations/github/project-lock.d.ts +0 -100
  51. package/dist/integrations/github/project-lock.d.ts.map +0 -1
  52. package/dist/integrations/github/project-lock.js +0 -103
  53. package/dist/integrations/github/project-lock.js.map +0 -1
  54. package/dist/rules/github-service.d.ts +0 -29
  55. package/dist/rules/github-service.d.ts.map +0 -1
  56. package/dist/rules/github-service.js.map +0 -1
  57. package/dist/rules/linear-service.d.ts +0 -27
  58. package/dist/rules/linear-service.d.ts.map +0 -1
  59. package/dist/rules/linear-service.js.map +0 -1
@@ -1,103 +0,0 @@
1
- // src/integrations/github/project-lock.ts
2
- import { createHash } from "crypto";
3
- var inProcessLocks = /* @__PURE__ */ new Map();
4
- var DEFAULT_PROJECT_LOCK_TIMEOUT_MS = 6e4;
5
- var ProjectLockTimeoutError = class extends Error {
6
- key;
7
- timeoutMs;
8
- constructor(key, timeoutMs) {
9
- super(`Project lock critical section for "${key}" exceeded ${timeoutMs}ms`);
10
- this.name = "ProjectLockTimeoutError";
11
- this.key = key;
12
- this.timeoutMs = timeoutMs;
13
- }
14
- };
15
- async function runWithTimeout(key, timeoutMs, fn) {
16
- const controller = new AbortController();
17
- const timer = setTimeout(() => controller.abort(), timeoutMs);
18
- const abortError = new Promise((_, reject) => {
19
- controller.signal.addEventListener("abort", () => reject(new ProjectLockTimeoutError(key, timeoutMs)), {
20
- once: true
21
- });
22
- });
23
- const work = fn(controller.signal);
24
- work.catch(() => {
25
- });
26
- try {
27
- return await Promise.race([work, abortError]);
28
- } finally {
29
- clearTimeout(timer);
30
- }
31
- }
32
- function isDistributedLockEnabled(storage) {
33
- if (process.env.MASTRACODE_DISTRIBUTED_LOCK === "0") return false;
34
- return typeof storage?.withDistributedLock === "function";
35
- }
36
- function hashKey(key) {
37
- const digest = createHash("sha256").update(key).digest();
38
- const a = digest.readInt32BE(0);
39
- const b = digest.readInt32BE(4);
40
- return [a, b];
41
- }
42
- function withProjectLock(options) {
43
- const { key, storage, fn, pool, timeoutMs = DEFAULT_PROJECT_LOCK_TIMEOUT_MS } = options;
44
- const prev = inProcessLocks.get(key) ?? Promise.resolve();
45
- const run = () => withDbAdvisoryLock({ key, storage, fn, pool, timeoutMs });
46
- const next = prev.then(run, run);
47
- const tail = next.then(
48
- () => void 0,
49
- () => void 0
50
- );
51
- inProcessLocks.set(key, tail);
52
- void tail.then(() => {
53
- if (inProcessLocks.get(key) === tail) {
54
- inProcessLocks.delete(key);
55
- }
56
- });
57
- return next;
58
- }
59
- async function withDbAdvisoryLock(options) {
60
- const { key, storage, fn, pool, timeoutMs = DEFAULT_PROJECT_LOCK_TIMEOUT_MS } = options;
61
- if (process.env.MASTRACODE_DISTRIBUTED_LOCK === "0") {
62
- return runWithTimeout(key, timeoutMs, fn);
63
- }
64
- if (pool) return advisoryLockOver(pool, key, timeoutMs, fn);
65
- if (typeof storage?.withDistributedLock !== "function") {
66
- return runWithTimeout(key, timeoutMs, fn);
67
- }
68
- return storage.withDistributedLock(key, () => runWithTimeout(key, timeoutMs, fn));
69
- }
70
- async function advisoryLockOver(pool, key, timeoutMs, fn) {
71
- const [k1, k2] = hashKey(key);
72
- const client = await pool.connect();
73
- try {
74
- await client.query("BEGIN");
75
- await client.query("SELECT pg_advisory_xact_lock($1, $2)", [k1, k2]);
76
- try {
77
- const result = await runWithTimeout(key, timeoutMs, fn);
78
- await client.query("COMMIT");
79
- return result;
80
- } catch (err) {
81
- try {
82
- await client.query("ROLLBACK");
83
- } catch {
84
- }
85
- throw err;
86
- }
87
- } finally {
88
- client.release();
89
- }
90
- }
91
- function __resetProjectLocksForTests() {
92
- inProcessLocks.clear();
93
- }
94
- export {
95
- DEFAULT_PROJECT_LOCK_TIMEOUT_MS,
96
- ProjectLockTimeoutError,
97
- __resetProjectLocksForTests,
98
- hashKey,
99
- isDistributedLockEnabled,
100
- withDbAdvisoryLock,
101
- withProjectLock
102
- };
103
- //# sourceMappingURL=project-lock.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/integrations/github/project-lock.ts"],"sourcesContent":["/**\n * Per-(project, user) lock that serializes the worktree/commit/push/PR flows.\n *\n * The push/PR flows temporarily rewrite the sandbox git remote to a tokenized\n * URL and scrub it again in a `finally`; two concurrent operations on the same\n * `(project, user)` sandbox could interleave those rewrites and leak a tokenized\n * remote. Serializing per `(project, user)` removes that race.\n *\n * There are two layers:\n * 1. An **in-process** promise-chain mutex keyed by the lock key, so repeated\n * same-replica callers stay cheap and never touch the database for ordering.\n * 2. The factory storage backend's **`withDistributedLock` capability** (pg:\n * transaction-scoped advisory locks) so that *different replicas*\n * operating on the same key also serialize. Backends without the\n * capability (libsql: local single-writer) fall back to the in-process\n * mutex alone — correct for single-replica deployments.\n *\n * Set `MASTRACODE_DISTRIBUTED_LOCK=0` to force-disable the distributed layer\n * (local dev, single replica) and fall back to the pure in-process mutex.\n */\n\nimport { createHash } from 'node:crypto';\n\nimport type { FactoryStorage } from '@mastra/core/storage';\n\n/** Minimal pg pool surface used by the distributed lock (for testability). */\nexport interface LockPool {\n connect(): Promise<LockClient>;\n}\nexport interface LockClient {\n query(sql: string, params?: unknown[]): Promise<unknown>;\n release(): void;\n}\n\nconst inProcessLocks = new Map<string, Promise<unknown>>();\n\n/**\n * Default hard cap on how long a critical section may run inside the project\n * lock. Prevents an untimed outbound call (sandbox HTTP, GitHub App API, git\n * push, etc.) from pinning both the advisory lock and the pg pool connection\n * indefinitely — the failure mode behind the 2025-07-23 shipyard 30s plateau\n * incident. Callers can override per call via `timeoutMs`.\n */\nexport const DEFAULT_PROJECT_LOCK_TIMEOUT_MS = 60_000;\n\n/** Thrown when the critical section under `withProjectLock` exceeds the timeout. */\nexport class ProjectLockTimeoutError extends Error {\n readonly key: string;\n readonly timeoutMs: number;\n constructor(key: string, timeoutMs: number) {\n super(`Project lock critical section for \"${key}\" exceeded ${timeoutMs}ms`);\n this.name = 'ProjectLockTimeoutError';\n this.key = key;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Race `fn()` against a timeout, throwing `ProjectLockTimeoutError` if the\n * timeout fires first. `fn()` receives an `AbortSignal` so it can (optionally)\n * abort in-flight outbound I/O when the timeout trips. If `fn()` ignores the\n * signal it will still resolve/reject eventually — but the caller sees the\n * timeout error immediately, which is what lets the outer lock wrapper roll\n * back and release the connection.\n */\nasync function runWithTimeout<T>(key: string, timeoutMs: number, fn: (signal: AbortSignal) => Promise<T>): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n const abortError = new Promise<never>((_, reject) => {\n controller.signal.addEventListener('abort', () => reject(new ProjectLockTimeoutError(key, timeoutMs)), {\n once: true,\n });\n });\n const work = fn(controller.signal);\n // If `fn` eventually rejects (e.g. its own fetch observes the abort signal\n // after we already rejected via timeout), swallow it — the outer caller\n // has already been rejected with our timeout error and we don't want an\n // unhandled rejection.\n work.catch(() => {});\n try {\n return await Promise.race([work, abortError]);\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * True when the cross-replica lock layer should be used: not force-disabled\n * via env, and the factory storage backend exposes the\n * `withDistributedLock` capability.\n */\nexport function isDistributedLockEnabled(storage: FactoryStorage | undefined): boolean {\n if (process.env.MASTRACODE_DISTRIBUTED_LOCK === '0') return false;\n return typeof storage?.withDistributedLock === 'function';\n}\n\n/**\n * Hash a lock key into the two signed 32-bit integers that the two-arg form of\n * `pg_advisory_xact_lock(int4, int4)` expects. Using two int4 args (rather than\n * one int8) keeps the key inside the GitHub-feature advisory-lock namespace and\n * avoids collisions with other single-int8 advisory locks.\n */\nexport function hashKey(key: string): [number, number] {\n const digest = createHash('sha256').update(key).digest();\n // Read two independent 32-bit halves as signed int4 values.\n const a = digest.readInt32BE(0);\n const b = digest.readInt32BE(4);\n return [a, b];\n}\n\n/**\n * Run `fn` while holding the lock for `key`. Same-replica callers serialize via\n * the in-process mutex; cross-replica callers additionally serialize via a\n * Postgres transaction-scoped advisory lock (unless disabled).\n *\n * The in-process chain swallows rejections so one failed operation does not\n * poison the lock for subsequent callers.\n */\nexport function withProjectLock<T>(options: {\n key: string;\n /** Factory storage backend supplying the `withDistributedLock` capability, when available. */\n storage?: FactoryStorage;\n fn: (signal: AbortSignal) => Promise<T>;\n /** Test seam: fake pg pool standing in for the distributed layer. */\n pool?: LockPool;\n /**\n * Hard cap on the critical section. Defaults to\n * {@link DEFAULT_PROJECT_LOCK_TIMEOUT_MS}. On timeout `fn`'s abort signal\n * fires and the outer lock throws `ProjectLockTimeoutError`, releasing the\n * advisory lock + pool connection.\n */\n timeoutMs?: number;\n}): Promise<T> {\n const { key, storage, fn, pool, timeoutMs = DEFAULT_PROJECT_LOCK_TIMEOUT_MS } = options;\n const prev = inProcessLocks.get(key) ?? Promise.resolve();\n const run = () => withDbAdvisoryLock({ key, storage, fn, pool, timeoutMs });\n const next = prev.then(run, run);\n const tail = next.then(\n () => undefined,\n () => undefined,\n );\n inProcessLocks.set(key, tail);\n // Drop the entry once this operation settles, but only if no later caller has\n // chained onto it in the meantime — otherwise we'd evict a live waiter's tail.\n // This keeps the map from growing unbounded across many distinct project keys.\n void tail.then(() => {\n if (inProcessLocks.get(key) === tail) {\n inProcessLocks.delete(key);\n }\n });\n return next;\n}\n\n/**\n * Acquire only the cross-replica lock for `key` and run `fn` under it. This is\n * the distributed serialization layer; `withProjectLock` wraps it with an\n * in-process mutex for same-replica callers. Delegates to the factory storage\n * backend's `withDistributedLock` capability; backends without it (or a\n * force-disabled env) run `fn` directly — the in-process mutex still holds.\n *\n * `poolOverride` keeps the pg advisory-lock path directly testable with a fake\n * pool (each simulated replica has its own in-process state but shares one\n * database).\n */\nexport async function withDbAdvisoryLock<T>(options: {\n key: string;\n storage?: FactoryStorage;\n fn: (signal: AbortSignal) => Promise<T>;\n pool?: LockPool;\n timeoutMs?: number;\n}): Promise<T> {\n const { key, storage, fn, pool, timeoutMs = DEFAULT_PROJECT_LOCK_TIMEOUT_MS } = options;\n if (process.env.MASTRACODE_DISTRIBUTED_LOCK === '0') {\n return runWithTimeout(key, timeoutMs, fn);\n }\n\n if (pool) return advisoryLockOver(pool, key, timeoutMs, fn);\n\n if (typeof storage?.withDistributedLock !== 'function') {\n return runWithTimeout(key, timeoutMs, fn);\n }\n // Wrap the backend-provided lock so the critical section is bounded\n // regardless of whether the backend implements its own timeout. The\n // backend still owns lock acquisition/release; we own the timeout on\n // `fn`.\n return storage.withDistributedLock(key, () => runWithTimeout(key, timeoutMs, fn));\n}\n\n/** The pg advisory-lock body, kept for the `poolOverride` test seam. */\nasync function advisoryLockOver<T>(\n pool: LockPool,\n key: string,\n timeoutMs: number,\n fn: (signal: AbortSignal) => Promise<T>,\n): Promise<T> {\n const [k1, k2] = hashKey(key);\n const client = await pool.connect();\n try {\n await client.query('BEGIN');\n // Blocks until no other transaction holds this advisory key. Auto-released\n // when the transaction ends below.\n await client.query('SELECT pg_advisory_xact_lock($1, $2)', [k1, k2]);\n try {\n const result = await runWithTimeout(key, timeoutMs, fn);\n await client.query('COMMIT');\n return result;\n } catch (err) {\n // COMMIT/ROLLBACK below releases the advisory lock. If the underlying\n // connection is already dead (e.g. Neon killed it after IIT), the\n // rollback throws — we swallow that specifically so the original error\n // reaches the caller.\n try {\n await client.query('ROLLBACK');\n } catch {\n /* connection already gone; nothing to roll back */\n }\n throw err;\n }\n } finally {\n client.release();\n }\n}\n\n/** For tests: clear the in-process lock chains. */\nexport function __resetProjectLocksForTests(): void {\n inProcessLocks.clear();\n}\n"],"mappings":"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","names":[]}
@@ -1,29 +0,0 @@
1
- import type { GithubIntegration } from '../integrations/github/integration.js';
2
- import type { ParsedGithubWebhook } from '../integrations/github/webhook.js';
3
- import type { IntegrationStorageHandle } from '../storage/domains/integrations/base.js';
4
- import type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';
5
- import type { SourceControlStorageHandle } from '../storage/domains/source-control/base.js';
6
- import type { WorkItemsStorage } from '../storage/domains/work-items/base.js';
7
- import type { FactoryRules } from './types.js';
8
- interface FactoryPullRequestProvenanceData {
9
- kind: 'factory-pr-provenance';
10
- workItemId: string;
11
- }
12
- export interface FactoryGithubEventServiceOptions {
13
- github: GithubIntegration;
14
- sourceControl: SourceControlStorageHandle;
15
- integrationStorage: IntegrationStorageHandle<Record<string, unknown>, Record<string, unknown>, FactoryPullRequestProvenanceData>;
16
- projects: FactoryProjectsStorage;
17
- storage: WorkItemsStorage;
18
- rules: FactoryRules;
19
- }
20
- export declare class FactoryGithubEventService {
21
- #private;
22
- private readonly options;
23
- constructor(options: FactoryGithubEventServiceOptions);
24
- ingest(parsed: ParsedGithubWebhook): Promise<{
25
- status: 'ignored' | 'committed' | 'replayed' | 'missing';
26
- }>;
27
- }
28
- export {};
29
- //# sourceMappingURL=github-service.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"github-service.d.ts","sourceRoot":"","sources":["../../src/rules/github-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,yCAAyC,CAAC;AACxF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,KAAK,EAEV,0BAA0B,EAC3B,MAAM,2CAA2C,CAAC;AACnD,OAAO,KAAK,EAAe,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAE3F,OAAO,KAAK,EAKV,YAAY,EACb,MAAM,YAAY,CAAC;AAuFpB,UAAU,gCAAgC;IACxC,IAAI,EAAE,uBAAuB,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gCAAgC;IAC/C,MAAM,EAAE,iBAAiB,CAAC;IAC1B,aAAa,EAAE,0BAA0B,CAAC;IAC1C,kBAAkB,EAAE,wBAAwB,CAC1C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvB,gCAAgC,CACjC,CAAC;IACF,QAAQ,EAAE,sBAAsB,CAAC;IACjC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,KAAK,EAAE,YAAY,CAAC;CACrB;AAED,qBAAa,yBAAyB;;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,gCAAgC;IAEhE,MAAM,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAA;KAAE,CAAC;CA8MjH"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/rules/resolve.ts","../../src/rules/types.ts","../../src/rules/validation.ts","../../src/rules/github-service.ts"],"sourcesContent":["import type {\n FactoryGithubEventName,\n FactoryGithubRuleLeaf,\n FactoryLinearEventName,\n FactoryLinearRuleLeaf,\n FactoryRuleBoard,\n FactoryRuleHandler,\n FactoryRuleSource,\n FactoryRuleStage,\n FactoryRules,\n FactoryStageRuleContext,\n FactoryToolResultRuleContext,\n FactoryToolRuleLeaf,\n} from './types.js';\n\nexport interface ResolvedFactoryStageRule {\n phase: 'exit' | 'enter';\n handler: FactoryRuleHandler<FactoryStageRuleContext>;\n}\n\nexport function resolveFactoryStageRules(\n rules: FactoryRules,\n input: {\n board: FactoryRuleBoard;\n source: FactoryRuleSource;\n fromStage: FactoryRuleStage;\n toStage: FactoryRuleStage;\n initialEntry?: boolean;\n },\n): ResolvedFactoryStageRule[] {\n if (input.fromStage === input.toStage && !input.initialEntry) return [];\n const boardRules = rules[input.board];\n const resolved: ResolvedFactoryStageRule[] = [];\n const onExit = input.initialEntry ? undefined : boardRules[input.fromStage]?.[input.source]?.onExit;\n if (onExit) resolved.push({ phase: 'exit', handler: onExit });\n const onEnter = boardRules[input.toStage]?.[input.source]?.onEnter;\n if (onEnter) resolved.push({ phase: 'enter', handler: onEnter });\n return resolved;\n}\n\nexport function resolveFactoryToolRule(rules: FactoryRules, toolName: string): FactoryToolRuleLeaf['onResult'] {\n return rules.tools[toolName]?.onResult;\n}\n\nexport function resolveFactoryGithubRule(\n rules: FactoryRules,\n event: FactoryGithubEventName,\n): FactoryGithubRuleLeaf['onEvent'] {\n return rules.github[event]?.onEvent;\n}\n\nexport function resolveFactoryLinearRule(\n rules: FactoryRules,\n event: FactoryLinearEventName,\n): FactoryLinearRuleLeaf['onEvent'] {\n return rules.linear[event]?.onEvent;\n}\n\nexport type ResolvedFactoryToolRule = FactoryRuleHandler<FactoryToolResultRuleContext>;\n","export type WorkItemSource = 'github-issue' | 'github-pr' | 'linear-issue' | 'manual';\n\nexport const FACTORY_RULE_STAGES = ['intake', 'triage', 'planning', 'execute', 'review', 'done', 'canceled'] as const;\nexport type FactoryRuleStage = (typeof FACTORY_RULE_STAGES)[number];\n\nexport const FACTORY_RULE_BOARDS = ['work', 'review'] as const;\nexport type FactoryRuleBoard = (typeof FACTORY_RULE_BOARDS)[number];\n\nexport const FACTORY_RULE_SOURCES = ['issue', 'pullRequest', 'linearIssue', 'manual'] as const;\nexport type FactoryRuleSource = (typeof FACTORY_RULE_SOURCES)[number];\n\nexport const FACTORY_GITHUB_EVENTS = [\n 'issueOpened',\n 'pullRequestOpened',\n 'pullRequestUpdated',\n 'pullRequestReviewRequested',\n 'pullRequestMerged',\n] as const;\nexport type FactoryGithubEventName = (typeof FACTORY_GITHUB_EVENTS)[number];\n\nexport const FACTORY_LINEAR_EVENTS = ['issueObserved'] as const;\nexport type FactoryLinearEventName = (typeof FACTORY_LINEAR_EVENTS)[number];\n\nexport type FactoryRuleJsonValue =\n | null\n | boolean\n | number\n | string\n | FactoryRuleJsonValue[]\n | { [key: string]: FactoryRuleJsonValue };\n\nexport interface FactoryRuleItemContext {\n id: string;\n source: WorkItemSource;\n sourceKey: string | null;\n parentWorkItemId: string | null;\n title: string;\n url: string | null;\n stages: readonly string[];\n}\n\nexport type FactoryRuleActor =\n | { type: 'human'; id: string }\n | { type: 'agent'; bindingId: string; role: string }\n | { type: 'github'; login: string; trusted: boolean; factoryAuthored: boolean }\n | { type: 'system'; id: string };\n\nexport interface FactoryRuleIngressIdentity {\n type: 'human' | 'agent' | 'toolResult' | 'github' | 'linear' | 'rule';\n id: string;\n}\n\nexport interface FactoryRuleCausalEntry {\n ingressId: string;\n decisionType: FactoryCommitDecision['type'];\n}\n\nexport interface FactoryRuleContextBase {\n tenant: { orgId: string; projectId: string };\n actor: FactoryRuleActor;\n ingress: FactoryRuleIngressIdentity;\n cause: string;\n causalChain: readonly FactoryRuleCausalEntry[];\n ruleSetVersion: string;\n}\n\nexport interface FactoryBoundRuleContext extends FactoryRuleContextBase {\n item: FactoryRuleItemContext;\n board: FactoryRuleBoard;\n itemRevision: number;\n}\n\nexport interface FactoryStageRuleContext extends FactoryBoundRuleContext {\n source: FactoryRuleSource;\n stage: FactoryRuleStage;\n fromStage: FactoryRuleStage;\n toStage: FactoryRuleStage;\n}\n\nexport interface FactoryToolResultRuleContext extends FactoryBoundRuleContext {\n toolName: string;\n threadId: string;\n assistantMessageId: string;\n toolCallId: string;\n result: {\n status: 'success' | 'error';\n value: FactoryRuleJsonValue;\n };\n}\n\nexport interface FactoryGithubRuleContext extends FactoryRuleContextBase {\n item?: FactoryRuleItemContext;\n board?: FactoryRuleBoard;\n itemRevision?: number;\n event: FactoryGithubEventName;\n deliveryId: string;\n factory: { createdAt: string };\n repository: { id: number; fullName: string };\n issue?: { number: number; title: string; url: string; createdAt?: string };\n pullRequest?: {\n number: number;\n title: string;\n url: string;\n createdAt?: string;\n state: 'open' | 'closed';\n merged: boolean;\n headBranch: string;\n baseBranch: string;\n };\n}\n\nexport interface FactoryLinearRuleContext extends FactoryRuleContextBase {\n item?: FactoryRuleItemContext;\n board?: FactoryRuleBoard;\n itemRevision?: number;\n event: FactoryLinearEventName;\n issue: {\n id: string;\n identifier: string;\n title: string;\n url: string;\n state: string;\n stateType: string;\n priorityLabel: string;\n assignee: string | null;\n team: string | null;\n labels: readonly string[];\n createdAt: string;\n updatedAt: string;\n };\n}\n\nexport type FactoryRuleHandler<TContext> = (\n context: Readonly<TContext>,\n) => FactoryRuleDecision | void | Promise<FactoryRuleDecision | void>;\n\nexport interface FactoryBoardRuleLeaf {\n onEnter?: FactoryRuleHandler<FactoryStageRuleContext>;\n onExit?: FactoryRuleHandler<FactoryStageRuleContext>;\n}\n\nexport interface FactoryToolRuleLeaf {\n onResult?: FactoryRuleHandler<FactoryToolResultRuleContext>;\n}\n\nexport interface FactoryGithubRuleLeaf {\n onEvent?: FactoryRuleHandler<FactoryGithubRuleContext>;\n}\n\nexport interface FactoryLinearRuleLeaf {\n onEvent?: FactoryRuleHandler<FactoryLinearRuleContext>;\n}\n\nexport type FactoryBoardRules = Partial<\n Record<FactoryRuleStage, Partial<Record<FactoryRuleSource, FactoryBoardRuleLeaf>>>\n>;\n\nexport interface FactoryRules {\n version: string;\n work: FactoryBoardRules;\n review: FactoryBoardRules;\n tools: Record<string, FactoryToolRuleLeaf>;\n github: Partial<Record<FactoryGithubEventName, FactoryGithubRuleLeaf>>;\n linear: Partial<Record<FactoryLinearEventName, FactoryLinearRuleLeaf>>;\n}\n\nexport interface FactoryRulesOverrides {\n work?: FactoryBoardRules;\n review?: FactoryBoardRules;\n tools?: Record<string, FactoryToolRuleLeaf>;\n github?: Partial<Record<FactoryGithubEventName, FactoryGithubRuleLeaf>>;\n linear?: Partial<Record<FactoryLinearEventName, FactoryLinearRuleLeaf>>;\n}\n\nexport type FactoryRuleRejectionCode =\n | 'forbidden'\n | 'invalid_transition'\n | 'missing_binding'\n | 'stale'\n | 'timeout'\n | 'rule_error'\n | 'causal_depth_exceeded'\n | 'repeated_transition';\n\nexport interface FactoryRuleRejectDecision {\n type: 'reject';\n code: FactoryRuleRejectionCode;\n reason: string;\n}\n\ninterface FactoryCommitDecisionBase {\n idempotencyKey: string;\n}\n\nexport interface FactoryTransitionDecision extends FactoryCommitDecisionBase {\n type: 'transition';\n board: FactoryRuleBoard;\n stage: FactoryRuleStage;\n}\n\nexport interface FactoryUpsertLinkedWorkItemDecision extends FactoryCommitDecisionBase {\n type: 'upsertLinkedWorkItem';\n board: FactoryRuleBoard;\n source: WorkItemSource;\n sourceKey: string;\n title: string;\n url: string | null;\n stage: FactoryRuleStage;\n metadata?: Record<string, FactoryRuleJsonValue>;\n}\n\nexport interface FactoryInvokeSkillDecision extends FactoryCommitDecisionBase {\n type: 'invokeSkill';\n role: string;\n skillName: string;\n arguments?: string;\n precedingMessage?: string;\n}\n\nexport interface FactorySendMessageDecision extends FactoryCommitDecisionBase {\n type: 'sendMessage';\n role: string;\n message: string;\n priority?: 'medium' | 'high' | 'urgent';\n idleBehavior?: 'persist' | 'wake';\n prepareBinding?: boolean;\n}\n\nexport interface FactoryNotifyDecision extends FactoryCommitDecisionBase {\n type: 'notify';\n title: string;\n body?: string;\n level?: 'info' | 'warning' | 'error';\n}\n\nexport type FactoryCommitDecision =\n | FactoryTransitionDecision\n | FactoryUpsertLinkedWorkItemDecision\n | FactoryInvokeSkillDecision\n | FactorySendMessageDecision\n | FactoryNotifyDecision;\n\nexport type FactoryRuleDecision = FactoryRuleRejectDecision | FactoryCommitDecision;\n\nexport interface FactoryTransitionResultAccepted {\n status: 'accepted';\n transitionId: string;\n itemId: string;\n revision: number;\n stage: FactoryRuleStage;\n decisions: FactoryCommitDecision[];\n}\n\nexport interface FactoryTransitionResultRejected {\n status: 'rejected';\n transitionId: string;\n itemId: string;\n code: FactoryRuleRejectionCode;\n reason: string;\n}\n\nexport type FactoryTransitionResult = FactoryTransitionResultAccepted | FactoryTransitionResultRejected;\n\nexport function factoryRuleSourceForWorkItem(source: WorkItemSource): FactoryRuleSource {\n switch (source) {\n case 'github-issue':\n return 'issue';\n case 'github-pr':\n return 'pullRequest';\n case 'linear-issue':\n return 'linearIssue';\n case 'manual':\n return 'manual';\n }\n}\n","import {\n FACTORY_GITHUB_EVENTS,\n FACTORY_LINEAR_EVENTS,\n FACTORY_RULE_BOARDS,\n FACTORY_RULE_SOURCES,\n FACTORY_RULE_STAGES,\n} from './types.js';\nimport type {\n FactoryBoardRules,\n FactoryCommitDecision,\n FactoryRuleDecision,\n FactoryRuleJsonValue,\n FactoryRules,\n FactoryRuleRejectionCode,\n WorkItemSource,\n} from './types.js';\n\nexport const MAX_FACTORY_RULE_CAUSAL_DEPTH = 8;\n\nconst MAX_VERSION_LENGTH = 128;\nconst MAX_IDEMPOTENCY_KEY_LENGTH = 256;\nconst MAX_REASON_LENGTH = 512;\nconst MAX_TITLE_LENGTH = 512;\nconst MAX_MESSAGE_LENGTH = 8_192;\nconst MAX_ARGUMENTS_LENGTH = 4_096;\nconst MAX_ROLE_LENGTH = 32;\nconst MAX_SKILL_NAME_LENGTH = 128;\nconst MAX_SOURCE_KEY_LENGTH = 256;\nconst MAX_URL_LENGTH = 2_048;\nconst MAX_METADATA_JSON_LENGTH = 16_384;\nconst MAX_JSON_DEPTH = 8;\nconst MAX_JSON_COLLECTION_SIZE = 100;\n\nconst IDENTIFIER_RE = /^[a-z0-9][a-z0-9_-]*$/i;\nconst SKILL_NAME_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\nconst SENSITIVE_KEY_RE = /(?:authorization|cookie|credential|password|secret|token)/i;\nconst WORK_ITEM_SOURCES: readonly WorkItemSource[] = ['github-issue', 'github-pr', 'linear-issue', 'manual'];\nconst REJECTION_CODES: readonly FactoryRuleRejectionCode[] = [\n 'forbidden',\n 'invalid_transition',\n 'missing_binding',\n 'stale',\n 'timeout',\n 'rule_error',\n 'causal_depth_exceeded',\n 'repeated_transition',\n];\n\nexport class FactoryRuleValidationError extends Error {\n readonly code = 'invalid_factory_rule';\n\n constructor(message: string) {\n super(message);\n this.name = 'FactoryRuleValidationError';\n }\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\nfunction assertExactKeys(value: Record<string, unknown>, keys: readonly string[], label: string): void {\n const allowed = new Set(keys);\n if (Object.keys(value).some(key => !allowed.has(key))) {\n throw new FactoryRuleValidationError(`${label} contains an unsupported field.`);\n }\n}\n\nfunction boundedString(value: unknown, label: string, max: number, pattern?: RegExp): string {\n if (typeof value !== 'string') throw new FactoryRuleValidationError(`${label} must be a string.`);\n const normalized = value.trim();\n if (normalized.length === 0 || normalized.length > max || (pattern && !pattern.test(normalized))) {\n throw new FactoryRuleValidationError(`${label} is invalid.`);\n }\n return normalized;\n}\n\nfunction optionalBoundedString(value: unknown, label: string, max: number): string | undefined {\n if (value === undefined) return undefined;\n return boundedString(value, label, max);\n}\n\nfunction enumValue<T extends string>(value: unknown, allowed: readonly T[], label: string): T {\n if (typeof value !== 'string' || !allowed.includes(value as T)) {\n throw new FactoryRuleValidationError(`${label} is invalid.`);\n }\n return value as T;\n}\n\nexport function normalizeFactoryRuleJsonValue(\n value: unknown,\n depth = 0,\n seen = new Set<object>(),\n): FactoryRuleJsonValue {\n if (value === null || typeof value === 'boolean' || typeof value === 'string') return value;\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) throw new FactoryRuleValidationError('Rule metadata must contain finite numbers.');\n return value;\n }\n if (depth >= MAX_JSON_DEPTH || (typeof value !== 'object' && !Array.isArray(value))) {\n throw new FactoryRuleValidationError('Rule metadata is not bounded JSON.');\n }\n if (seen.has(value as object)) throw new FactoryRuleValidationError('Rule metadata must not contain cycles.');\n seen.add(value as object);\n try {\n if (Array.isArray(value)) {\n if (value.length > MAX_JSON_COLLECTION_SIZE) {\n throw new FactoryRuleValidationError('Rule metadata contains too many entries.');\n }\n return value.map(entry => normalizeFactoryRuleJsonValue(entry, depth + 1, seen));\n }\n if (!isPlainObject(value)) throw new FactoryRuleValidationError('Rule metadata must use plain objects.');\n const entries = Object.entries(value);\n if (entries.length > MAX_JSON_COLLECTION_SIZE) {\n throw new FactoryRuleValidationError('Rule metadata contains too many fields.');\n }\n const sanitized: Record<string, FactoryRuleJsonValue> = {};\n for (const [key, entry] of entries) {\n const normalizedKey = boundedString(key, 'Rule metadata key', 128, IDENTIFIER_RE);\n sanitized[normalizedKey] = SENSITIVE_KEY_RE.test(normalizedKey)\n ? '[REDACTED]'\n : normalizeFactoryRuleJsonValue(entry, depth + 1, seen);\n }\n return sanitized;\n } finally {\n seen.delete(value as object);\n }\n}\n\nfunction sanitizeMetadata(value: unknown): Record<string, FactoryRuleJsonValue> | undefined {\n if (value === undefined) return undefined;\n const sanitized = normalizeFactoryRuleJsonValue(value);\n if (!isPlainObject(sanitized)) throw new FactoryRuleValidationError('Rule metadata must be an object.');\n if (JSON.stringify(sanitized).length > MAX_METADATA_JSON_LENGTH) {\n throw new FactoryRuleValidationError('Rule metadata is too large.');\n }\n return sanitized;\n}\n\nfunction validateBoardRules(rules: unknown, label: string): asserts rules is FactoryBoardRules {\n if (!isPlainObject(rules)) throw new FactoryRuleValidationError(`${label} must be an object.`);\n for (const [stage, sources] of Object.entries(rules)) {\n enumValue(stage, FACTORY_RULE_STAGES, `${label} stage`);\n if (!isPlainObject(sources)) throw new FactoryRuleValidationError(`${label}.${stage} must be an object.`);\n for (const [source, leaf] of Object.entries(sources)) {\n enumValue(source, FACTORY_RULE_SOURCES, `${label}.${stage} source`);\n if (!isPlainObject(leaf)) throw new FactoryRuleValidationError(`${label}.${stage}.${source} must be an object.`);\n assertExactKeys(leaf, ['onEnter', 'onExit'], `${label}.${stage}.${source}`);\n for (const handler of Object.values(leaf)) {\n if (handler !== undefined && typeof handler !== 'function') {\n throw new FactoryRuleValidationError(`${label}.${stage}.${source} handlers must be functions.`);\n }\n }\n }\n }\n}\n\nexport function assertFactoryRules(rules: unknown): asserts rules is FactoryRules {\n if (!isPlainObject(rules)) throw new FactoryRuleValidationError('Factory rules must be an object.');\n assertExactKeys(rules, ['version', 'work', 'review', 'tools', 'github', 'linear'], 'Factory rules');\n boundedString(rules.version, 'Factory rule version', MAX_VERSION_LENGTH);\n validateBoardRules(rules.work, 'Factory rules.work');\n validateBoardRules(rules.review, 'Factory rules.review');\n\n if (!isPlainObject(rules.tools)) throw new FactoryRuleValidationError('Factory rules.tools must be an object.');\n for (const [toolName, leaf] of Object.entries(rules.tools)) {\n boundedString(toolName, 'Factory tool name', 128, IDENTIFIER_RE);\n if (!isPlainObject(leaf))\n throw new FactoryRuleValidationError(`Factory rules.tools.${toolName} must be an object.`);\n assertExactKeys(leaf, ['onResult'], `Factory rules.tools.${toolName}`);\n if (leaf.onResult !== undefined && typeof leaf.onResult !== 'function') {\n throw new FactoryRuleValidationError(`Factory rules.tools.${toolName}.onResult must be a function.`);\n }\n }\n\n if (!isPlainObject(rules.github)) throw new FactoryRuleValidationError('Factory rules.github must be an object.');\n for (const [event, leaf] of Object.entries(rules.github)) {\n enumValue(event, FACTORY_GITHUB_EVENTS, 'Factory GitHub event');\n if (!isPlainObject(leaf)) throw new FactoryRuleValidationError(`Factory rules.github.${event} must be an object.`);\n assertExactKeys(leaf, ['onEvent'], `Factory rules.github.${event}`);\n if (leaf.onEvent !== undefined && typeof leaf.onEvent !== 'function') {\n throw new FactoryRuleValidationError(`Factory rules.github.${event}.onEvent must be a function.`);\n }\n }\n\n if (!isPlainObject(rules.linear)) throw new FactoryRuleValidationError('Factory rules.linear must be an object.');\n for (const [event, leaf] of Object.entries(rules.linear)) {\n enumValue(event, FACTORY_LINEAR_EVENTS, 'Factory Linear event');\n if (!isPlainObject(leaf)) throw new FactoryRuleValidationError(`Factory rules.linear.${event} must be an object.`);\n assertExactKeys(leaf, ['onEvent'], `Factory rules.linear.${event}`);\n if (leaf.onEvent !== undefined && typeof leaf.onEvent !== 'function') {\n throw new FactoryRuleValidationError(`Factory rules.linear.${event}.onEvent must be a function.`);\n }\n }\n}\n\nfunction commonCommitFields(value: Record<string, unknown>): { idempotencyKey: string } {\n return {\n idempotencyKey: boundedString(value.idempotencyKey, 'Factory decision idempotencyKey', MAX_IDEMPOTENCY_KEY_LENGTH),\n };\n}\n\nexport function validateFactoryRuleDecision(value: unknown, causalDepth = 0): FactoryRuleDecision {\n if (causalDepth > MAX_FACTORY_RULE_CAUSAL_DEPTH) {\n throw new FactoryRuleValidationError('Factory rule causal depth exceeded.');\n }\n if (!isPlainObject(value)) throw new FactoryRuleValidationError('Factory rule decision must be an object.');\n const type = value.type;\n if (typeof type !== 'string') throw new FactoryRuleValidationError('Factory rule decision type is required.');\n\n switch (type) {\n case 'reject': {\n assertExactKeys(value, ['type', 'code', 'reason'], 'Factory reject decision');\n return {\n type,\n code: enumValue(value.code, REJECTION_CODES, 'Factory rejection code'),\n reason: boundedString(value.reason, 'Factory rejection reason', MAX_REASON_LENGTH),\n };\n }\n case 'transition': {\n assertExactKeys(value, ['type', 'idempotencyKey', 'board', 'stage'], 'Factory transition decision');\n return {\n type,\n ...commonCommitFields(value),\n board: enumValue(value.board, FACTORY_RULE_BOARDS, 'Factory transition board'),\n stage: enumValue(value.stage, FACTORY_RULE_STAGES, 'Factory transition stage'),\n };\n }\n case 'upsertLinkedWorkItem': {\n assertExactKeys(\n value,\n ['type', 'idempotencyKey', 'board', 'source', 'sourceKey', 'title', 'url', 'stage', 'metadata'],\n 'Factory linked work item decision',\n );\n const url = value.url;\n if (url !== null && (typeof url !== 'string' || url.length > MAX_URL_LENGTH || !/^https?:\\/\\//.test(url))) {\n throw new FactoryRuleValidationError('Factory linked work item URL is invalid.');\n }\n const metadata = sanitizeMetadata(value.metadata);\n return {\n type,\n ...commonCommitFields(value),\n board: enumValue(value.board, FACTORY_RULE_BOARDS, 'Factory linked work item board'),\n source: enumValue(value.source, WORK_ITEM_SOURCES, 'Factory linked work item source'),\n sourceKey: boundedString(value.sourceKey, 'Factory linked work item sourceKey', MAX_SOURCE_KEY_LENGTH),\n title: boundedString(value.title, 'Factory linked work item title', MAX_TITLE_LENGTH),\n url,\n stage: enumValue(value.stage, FACTORY_RULE_STAGES, 'Factory linked work item stage'),\n ...(metadata ? { metadata } : {}),\n };\n }\n case 'invokeSkill': {\n assertExactKeys(\n value,\n ['type', 'idempotencyKey', 'role', 'skillName', 'arguments', 'precedingMessage'],\n 'Factory invoke skill decision',\n );\n const args = optionalBoundedString(value.arguments, 'Factory skill arguments', MAX_ARGUMENTS_LENGTH);\n const precedingMessage = optionalBoundedString(\n value.precedingMessage,\n 'Factory skill preceding message',\n MAX_MESSAGE_LENGTH,\n );\n return {\n type,\n ...commonCommitFields(value),\n role: boundedString(value.role, 'Factory skill role', MAX_ROLE_LENGTH, IDENTIFIER_RE),\n skillName: boundedString(value.skillName, 'Factory skill name', MAX_SKILL_NAME_LENGTH, SKILL_NAME_RE),\n ...(args ? { arguments: args } : {}),\n ...(precedingMessage ? { precedingMessage } : {}),\n };\n }\n case 'sendMessage': {\n assertExactKeys(\n value,\n ['type', 'idempotencyKey', 'role', 'message', 'priority', 'idleBehavior', 'prepareBinding'],\n 'Factory send message decision',\n );\n const priority =\n value.priority === undefined\n ? undefined\n : enumValue(value.priority, ['medium', 'high', 'urgent'] as const, 'Factory message priority');\n const idleBehavior =\n value.idleBehavior === undefined\n ? undefined\n : enumValue(value.idleBehavior, ['persist', 'wake'] as const, 'Factory message idle behavior');\n if (value.prepareBinding !== undefined && typeof value.prepareBinding !== 'boolean') {\n throw new FactoryRuleValidationError('Factory message prepareBinding must be a boolean.');\n }\n return {\n type,\n ...commonCommitFields(value),\n role: boundedString(value.role, 'Factory message role', MAX_ROLE_LENGTH, IDENTIFIER_RE),\n message: boundedString(value.message, 'Factory message', MAX_MESSAGE_LENGTH),\n ...(priority ? { priority } : {}),\n ...(idleBehavior ? { idleBehavior } : {}),\n ...(value.prepareBinding === true ? { prepareBinding: true } : {}),\n };\n }\n case 'notify': {\n assertExactKeys(value, ['type', 'idempotencyKey', 'title', 'body', 'level'], 'Factory notify decision');\n const body = optionalBoundedString(value.body, 'Factory notification body', MAX_MESSAGE_LENGTH);\n const level =\n value.level === undefined\n ? undefined\n : enumValue(value.level, ['info', 'warning', 'error'] as const, 'Factory notification level');\n return {\n type,\n ...commonCommitFields(value),\n title: boundedString(value.title, 'Factory notification title', MAX_TITLE_LENGTH),\n ...(body ? { body } : {}),\n ...(level ? { level } : {}),\n };\n }\n default:\n throw new FactoryRuleValidationError('Factory rule decision type is unsupported.');\n }\n}\n\nexport function validateFactoryRuleDecisions(values: readonly unknown[], causalDepth = 0): FactoryCommitDecision[] {\n if (values.length > MAX_JSON_COLLECTION_SIZE) {\n throw new FactoryRuleValidationError('Factory rule produced too many decisions.');\n }\n const decisions: FactoryCommitDecision[] = [];\n for (const value of values) {\n const decision = validateFactoryRuleDecision(value, causalDepth);\n if (decision.type === 'reject') {\n throw new FactoryRuleValidationError('A rejection cannot be persisted with commit decisions.');\n }\n decisions.push(decision);\n }\n const keys = decisions.map(decision => decision.idempotencyKey);\n if (new Set(keys).size !== keys.length) {\n throw new FactoryRuleValidationError('Factory decisions require unique idempotency keys.');\n }\n return decisions;\n}\n","import type { GithubIntegration } from '../integrations/github/integration.js';\nimport type { ParsedGithubWebhook } from '../integrations/github/webhook.js';\nimport type { IntegrationStorageHandle } from '../storage/domains/integrations/base.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type {\n ExternalRepositoryProjectTarget,\n SourceControlStorageHandle,\n} from '../storage/domains/source-control/base.js';\nimport type { WorkItemRow, WorkItemsStorage } from '../storage/domains/work-items/base.js';\nimport { resolveFactoryGithubRule } from './resolve.js';\nimport type {\n FactoryGithubEventName,\n FactoryGithubRuleContext,\n FactoryRuleActor,\n FactoryRuleDecision,\n FactoryRules,\n} from './types.js';\nimport { validateFactoryRuleDecisions } from './validation.js';\n\nconst TRUSTED_PERMISSIONS = new Set(['write', 'admin']);\nconst RULE_TIMEOUT_MS = 5_000;\n\nasync function withRuleTimeout<T>(promise: Promise<T>): Promise<T> {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n timeout = setTimeout(() => reject(new Error('FACTORY_RULE_TIMEOUT')), RULE_TIMEOUT_MS);\n }),\n ]);\n } finally {\n if (timeout) clearTimeout(timeout);\n }\n}\n\nfunction object(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;\n}\n\nfunction string(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction number(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction boolean(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined;\n}\n\nfunction eventName(parsed: ParsedGithubWebhook): FactoryGithubEventName | undefined {\n const action = string(parsed.payload.action);\n if (parsed.event === 'issues' && action === 'opened') return 'issueOpened';\n if (parsed.event === 'pull_request' && action === 'opened') return 'pullRequestOpened';\n if (parsed.event === 'pull_request' && action === 'synchronize') return 'pullRequestUpdated';\n if (parsed.event === 'pull_request' && action === 'closed' && boolean(object(parsed.payload.pull_request)?.merged)) {\n return 'pullRequestMerged';\n }\n if (parsed.event === 'pull_request' && action === 'review_requested') return 'pullRequestReviewRequested';\n return undefined;\n}\n\nfunction canonicalSourceKey(kind: 'issue' | 'pull-request', itemNumber: number): string {\n return kind === 'issue' ? `github-issue:${itemNumber}` : `github-pr:${itemNumber}`;\n}\n\nfunction legacySourceKey(repositoryId: number, kind: 'issue' | 'pull-request', itemNumber: number): string {\n return `github:${repositoryId}:${kind}:${itemNumber}`;\n}\n\nfunction provenanceTarget(repositoryId: number, pullRequestNumber: number): string {\n return `factory-pr-provenance:${repositoryId}:${pullRequestNumber}`;\n}\n\nfunction workItemSource(item: WorkItemRow) {\n if (!item.externalSource) return 'manual' as const;\n return item.externalSource.type === 'pull-request' ? ('github-pr' as const) : ('github-issue' as const);\n}\n\nfunction workItemSourceKey(item: WorkItemRow): string | null {\n return item.externalSource?.externalId ?? null;\n}\n\nasync function githubActor(\n github: GithubIntegration,\n input: { installationId: number; repository: string; login: string; factoryAuthored: boolean },\n): Promise<FactoryRuleActor> {\n let trusted = false;\n try {\n const permission = await github.getRepositoryCollaboratorPermission(\n input.installationId,\n input.repository,\n input.login,\n );\n trusted = permission !== undefined && TRUSTED_PERMISSIONS.has(permission);\n } catch {\n trusted = false;\n }\n return { type: 'github', login: input.login, trusted, factoryAuthored: input.factoryAuthored };\n}\n\ninterface FactoryPullRequestProvenanceData {\n kind: 'factory-pr-provenance';\n workItemId: string;\n}\n\nexport interface FactoryGithubEventServiceOptions {\n github: GithubIntegration;\n sourceControl: SourceControlStorageHandle;\n integrationStorage: IntegrationStorageHandle<\n Record<string, unknown>,\n Record<string, unknown>,\n FactoryPullRequestProvenanceData\n >;\n projects: FactoryProjectsStorage;\n storage: WorkItemsStorage;\n rules: FactoryRules;\n}\n\nexport class FactoryGithubEventService {\n constructor(private readonly options: FactoryGithubEventServiceOptions) {}\n\n async ingest(parsed: ParsedGithubWebhook): Promise<{ status: 'ignored' | 'committed' | 'replayed' | 'missing' }> {\n const event = eventName(parsed);\n const repository = object(parsed.payload.repository);\n const installationId = number(object(parsed.payload.installation)?.id);\n const repositoryId = number(repository?.id);\n const repositoryName = string(repository?.full_name);\n const login = string(object(parsed.payload.sender)?.login);\n if (!event || !installationId || !repositoryId || !repositoryName || !login) return { status: 'ignored' };\n\n const projects = await this.options.sourceControl.projectRepositories.listByExternalRepository({\n installationExternalId: String(installationId),\n repositoryExternalId: String(repositoryId),\n });\n if (projects.length === 0) return { status: 'ignored' };\n const results = [];\n for (const project of projects) {\n results.push(\n await this.#ingestProject(parsed, event, installationId, repositoryId, repositoryName, login, project),\n );\n }\n if (results.some(result => result.status === 'committed')) return { status: 'committed' };\n if (results.some(result => result.status === 'replayed')) return { status: 'replayed' };\n return results[0] ?? { status: 'ignored' };\n }\n\n async #ingestProject(\n parsed: ParsedGithubWebhook,\n event: FactoryGithubEventName,\n installationId: number,\n repositoryId: number,\n repositoryName: string,\n login: string,\n project: ExternalRepositoryProjectTarget,\n ): Promise<{ status: 'committed' | 'replayed' | 'missing' }> {\n const factoryProject = await this.options.projects.get({\n orgId: project.orgId,\n id: project.factoryProjectId,\n });\n if (!factoryProject) return { status: 'missing' };\n const issue = object(parsed.payload.issue);\n const pullRequest = object(parsed.payload.pull_request);\n const issueNumber = number(issue?.number);\n const pullRequestNumber = number(pullRequest?.number);\n const provenance = pullRequestNumber\n ? ((\n await this.options.integrationStorage.subscriptions.listByTarget(\n provenanceTarget(repositoryId, pullRequestNumber),\n { status: 'active' },\n )\n ).find(subscription => subscription.orgId === project.orgId)?.data ?? null)\n : null;\n const relatedItem = await this.#relatedItem(\n project.orgId,\n project.factoryProjectId,\n repositoryId,\n issueNumber,\n pullRequestNumber,\n string(object(pullRequest?.head)?.ref),\n provenance,\n );\n const actor = await githubActor(this.options.github, {\n installationId,\n repository: repositoryName,\n login,\n factoryAuthored: provenance !== null,\n });\n const context: FactoryGithubRuleContext = {\n tenant: { orgId: project.orgId, projectId: project.factoryProjectId },\n actor,\n ingress: { type: 'github', id: `${installationId}:${parsed.deliveryId}` },\n cause: `github.${event}`,\n causalChain: [],\n ruleSetVersion: this.options.rules.version,\n ...(relatedItem\n ? {\n item: {\n id: relatedItem.id,\n source: workItemSource(relatedItem),\n sourceKey: workItemSourceKey(relatedItem),\n parentWorkItemId: relatedItem.parentWorkItemId,\n title: relatedItem.title,\n url: relatedItem.externalSource?.url ?? null,\n stages: relatedItem.stages,\n },\n board: relatedItem.externalSource?.type === 'pull-request' ? ('review' as const) : ('work' as const),\n itemRevision: relatedItem.revision,\n }\n : {}),\n event,\n deliveryId: parsed.deliveryId,\n factory: { createdAt: factoryProject.createdAt.toISOString() },\n repository: { id: repositoryId, fullName: repositoryName },\n ...(issueNumber && string(issue?.title) && string(issue?.html_url)\n ? {\n issue: {\n number: issueNumber,\n title: string(issue?.title)!,\n url: string(issue?.html_url)!,\n ...(string(issue?.created_at) ? { createdAt: string(issue?.created_at) } : {}),\n },\n }\n : {}),\n ...(pullRequestNumber && string(pullRequest?.title) && string(pullRequest?.html_url)\n ? {\n pullRequest: {\n number: pullRequestNumber,\n title: string(pullRequest?.title)!,\n url: string(pullRequest?.html_url)!,\n ...(string(pullRequest?.created_at) ? { createdAt: string(pullRequest?.created_at) } : {}),\n state: string(pullRequest?.state) === 'closed' ? ('closed' as const) : ('open' as const),\n merged: boolean(pullRequest?.merged) ?? false,\n headBranch: string(object(pullRequest?.head)?.ref) ?? '',\n baseBranch: string(object(pullRequest?.base)?.ref) ?? '',\n },\n }\n : {}),\n ...(object(parsed.payload.review)\n ? {\n review: {\n id: number(object(parsed.payload.review)?.id) ?? 0,\n state: string(object(parsed.payload.review)?.state) ?? 'unknown',\n url: string(object(parsed.payload.review)?.html_url) ?? '',\n },\n }\n : {}),\n };\n\n const rule = resolveFactoryGithubRule(this.options.rules, event);\n let decision: FactoryRuleDecision | void;\n let decisions: Record<string, unknown>[] = [];\n let outcome: { status: 'accepted' | 'rejected'; code?: string; reason?: string } = { status: 'accepted' };\n try {\n decision = rule ? await withRuleTimeout(Promise.resolve(rule(Object.freeze(context)))) : undefined;\n if (decision?.type === 'reject') {\n outcome = { status: 'rejected', code: decision.code, reason: decision.reason };\n } else if (decision) {\n decisions = validateFactoryRuleDecisions([decision]).map(entry => ({ ...entry }));\n }\n } catch (error) {\n const timedOut = error instanceof Error && error.message === 'FACTORY_RULE_TIMEOUT';\n outcome = {\n status: 'rejected',\n code: timedOut ? 'timeout' : 'rule_error',\n reason: timedOut\n ? 'Factory rule evaluation timed out.'\n : error instanceof Error\n ? error.message.slice(0, 2_000)\n : 'Factory GitHub rule failed.',\n };\n }\n\n const committed = await this.options.storage.commitRuleEvaluation({\n orgId: project.orgId,\n factoryProjectId: project.factoryProjectId,\n workItemId: relatedItem?.id ?? null,\n ingress: { identity: `${installationId}:${parsed.deliveryId}`, triggerType: `github.${event}` },\n ruleSetVersion: this.options.rules.version,\n expectedRevision: relatedItem?.revision ?? null,\n actor: { ...actor },\n outcome,\n decisions,\n causalChain: [],\n now: new Date(),\n });\n return { status: committed.status };\n }\n\n async #relatedItem(\n orgId: string,\n projectId: string,\n repositoryId: number,\n issueNumber: number | undefined,\n pullRequestNumber: number | undefined,\n pullRequestHeadBranch: string | undefined,\n provenance: FactoryPullRequestProvenanceData | null,\n ): Promise<WorkItemRow | undefined> {\n const items = await this.options.storage.list({ orgId, factoryProjectId: projectId });\n if (provenance) return items.find(item => item.id === provenance.workItemId);\n if (issueNumber) {\n return (\n items.find(item => item.externalSource?.externalId === canonicalSourceKey('issue', issueNumber)) ??\n items.find(item => item.externalSource?.externalId === legacySourceKey(repositoryId, 'issue', issueNumber))\n );\n }\n if (pullRequestNumber) {\n return (\n items.find(item => item.externalSource?.externalId === canonicalSourceKey('pull-request', pullRequestNumber)) ??\n items.find(\n item => item.externalSource?.externalId === legacySourceKey(repositoryId, 'pull-request', pullRequestNumber),\n ) ??\n // Provenance fallback: a PR pushed from a work item's session branch\n // belongs to that item even when no gh-pr-create provenance was\n // recorded (session predating state seeding, or the PR was opened\n // outside the tracked tool call). Session branches are per-item\n // (`factory/issue-N`), so a head-branch match is unambiguous.\n (pullRequestHeadBranch\n ? items.find(\n item =>\n item.externalSource?.type !== 'pull-request' &&\n Object.values(item.sessions).some(session => session.branch === pullRequestHeadBranch),\n )\n : undefined)\n );\n }\n return undefined;\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,27 +0,0 @@
1
- import type { LinearIssueIngress } from '../integrations/base.js';
2
- import type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';
3
- import type { WorkItemsStorage } from '../storage/domains/work-items/base.js';
4
- import type { FactoryRules } from './types.js';
5
- export interface FactoryLinearIssueServiceOptions {
6
- projects: Pick<FactoryProjectsStorage, 'get'>;
7
- storage: WorkItemsStorage;
8
- rules: FactoryRules;
9
- }
10
- export interface FactoryLinearIssueIngress {
11
- orgId: string;
12
- userId: string;
13
- factoryProjectId: string;
14
- issues: LinearIssueIngress[];
15
- }
16
- type IngressStatus = 'committed' | 'replayed' | 'missing';
17
- export declare class FactoryLinearIssueService {
18
- #private;
19
- private readonly options;
20
- constructor(options: FactoryLinearIssueServiceOptions);
21
- ingest(input: FactoryLinearIssueIngress): Promise<{
22
- status: IngressStatus;
23
- ingested: number;
24
- }>;
25
- }
26
- export {};
27
- //# sourceMappingURL=linear-service.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"linear-service.d.ts","sourceRoot":"","sources":["../../src/rules/linear-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,KAAK,EAAe,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAE3F,OAAO,KAAK,EAAiD,YAAY,EAAE,MAAM,YAAY,CAAC;AAmB9F,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,EAAE,IAAI,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;IAC9C,OAAO,EAAE,gBAAgB,CAAC;IAC1B,KAAK,EAAE,YAAY,CAAC;CACrB;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,kBAAkB,EAAE,CAAC;CAC9B;AAED,KAAK,aAAa,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;AAE1D,qBAAa,yBAAyB;;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,gCAAgC;IAEhE,MAAM,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,aAAa,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CAuFrG"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/rules/resolve.ts","../../src/rules/types.ts","../../src/rules/validation.ts","../../src/rules/linear-service.ts"],"sourcesContent":["import type {\n FactoryGithubEventName,\n FactoryGithubRuleLeaf,\n FactoryLinearEventName,\n FactoryLinearRuleLeaf,\n FactoryRuleBoard,\n FactoryRuleHandler,\n FactoryRuleSource,\n FactoryRuleStage,\n FactoryRules,\n FactoryStageRuleContext,\n FactoryToolResultRuleContext,\n FactoryToolRuleLeaf,\n} from './types.js';\n\nexport interface ResolvedFactoryStageRule {\n phase: 'exit' | 'enter';\n handler: FactoryRuleHandler<FactoryStageRuleContext>;\n}\n\nexport function resolveFactoryStageRules(\n rules: FactoryRules,\n input: {\n board: FactoryRuleBoard;\n source: FactoryRuleSource;\n fromStage: FactoryRuleStage;\n toStage: FactoryRuleStage;\n initialEntry?: boolean;\n },\n): ResolvedFactoryStageRule[] {\n if (input.fromStage === input.toStage && !input.initialEntry) return [];\n const boardRules = rules[input.board];\n const resolved: ResolvedFactoryStageRule[] = [];\n const onExit = input.initialEntry ? undefined : boardRules[input.fromStage]?.[input.source]?.onExit;\n if (onExit) resolved.push({ phase: 'exit', handler: onExit });\n const onEnter = boardRules[input.toStage]?.[input.source]?.onEnter;\n if (onEnter) resolved.push({ phase: 'enter', handler: onEnter });\n return resolved;\n}\n\nexport function resolveFactoryToolRule(rules: FactoryRules, toolName: string): FactoryToolRuleLeaf['onResult'] {\n return rules.tools[toolName]?.onResult;\n}\n\nexport function resolveFactoryGithubRule(\n rules: FactoryRules,\n event: FactoryGithubEventName,\n): FactoryGithubRuleLeaf['onEvent'] {\n return rules.github[event]?.onEvent;\n}\n\nexport function resolveFactoryLinearRule(\n rules: FactoryRules,\n event: FactoryLinearEventName,\n): FactoryLinearRuleLeaf['onEvent'] {\n return rules.linear[event]?.onEvent;\n}\n\nexport type ResolvedFactoryToolRule = FactoryRuleHandler<FactoryToolResultRuleContext>;\n","export type WorkItemSource = 'github-issue' | 'github-pr' | 'linear-issue' | 'manual';\n\nexport const FACTORY_RULE_STAGES = ['intake', 'triage', 'planning', 'execute', 'review', 'done', 'canceled'] as const;\nexport type FactoryRuleStage = (typeof FACTORY_RULE_STAGES)[number];\n\nexport const FACTORY_RULE_BOARDS = ['work', 'review'] as const;\nexport type FactoryRuleBoard = (typeof FACTORY_RULE_BOARDS)[number];\n\nexport const FACTORY_RULE_SOURCES = ['issue', 'pullRequest', 'linearIssue', 'manual'] as const;\nexport type FactoryRuleSource = (typeof FACTORY_RULE_SOURCES)[number];\n\nexport const FACTORY_GITHUB_EVENTS = [\n 'issueOpened',\n 'pullRequestOpened',\n 'pullRequestUpdated',\n 'pullRequestReviewRequested',\n 'pullRequestMerged',\n] as const;\nexport type FactoryGithubEventName = (typeof FACTORY_GITHUB_EVENTS)[number];\n\nexport const FACTORY_LINEAR_EVENTS = ['issueObserved'] as const;\nexport type FactoryLinearEventName = (typeof FACTORY_LINEAR_EVENTS)[number];\n\nexport type FactoryRuleJsonValue =\n | null\n | boolean\n | number\n | string\n | FactoryRuleJsonValue[]\n | { [key: string]: FactoryRuleJsonValue };\n\nexport interface FactoryRuleItemContext {\n id: string;\n source: WorkItemSource;\n sourceKey: string | null;\n parentWorkItemId: string | null;\n title: string;\n url: string | null;\n stages: readonly string[];\n}\n\nexport type FactoryRuleActor =\n | { type: 'human'; id: string }\n | { type: 'agent'; bindingId: string; role: string }\n | { type: 'github'; login: string; trusted: boolean; factoryAuthored: boolean }\n | { type: 'system'; id: string };\n\nexport interface FactoryRuleIngressIdentity {\n type: 'human' | 'agent' | 'toolResult' | 'github' | 'linear' | 'rule';\n id: string;\n}\n\nexport interface FactoryRuleCausalEntry {\n ingressId: string;\n decisionType: FactoryCommitDecision['type'];\n}\n\nexport interface FactoryRuleContextBase {\n tenant: { orgId: string; projectId: string };\n actor: FactoryRuleActor;\n ingress: FactoryRuleIngressIdentity;\n cause: string;\n causalChain: readonly FactoryRuleCausalEntry[];\n ruleSetVersion: string;\n}\n\nexport interface FactoryBoundRuleContext extends FactoryRuleContextBase {\n item: FactoryRuleItemContext;\n board: FactoryRuleBoard;\n itemRevision: number;\n}\n\nexport interface FactoryStageRuleContext extends FactoryBoundRuleContext {\n source: FactoryRuleSource;\n stage: FactoryRuleStage;\n fromStage: FactoryRuleStage;\n toStage: FactoryRuleStage;\n}\n\nexport interface FactoryToolResultRuleContext extends FactoryBoundRuleContext {\n toolName: string;\n threadId: string;\n assistantMessageId: string;\n toolCallId: string;\n result: {\n status: 'success' | 'error';\n value: FactoryRuleJsonValue;\n };\n}\n\nexport interface FactoryGithubRuleContext extends FactoryRuleContextBase {\n item?: FactoryRuleItemContext;\n board?: FactoryRuleBoard;\n itemRevision?: number;\n event: FactoryGithubEventName;\n deliveryId: string;\n factory: { createdAt: string };\n repository: { id: number; fullName: string };\n issue?: { number: number; title: string; url: string; createdAt?: string };\n pullRequest?: {\n number: number;\n title: string;\n url: string;\n createdAt?: string;\n state: 'open' | 'closed';\n merged: boolean;\n headBranch: string;\n baseBranch: string;\n };\n}\n\nexport interface FactoryLinearRuleContext extends FactoryRuleContextBase {\n item?: FactoryRuleItemContext;\n board?: FactoryRuleBoard;\n itemRevision?: number;\n event: FactoryLinearEventName;\n issue: {\n id: string;\n identifier: string;\n title: string;\n url: string;\n state: string;\n stateType: string;\n priorityLabel: string;\n assignee: string | null;\n team: string | null;\n labels: readonly string[];\n createdAt: string;\n updatedAt: string;\n };\n}\n\nexport type FactoryRuleHandler<TContext> = (\n context: Readonly<TContext>,\n) => FactoryRuleDecision | void | Promise<FactoryRuleDecision | void>;\n\nexport interface FactoryBoardRuleLeaf {\n onEnter?: FactoryRuleHandler<FactoryStageRuleContext>;\n onExit?: FactoryRuleHandler<FactoryStageRuleContext>;\n}\n\nexport interface FactoryToolRuleLeaf {\n onResult?: FactoryRuleHandler<FactoryToolResultRuleContext>;\n}\n\nexport interface FactoryGithubRuleLeaf {\n onEvent?: FactoryRuleHandler<FactoryGithubRuleContext>;\n}\n\nexport interface FactoryLinearRuleLeaf {\n onEvent?: FactoryRuleHandler<FactoryLinearRuleContext>;\n}\n\nexport type FactoryBoardRules = Partial<\n Record<FactoryRuleStage, Partial<Record<FactoryRuleSource, FactoryBoardRuleLeaf>>>\n>;\n\nexport interface FactoryRules {\n version: string;\n work: FactoryBoardRules;\n review: FactoryBoardRules;\n tools: Record<string, FactoryToolRuleLeaf>;\n github: Partial<Record<FactoryGithubEventName, FactoryGithubRuleLeaf>>;\n linear: Partial<Record<FactoryLinearEventName, FactoryLinearRuleLeaf>>;\n}\n\nexport interface FactoryRulesOverrides {\n work?: FactoryBoardRules;\n review?: FactoryBoardRules;\n tools?: Record<string, FactoryToolRuleLeaf>;\n github?: Partial<Record<FactoryGithubEventName, FactoryGithubRuleLeaf>>;\n linear?: Partial<Record<FactoryLinearEventName, FactoryLinearRuleLeaf>>;\n}\n\nexport type FactoryRuleRejectionCode =\n | 'forbidden'\n | 'invalid_transition'\n | 'missing_binding'\n | 'stale'\n | 'timeout'\n | 'rule_error'\n | 'causal_depth_exceeded'\n | 'repeated_transition';\n\nexport interface FactoryRuleRejectDecision {\n type: 'reject';\n code: FactoryRuleRejectionCode;\n reason: string;\n}\n\ninterface FactoryCommitDecisionBase {\n idempotencyKey: string;\n}\n\nexport interface FactoryTransitionDecision extends FactoryCommitDecisionBase {\n type: 'transition';\n board: FactoryRuleBoard;\n stage: FactoryRuleStage;\n}\n\nexport interface FactoryUpsertLinkedWorkItemDecision extends FactoryCommitDecisionBase {\n type: 'upsertLinkedWorkItem';\n board: FactoryRuleBoard;\n source: WorkItemSource;\n sourceKey: string;\n title: string;\n url: string | null;\n stage: FactoryRuleStage;\n metadata?: Record<string, FactoryRuleJsonValue>;\n}\n\nexport interface FactoryInvokeSkillDecision extends FactoryCommitDecisionBase {\n type: 'invokeSkill';\n role: string;\n skillName: string;\n arguments?: string;\n precedingMessage?: string;\n}\n\nexport interface FactorySendMessageDecision extends FactoryCommitDecisionBase {\n type: 'sendMessage';\n role: string;\n message: string;\n priority?: 'medium' | 'high' | 'urgent';\n idleBehavior?: 'persist' | 'wake';\n prepareBinding?: boolean;\n}\n\nexport interface FactoryNotifyDecision extends FactoryCommitDecisionBase {\n type: 'notify';\n title: string;\n body?: string;\n level?: 'info' | 'warning' | 'error';\n}\n\nexport type FactoryCommitDecision =\n | FactoryTransitionDecision\n | FactoryUpsertLinkedWorkItemDecision\n | FactoryInvokeSkillDecision\n | FactorySendMessageDecision\n | FactoryNotifyDecision;\n\nexport type FactoryRuleDecision = FactoryRuleRejectDecision | FactoryCommitDecision;\n\nexport interface FactoryTransitionResultAccepted {\n status: 'accepted';\n transitionId: string;\n itemId: string;\n revision: number;\n stage: FactoryRuleStage;\n decisions: FactoryCommitDecision[];\n}\n\nexport interface FactoryTransitionResultRejected {\n status: 'rejected';\n transitionId: string;\n itemId: string;\n code: FactoryRuleRejectionCode;\n reason: string;\n}\n\nexport type FactoryTransitionResult = FactoryTransitionResultAccepted | FactoryTransitionResultRejected;\n\nexport function factoryRuleSourceForWorkItem(source: WorkItemSource): FactoryRuleSource {\n switch (source) {\n case 'github-issue':\n return 'issue';\n case 'github-pr':\n return 'pullRequest';\n case 'linear-issue':\n return 'linearIssue';\n case 'manual':\n return 'manual';\n }\n}\n","import {\n FACTORY_GITHUB_EVENTS,\n FACTORY_LINEAR_EVENTS,\n FACTORY_RULE_BOARDS,\n FACTORY_RULE_SOURCES,\n FACTORY_RULE_STAGES,\n} from './types.js';\nimport type {\n FactoryBoardRules,\n FactoryCommitDecision,\n FactoryRuleDecision,\n FactoryRuleJsonValue,\n FactoryRules,\n FactoryRuleRejectionCode,\n WorkItemSource,\n} from './types.js';\n\nexport const MAX_FACTORY_RULE_CAUSAL_DEPTH = 8;\n\nconst MAX_VERSION_LENGTH = 128;\nconst MAX_IDEMPOTENCY_KEY_LENGTH = 256;\nconst MAX_REASON_LENGTH = 512;\nconst MAX_TITLE_LENGTH = 512;\nconst MAX_MESSAGE_LENGTH = 8_192;\nconst MAX_ARGUMENTS_LENGTH = 4_096;\nconst MAX_ROLE_LENGTH = 32;\nconst MAX_SKILL_NAME_LENGTH = 128;\nconst MAX_SOURCE_KEY_LENGTH = 256;\nconst MAX_URL_LENGTH = 2_048;\nconst MAX_METADATA_JSON_LENGTH = 16_384;\nconst MAX_JSON_DEPTH = 8;\nconst MAX_JSON_COLLECTION_SIZE = 100;\n\nconst IDENTIFIER_RE = /^[a-z0-9][a-z0-9_-]*$/i;\nconst SKILL_NAME_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\nconst SENSITIVE_KEY_RE = /(?:authorization|cookie|credential|password|secret|token)/i;\nconst WORK_ITEM_SOURCES: readonly WorkItemSource[] = ['github-issue', 'github-pr', 'linear-issue', 'manual'];\nconst REJECTION_CODES: readonly FactoryRuleRejectionCode[] = [\n 'forbidden',\n 'invalid_transition',\n 'missing_binding',\n 'stale',\n 'timeout',\n 'rule_error',\n 'causal_depth_exceeded',\n 'repeated_transition',\n];\n\nexport class FactoryRuleValidationError extends Error {\n readonly code = 'invalid_factory_rule';\n\n constructor(message: string) {\n super(message);\n this.name = 'FactoryRuleValidationError';\n }\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\nfunction assertExactKeys(value: Record<string, unknown>, keys: readonly string[], label: string): void {\n const allowed = new Set(keys);\n if (Object.keys(value).some(key => !allowed.has(key))) {\n throw new FactoryRuleValidationError(`${label} contains an unsupported field.`);\n }\n}\n\nfunction boundedString(value: unknown, label: string, max: number, pattern?: RegExp): string {\n if (typeof value !== 'string') throw new FactoryRuleValidationError(`${label} must be a string.`);\n const normalized = value.trim();\n if (normalized.length === 0 || normalized.length > max || (pattern && !pattern.test(normalized))) {\n throw new FactoryRuleValidationError(`${label} is invalid.`);\n }\n return normalized;\n}\n\nfunction optionalBoundedString(value: unknown, label: string, max: number): string | undefined {\n if (value === undefined) return undefined;\n return boundedString(value, label, max);\n}\n\nfunction enumValue<T extends string>(value: unknown, allowed: readonly T[], label: string): T {\n if (typeof value !== 'string' || !allowed.includes(value as T)) {\n throw new FactoryRuleValidationError(`${label} is invalid.`);\n }\n return value as T;\n}\n\nexport function normalizeFactoryRuleJsonValue(\n value: unknown,\n depth = 0,\n seen = new Set<object>(),\n): FactoryRuleJsonValue {\n if (value === null || typeof value === 'boolean' || typeof value === 'string') return value;\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) throw new FactoryRuleValidationError('Rule metadata must contain finite numbers.');\n return value;\n }\n if (depth >= MAX_JSON_DEPTH || (typeof value !== 'object' && !Array.isArray(value))) {\n throw new FactoryRuleValidationError('Rule metadata is not bounded JSON.');\n }\n if (seen.has(value as object)) throw new FactoryRuleValidationError('Rule metadata must not contain cycles.');\n seen.add(value as object);\n try {\n if (Array.isArray(value)) {\n if (value.length > MAX_JSON_COLLECTION_SIZE) {\n throw new FactoryRuleValidationError('Rule metadata contains too many entries.');\n }\n return value.map(entry => normalizeFactoryRuleJsonValue(entry, depth + 1, seen));\n }\n if (!isPlainObject(value)) throw new FactoryRuleValidationError('Rule metadata must use plain objects.');\n const entries = Object.entries(value);\n if (entries.length > MAX_JSON_COLLECTION_SIZE) {\n throw new FactoryRuleValidationError('Rule metadata contains too many fields.');\n }\n const sanitized: Record<string, FactoryRuleJsonValue> = {};\n for (const [key, entry] of entries) {\n const normalizedKey = boundedString(key, 'Rule metadata key', 128, IDENTIFIER_RE);\n sanitized[normalizedKey] = SENSITIVE_KEY_RE.test(normalizedKey)\n ? '[REDACTED]'\n : normalizeFactoryRuleJsonValue(entry, depth + 1, seen);\n }\n return sanitized;\n } finally {\n seen.delete(value as object);\n }\n}\n\nfunction sanitizeMetadata(value: unknown): Record<string, FactoryRuleJsonValue> | undefined {\n if (value === undefined) return undefined;\n const sanitized = normalizeFactoryRuleJsonValue(value);\n if (!isPlainObject(sanitized)) throw new FactoryRuleValidationError('Rule metadata must be an object.');\n if (JSON.stringify(sanitized).length > MAX_METADATA_JSON_LENGTH) {\n throw new FactoryRuleValidationError('Rule metadata is too large.');\n }\n return sanitized;\n}\n\nfunction validateBoardRules(rules: unknown, label: string): asserts rules is FactoryBoardRules {\n if (!isPlainObject(rules)) throw new FactoryRuleValidationError(`${label} must be an object.`);\n for (const [stage, sources] of Object.entries(rules)) {\n enumValue(stage, FACTORY_RULE_STAGES, `${label} stage`);\n if (!isPlainObject(sources)) throw new FactoryRuleValidationError(`${label}.${stage} must be an object.`);\n for (const [source, leaf] of Object.entries(sources)) {\n enumValue(source, FACTORY_RULE_SOURCES, `${label}.${stage} source`);\n if (!isPlainObject(leaf)) throw new FactoryRuleValidationError(`${label}.${stage}.${source} must be an object.`);\n assertExactKeys(leaf, ['onEnter', 'onExit'], `${label}.${stage}.${source}`);\n for (const handler of Object.values(leaf)) {\n if (handler !== undefined && typeof handler !== 'function') {\n throw new FactoryRuleValidationError(`${label}.${stage}.${source} handlers must be functions.`);\n }\n }\n }\n }\n}\n\nexport function assertFactoryRules(rules: unknown): asserts rules is FactoryRules {\n if (!isPlainObject(rules)) throw new FactoryRuleValidationError('Factory rules must be an object.');\n assertExactKeys(rules, ['version', 'work', 'review', 'tools', 'github', 'linear'], 'Factory rules');\n boundedString(rules.version, 'Factory rule version', MAX_VERSION_LENGTH);\n validateBoardRules(rules.work, 'Factory rules.work');\n validateBoardRules(rules.review, 'Factory rules.review');\n\n if (!isPlainObject(rules.tools)) throw new FactoryRuleValidationError('Factory rules.tools must be an object.');\n for (const [toolName, leaf] of Object.entries(rules.tools)) {\n boundedString(toolName, 'Factory tool name', 128, IDENTIFIER_RE);\n if (!isPlainObject(leaf))\n throw new FactoryRuleValidationError(`Factory rules.tools.${toolName} must be an object.`);\n assertExactKeys(leaf, ['onResult'], `Factory rules.tools.${toolName}`);\n if (leaf.onResult !== undefined && typeof leaf.onResult !== 'function') {\n throw new FactoryRuleValidationError(`Factory rules.tools.${toolName}.onResult must be a function.`);\n }\n }\n\n if (!isPlainObject(rules.github)) throw new FactoryRuleValidationError('Factory rules.github must be an object.');\n for (const [event, leaf] of Object.entries(rules.github)) {\n enumValue(event, FACTORY_GITHUB_EVENTS, 'Factory GitHub event');\n if (!isPlainObject(leaf)) throw new FactoryRuleValidationError(`Factory rules.github.${event} must be an object.`);\n assertExactKeys(leaf, ['onEvent'], `Factory rules.github.${event}`);\n if (leaf.onEvent !== undefined && typeof leaf.onEvent !== 'function') {\n throw new FactoryRuleValidationError(`Factory rules.github.${event}.onEvent must be a function.`);\n }\n }\n\n if (!isPlainObject(rules.linear)) throw new FactoryRuleValidationError('Factory rules.linear must be an object.');\n for (const [event, leaf] of Object.entries(rules.linear)) {\n enumValue(event, FACTORY_LINEAR_EVENTS, 'Factory Linear event');\n if (!isPlainObject(leaf)) throw new FactoryRuleValidationError(`Factory rules.linear.${event} must be an object.`);\n assertExactKeys(leaf, ['onEvent'], `Factory rules.linear.${event}`);\n if (leaf.onEvent !== undefined && typeof leaf.onEvent !== 'function') {\n throw new FactoryRuleValidationError(`Factory rules.linear.${event}.onEvent must be a function.`);\n }\n }\n}\n\nfunction commonCommitFields(value: Record<string, unknown>): { idempotencyKey: string } {\n return {\n idempotencyKey: boundedString(value.idempotencyKey, 'Factory decision idempotencyKey', MAX_IDEMPOTENCY_KEY_LENGTH),\n };\n}\n\nexport function validateFactoryRuleDecision(value: unknown, causalDepth = 0): FactoryRuleDecision {\n if (causalDepth > MAX_FACTORY_RULE_CAUSAL_DEPTH) {\n throw new FactoryRuleValidationError('Factory rule causal depth exceeded.');\n }\n if (!isPlainObject(value)) throw new FactoryRuleValidationError('Factory rule decision must be an object.');\n const type = value.type;\n if (typeof type !== 'string') throw new FactoryRuleValidationError('Factory rule decision type is required.');\n\n switch (type) {\n case 'reject': {\n assertExactKeys(value, ['type', 'code', 'reason'], 'Factory reject decision');\n return {\n type,\n code: enumValue(value.code, REJECTION_CODES, 'Factory rejection code'),\n reason: boundedString(value.reason, 'Factory rejection reason', MAX_REASON_LENGTH),\n };\n }\n case 'transition': {\n assertExactKeys(value, ['type', 'idempotencyKey', 'board', 'stage'], 'Factory transition decision');\n return {\n type,\n ...commonCommitFields(value),\n board: enumValue(value.board, FACTORY_RULE_BOARDS, 'Factory transition board'),\n stage: enumValue(value.stage, FACTORY_RULE_STAGES, 'Factory transition stage'),\n };\n }\n case 'upsertLinkedWorkItem': {\n assertExactKeys(\n value,\n ['type', 'idempotencyKey', 'board', 'source', 'sourceKey', 'title', 'url', 'stage', 'metadata'],\n 'Factory linked work item decision',\n );\n const url = value.url;\n if (url !== null && (typeof url !== 'string' || url.length > MAX_URL_LENGTH || !/^https?:\\/\\//.test(url))) {\n throw new FactoryRuleValidationError('Factory linked work item URL is invalid.');\n }\n const metadata = sanitizeMetadata(value.metadata);\n return {\n type,\n ...commonCommitFields(value),\n board: enumValue(value.board, FACTORY_RULE_BOARDS, 'Factory linked work item board'),\n source: enumValue(value.source, WORK_ITEM_SOURCES, 'Factory linked work item source'),\n sourceKey: boundedString(value.sourceKey, 'Factory linked work item sourceKey', MAX_SOURCE_KEY_LENGTH),\n title: boundedString(value.title, 'Factory linked work item title', MAX_TITLE_LENGTH),\n url,\n stage: enumValue(value.stage, FACTORY_RULE_STAGES, 'Factory linked work item stage'),\n ...(metadata ? { metadata } : {}),\n };\n }\n case 'invokeSkill': {\n assertExactKeys(\n value,\n ['type', 'idempotencyKey', 'role', 'skillName', 'arguments', 'precedingMessage'],\n 'Factory invoke skill decision',\n );\n const args = optionalBoundedString(value.arguments, 'Factory skill arguments', MAX_ARGUMENTS_LENGTH);\n const precedingMessage = optionalBoundedString(\n value.precedingMessage,\n 'Factory skill preceding message',\n MAX_MESSAGE_LENGTH,\n );\n return {\n type,\n ...commonCommitFields(value),\n role: boundedString(value.role, 'Factory skill role', MAX_ROLE_LENGTH, IDENTIFIER_RE),\n skillName: boundedString(value.skillName, 'Factory skill name', MAX_SKILL_NAME_LENGTH, SKILL_NAME_RE),\n ...(args ? { arguments: args } : {}),\n ...(precedingMessage ? { precedingMessage } : {}),\n };\n }\n case 'sendMessage': {\n assertExactKeys(\n value,\n ['type', 'idempotencyKey', 'role', 'message', 'priority', 'idleBehavior', 'prepareBinding'],\n 'Factory send message decision',\n );\n const priority =\n value.priority === undefined\n ? undefined\n : enumValue(value.priority, ['medium', 'high', 'urgent'] as const, 'Factory message priority');\n const idleBehavior =\n value.idleBehavior === undefined\n ? undefined\n : enumValue(value.idleBehavior, ['persist', 'wake'] as const, 'Factory message idle behavior');\n if (value.prepareBinding !== undefined && typeof value.prepareBinding !== 'boolean') {\n throw new FactoryRuleValidationError('Factory message prepareBinding must be a boolean.');\n }\n return {\n type,\n ...commonCommitFields(value),\n role: boundedString(value.role, 'Factory message role', MAX_ROLE_LENGTH, IDENTIFIER_RE),\n message: boundedString(value.message, 'Factory message', MAX_MESSAGE_LENGTH),\n ...(priority ? { priority } : {}),\n ...(idleBehavior ? { idleBehavior } : {}),\n ...(value.prepareBinding === true ? { prepareBinding: true } : {}),\n };\n }\n case 'notify': {\n assertExactKeys(value, ['type', 'idempotencyKey', 'title', 'body', 'level'], 'Factory notify decision');\n const body = optionalBoundedString(value.body, 'Factory notification body', MAX_MESSAGE_LENGTH);\n const level =\n value.level === undefined\n ? undefined\n : enumValue(value.level, ['info', 'warning', 'error'] as const, 'Factory notification level');\n return {\n type,\n ...commonCommitFields(value),\n title: boundedString(value.title, 'Factory notification title', MAX_TITLE_LENGTH),\n ...(body ? { body } : {}),\n ...(level ? { level } : {}),\n };\n }\n default:\n throw new FactoryRuleValidationError('Factory rule decision type is unsupported.');\n }\n}\n\nexport function validateFactoryRuleDecisions(values: readonly unknown[], causalDepth = 0): FactoryCommitDecision[] {\n if (values.length > MAX_JSON_COLLECTION_SIZE) {\n throw new FactoryRuleValidationError('Factory rule produced too many decisions.');\n }\n const decisions: FactoryCommitDecision[] = [];\n for (const value of values) {\n const decision = validateFactoryRuleDecision(value, causalDepth);\n if (decision.type === 'reject') {\n throw new FactoryRuleValidationError('A rejection cannot be persisted with commit decisions.');\n }\n decisions.push(decision);\n }\n const keys = decisions.map(decision => decision.idempotencyKey);\n if (new Set(keys).size !== keys.length) {\n throw new FactoryRuleValidationError('Factory decisions require unique idempotency keys.');\n }\n return decisions;\n}\n","import type { LinearIssueIngress } from '../integrations/base.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type { WorkItemRow, WorkItemsStorage } from '../storage/domains/work-items/base.js';\nimport { resolveFactoryLinearRule } from './resolve.js';\nimport type { FactoryLinearRuleContext, FactoryRuleDecision, FactoryRules } from './types.js';\nimport { validateFactoryRuleDecisions } from './validation.js';\n\nconst RULE_TIMEOUT_MS = 5_000;\n\nasync function withRuleTimeout<T>(promise: Promise<T>): Promise<T> {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n timeout = setTimeout(() => reject(new Error('FACTORY_RULE_TIMEOUT')), RULE_TIMEOUT_MS);\n }),\n ]);\n } finally {\n if (timeout) clearTimeout(timeout);\n }\n}\n\nexport interface FactoryLinearIssueServiceOptions {\n projects: Pick<FactoryProjectsStorage, 'get'>;\n storage: WorkItemsStorage;\n rules: FactoryRules;\n}\n\nexport interface FactoryLinearIssueIngress {\n orgId: string;\n userId: string;\n factoryProjectId: string;\n issues: LinearIssueIngress[];\n}\n\ntype IngressStatus = 'committed' | 'replayed' | 'missing';\n\nexport class FactoryLinearIssueService {\n constructor(private readonly options: FactoryLinearIssueServiceOptions) {}\n\n async ingest(input: FactoryLinearIssueIngress): Promise<{ status: IngressStatus; ingested: number }> {\n const project = await this.options.projects.get({ orgId: input.orgId, id: input.factoryProjectId });\n if (!project) return { status: 'missing', ingested: 0 };\n\n const items = await this.options.storage.list({ orgId: input.orgId, factoryProjectId: input.factoryProjectId });\n const itemsBySourceKey = new Map(items.map(item => [item.externalSource?.externalId, item]));\n const statuses: IngressStatus[] = [];\n for (const issue of input.issues) {\n statuses.push(await this.#ingestIssue(input, issue, itemsBySourceKey.get(`linear:${issue.identifier}`)));\n }\n if (statuses.some(status => status === 'committed')) return { status: 'committed', ingested: statuses.length };\n if (statuses.some(status => status === 'replayed')) return { status: 'replayed', ingested: statuses.length };\n return { status: 'missing', ingested: statuses.length };\n }\n\n async #ingestIssue(\n input: FactoryLinearIssueIngress,\n issue: LinearIssueIngress,\n relatedItem: WorkItemRow | undefined,\n ): Promise<IngressStatus> {\n const ingressId = `linear:${issue.id}:${issue.updatedAt}`;\n const actor = { type: 'human' as const, id: input.userId };\n const context: FactoryLinearRuleContext = {\n tenant: { orgId: input.orgId, projectId: input.factoryProjectId },\n actor,\n ingress: { type: 'linear', id: ingressId },\n cause: 'linear.issueObserved',\n causalChain: [],\n ruleSetVersion: this.options.rules.version,\n ...(relatedItem\n ? {\n item: {\n id: relatedItem.id,\n source: 'linear-issue',\n sourceKey: relatedItem.externalSource?.externalId ?? null,\n parentWorkItemId: relatedItem.parentWorkItemId,\n title: relatedItem.title,\n url: relatedItem.externalSource?.url ?? null,\n stages: relatedItem.stages,\n },\n board: 'work' as const,\n itemRevision: relatedItem.revision,\n }\n : {}),\n event: 'issueObserved',\n issue,\n };\n\n const rule = resolveFactoryLinearRule(this.options.rules, context.event);\n let decision: FactoryRuleDecision | void;\n let decisions: Record<string, unknown>[] = [];\n let outcome: { status: 'accepted' | 'rejected'; code?: string; reason?: string } = { status: 'accepted' };\n try {\n decision = rule ? await withRuleTimeout(Promise.resolve(rule(Object.freeze(context)))) : undefined;\n if (decision?.type === 'reject') {\n outcome = { status: 'rejected', code: decision.code, reason: decision.reason };\n } else if (decision) {\n decisions = validateFactoryRuleDecisions([decision]).map(entry => ({ ...entry }));\n }\n } catch (error) {\n const timedOut = error instanceof Error && error.message === 'FACTORY_RULE_TIMEOUT';\n outcome = {\n status: 'rejected',\n code: timedOut ? 'timeout' : 'rule_error',\n reason: timedOut\n ? 'Factory rule evaluation timed out.'\n : error instanceof Error\n ? error.message.slice(0, 2_000)\n : 'Factory Linear rule failed.',\n };\n }\n\n const committed = await this.options.storage.commitRuleEvaluation({\n orgId: input.orgId,\n factoryProjectId: input.factoryProjectId,\n workItemId: relatedItem?.id ?? null,\n ingress: { identity: ingressId, triggerType: 'linear.issueObserved' },\n ruleSetVersion: this.options.rules.version,\n expectedRevision: relatedItem?.revision ?? null,\n actor,\n outcome,\n decisions,\n causalChain: [],\n now: new Date(),\n });\n return committed.status;\n }\n}\n"],"mappings":";AAmDO,SAAS,yBACd,OACA,OACkC;AAClC,SAAO,MAAM,OAAO,KAAK,GAAG;AAC9B;;;ACtDO,IAAM,sBAAsB,CAAC,UAAU,UAAU,YAAY,WAAW,UAAU,QAAQ,UAAU;AAGpG,IAAM,sBAAsB,CAAC,QAAQ,QAAQ;;;ACY7C,IAAM,gCAAgC;AAG7C,IAAM,6BAA6B;AACnC,IAAM,oBAAoB;AAC1B,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AAC3B,IAAM,uBAAuB;AAC7B,IAAM,kBAAkB;AACxB,IAAM,wBAAwB;AAC9B,IAAM,wBAAwB;AAC9B,IAAM,iBAAiB;AACvB,IAAM,2BAA2B;AACjC,IAAM,iBAAiB;AACvB,IAAM,2BAA2B;AAEjC,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AACtB,IAAM,mBAAmB;AACzB,IAAM,oBAA+C,CAAC,gBAAgB,aAAa,gBAAgB,QAAQ;AAC3G,IAAM,kBAAuD;AAAA,EAC3D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAM,6BAAN,cAAyC,MAAM;AAAA,EAC3C,OAAO;AAAA,EAEhB,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEA,SAAS,cAAc,OAAkD;AACvE,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,EAAG,QAAO;AAChF,QAAM,YAAY,OAAO,eAAe,KAAK;AAC7C,SAAO,cAAc,OAAO,aAAa,cAAc;AACzD;AAEA,SAAS,gBAAgB,OAAgC,MAAyB,OAAqB;AACrG,QAAM,UAAU,IAAI,IAAI,IAAI;AAC5B,MAAI,OAAO,KAAK,KAAK,EAAE,KAAK,SAAO,CAAC,QAAQ,IAAI,GAAG,CAAC,GAAG;AACrD,UAAM,IAAI,2BAA2B,GAAG,KAAK,iCAAiC;AAAA,EAChF;AACF;AAEA,SAAS,cAAc,OAAgB,OAAe,KAAa,SAA0B;AAC3F,MAAI,OAAO,UAAU,SAAU,OAAM,IAAI,2BAA2B,GAAG,KAAK,oBAAoB;AAChG,QAAM,aAAa,MAAM,KAAK;AAC9B,MAAI,WAAW,WAAW,KAAK,WAAW,SAAS,OAAQ,WAAW,CAAC,QAAQ,KAAK,UAAU,GAAI;AAChG,UAAM,IAAI,2BAA2B,GAAG,KAAK,cAAc;AAAA,EAC7D;AACA,SAAO;AACT;AAEA,SAAS,sBAAsB,OAAgB,OAAe,KAAiC;AAC7F,MAAI,UAAU,OAAW,QAAO;AAChC,SAAO,cAAc,OAAO,OAAO,GAAG;AACxC;AAEA,SAAS,UAA4B,OAAgB,SAAuB,OAAkB;AAC5F,MAAI,OAAO,UAAU,YAAY,CAAC,QAAQ,SAAS,KAAU,GAAG;AAC9D,UAAM,IAAI,2BAA2B,GAAG,KAAK,cAAc;AAAA,EAC7D;AACA,SAAO;AACT;AAEO,SAAS,8BACd,OACA,QAAQ,GACR,OAAO,oBAAI,IAAY,GACD;AACtB,MAAI,UAAU,QAAQ,OAAO,UAAU,aAAa,OAAO,UAAU,SAAU,QAAO;AACtF,MAAI,OAAO,UAAU,UAAU;AAC7B,QAAI,CAAC,OAAO,SAAS,KAAK,EAAG,OAAM,IAAI,2BAA2B,4CAA4C;AAC9G,WAAO;AAAA,EACT;AACA,MAAI,SAAS,kBAAmB,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAAI;AACnF,UAAM,IAAI,2BAA2B,oCAAoC;AAAA,EAC3E;AACA,MAAI,KAAK,IAAI,KAAe,EAAG,OAAM,IAAI,2BAA2B,wCAAwC;AAC5G,OAAK,IAAI,KAAe;AACxB,MAAI;AACF,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,UAAI,MAAM,SAAS,0BAA0B;AAC3C,cAAM,IAAI,2BAA2B,0CAA0C;AAAA,MACjF;AACA,aAAO,MAAM,IAAI,WAAS,8BAA8B,OAAO,QAAQ,GAAG,IAAI,CAAC;AAAA,IACjF;AACA,QAAI,CAAC,cAAc,KAAK,EAAG,OAAM,IAAI,2BAA2B,uCAAuC;AACvG,UAAM,UAAU,OAAO,QAAQ,KAAK;AACpC,QAAI,QAAQ,SAAS,0BAA0B;AAC7C,YAAM,IAAI,2BAA2B,yCAAyC;AAAA,IAChF;AACA,UAAM,YAAkD,CAAC;AACzD,eAAW,CAAC,KAAK,KAAK,KAAK,SAAS;AAClC,YAAM,gBAAgB,cAAc,KAAK,qBAAqB,KAAK,aAAa;AAChF,gBAAU,aAAa,IAAI,iBAAiB,KAAK,aAAa,IAC1D,eACA,8BAA8B,OAAO,QAAQ,GAAG,IAAI;AAAA,IAC1D;AACA,WAAO;AAAA,EACT,UAAE;AACA,SAAK,OAAO,KAAe;AAAA,EAC7B;AACF;AAEA,SAAS,iBAAiB,OAAkE;AAC1F,MAAI,UAAU,OAAW,QAAO;AAChC,QAAM,YAAY,8BAA8B,KAAK;AACrD,MAAI,CAAC,cAAc,SAAS,EAAG,OAAM,IAAI,2BAA2B,kCAAkC;AACtG,MAAI,KAAK,UAAU,SAAS,EAAE,SAAS,0BAA0B;AAC/D,UAAM,IAAI,2BAA2B,6BAA6B;AAAA,EACpE;AACA,SAAO;AACT;AA2DA,SAAS,mBAAmB,OAA4D;AACtF,SAAO;AAAA,IACL,gBAAgB,cAAc,MAAM,gBAAgB,mCAAmC,0BAA0B;AAAA,EACnH;AACF;AAEO,SAAS,4BAA4B,OAAgB,cAAc,GAAwB;AAChG,MAAI,cAAc,+BAA+B;AAC/C,UAAM,IAAI,2BAA2B,qCAAqC;AAAA,EAC5E;AACA,MAAI,CAAC,cAAc,KAAK,EAAG,OAAM,IAAI,2BAA2B,0CAA0C;AAC1G,QAAM,OAAO,MAAM;AACnB,MAAI,OAAO,SAAS,SAAU,OAAM,IAAI,2BAA2B,yCAAyC;AAE5G,UAAQ,MAAM;AAAA,IACZ,KAAK,UAAU;AACb,sBAAgB,OAAO,CAAC,QAAQ,QAAQ,QAAQ,GAAG,yBAAyB;AAC5E,aAAO;AAAA,QACL;AAAA,QACA,MAAM,UAAU,MAAM,MAAM,iBAAiB,wBAAwB;AAAA,QACrE,QAAQ,cAAc,MAAM,QAAQ,4BAA4B,iBAAiB;AAAA,MACnF;AAAA,IACF;AAAA,IACA,KAAK,cAAc;AACjB,sBAAgB,OAAO,CAAC,QAAQ,kBAAkB,SAAS,OAAO,GAAG,6BAA6B;AAClG,aAAO;AAAA,QACL;AAAA,QACA,GAAG,mBAAmB,KAAK;AAAA,QAC3B,OAAO,UAAU,MAAM,OAAO,qBAAqB,0BAA0B;AAAA,QAC7E,OAAO,UAAU,MAAM,OAAO,qBAAqB,0BAA0B;AAAA,MAC/E;AAAA,IACF;AAAA,IACA,KAAK,wBAAwB;AAC3B;AAAA,QACE;AAAA,QACA,CAAC,QAAQ,kBAAkB,SAAS,UAAU,aAAa,SAAS,OAAO,SAAS,UAAU;AAAA,QAC9F;AAAA,MACF;AACA,YAAM,MAAM,MAAM;AAClB,UAAI,QAAQ,SAAS,OAAO,QAAQ,YAAY,IAAI,SAAS,kBAAkB,CAAC,eAAe,KAAK,GAAG,IAAI;AACzG,cAAM,IAAI,2BAA2B,0CAA0C;AAAA,MACjF;AACA,YAAM,WAAW,iBAAiB,MAAM,QAAQ;AAChD,aAAO;AAAA,QACL;AAAA,QACA,GAAG,mBAAmB,KAAK;AAAA,QAC3B,OAAO,UAAU,MAAM,OAAO,qBAAqB,gCAAgC;AAAA,QACnF,QAAQ,UAAU,MAAM,QAAQ,mBAAmB,iCAAiC;AAAA,QACpF,WAAW,cAAc,MAAM,WAAW,sCAAsC,qBAAqB;AAAA,QACrG,OAAO,cAAc,MAAM,OAAO,kCAAkC,gBAAgB;AAAA,QACpF;AAAA,QACA,OAAO,UAAU,MAAM,OAAO,qBAAqB,gCAAgC;AAAA,QACnF,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,MACjC;AAAA,IACF;AAAA,IACA,KAAK,eAAe;AAClB;AAAA,QACE;AAAA,QACA,CAAC,QAAQ,kBAAkB,QAAQ,aAAa,aAAa,kBAAkB;AAAA,QAC/E;AAAA,MACF;AACA,YAAM,OAAO,sBAAsB,MAAM,WAAW,2BAA2B,oBAAoB;AACnG,YAAM,mBAAmB;AAAA,QACvB,MAAM;AAAA,QACN;AAAA,QACA;AAAA,MACF;AACA,aAAO;AAAA,QACL;AAAA,QACA,GAAG,mBAAmB,KAAK;AAAA,QAC3B,MAAM,cAAc,MAAM,MAAM,sBAAsB,iBAAiB,aAAa;AAAA,QACpF,WAAW,cAAc,MAAM,WAAW,sBAAsB,uBAAuB,aAAa;AAAA,QACpG,GAAI,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;AAAA,QAClC,GAAI,mBAAmB,EAAE,iBAAiB,IAAI,CAAC;AAAA,MACjD;AAAA,IACF;AAAA,IACA,KAAK,eAAe;AAClB;AAAA,QACE;AAAA,QACA,CAAC,QAAQ,kBAAkB,QAAQ,WAAW,YAAY,gBAAgB,gBAAgB;AAAA,QAC1F;AAAA,MACF;AACA,YAAM,WACJ,MAAM,aAAa,SACf,SACA,UAAU,MAAM,UAAU,CAAC,UAAU,QAAQ,QAAQ,GAAY,0BAA0B;AACjG,YAAM,eACJ,MAAM,iBAAiB,SACnB,SACA,UAAU,MAAM,cAAc,CAAC,WAAW,MAAM,GAAY,+BAA+B;AACjG,UAAI,MAAM,mBAAmB,UAAa,OAAO,MAAM,mBAAmB,WAAW;AACnF,cAAM,IAAI,2BAA2B,mDAAmD;AAAA,MAC1F;AACA,aAAO;AAAA,QACL;AAAA,QACA,GAAG,mBAAmB,KAAK;AAAA,QAC3B,MAAM,cAAc,MAAM,MAAM,wBAAwB,iBAAiB,aAAa;AAAA,QACtF,SAAS,cAAc,MAAM,SAAS,mBAAmB,kBAAkB;AAAA,QAC3E,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,QAC/B,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;AAAA,QACvC,GAAI,MAAM,mBAAmB,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAAA,MAClE;AAAA,IACF;AAAA,IACA,KAAK,UAAU;AACb,sBAAgB,OAAO,CAAC,QAAQ,kBAAkB,SAAS,QAAQ,OAAO,GAAG,yBAAyB;AACtG,YAAM,OAAO,sBAAsB,MAAM,MAAM,6BAA6B,kBAAkB;AAC9F,YAAM,QACJ,MAAM,UAAU,SACZ,SACA,UAAU,MAAM,OAAO,CAAC,QAAQ,WAAW,OAAO,GAAY,4BAA4B;AAChG,aAAO;AAAA,QACL;AAAA,QACA,GAAG,mBAAmB,KAAK;AAAA,QAC3B,OAAO,cAAc,MAAM,OAAO,8BAA8B,gBAAgB;AAAA,QAChF,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,QACvB,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,MAC3B;AAAA,IACF;AAAA,IACA;AACE,YAAM,IAAI,2BAA2B,4CAA4C;AAAA,EACrF;AACF;AAEO,SAAS,6BAA6B,QAA4B,cAAc,GAA4B;AACjH,MAAI,OAAO,SAAS,0BAA0B;AAC5C,UAAM,IAAI,2BAA2B,2CAA2C;AAAA,EAClF;AACA,QAAM,YAAqC,CAAC;AAC5C,aAAW,SAAS,QAAQ;AAC1B,UAAM,WAAW,4BAA4B,OAAO,WAAW;AAC/D,QAAI,SAAS,SAAS,UAAU;AAC9B,YAAM,IAAI,2BAA2B,wDAAwD;AAAA,IAC/F;AACA,cAAU,KAAK,QAAQ;AAAA,EACzB;AACA,QAAM,OAAO,UAAU,IAAI,cAAY,SAAS,cAAc;AAC9D,MAAI,IAAI,IAAI,IAAI,EAAE,SAAS,KAAK,QAAQ;AACtC,UAAM,IAAI,2BAA2B,oDAAoD;AAAA,EAC3F;AACA,SAAO;AACT;;;AC3UA,IAAM,kBAAkB;AAExB,eAAe,gBAAmB,SAAiC;AACjE,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,QAAQ,KAAK;AAAA,MACxB;AAAA,MACA,IAAI,QAAe,CAAC,GAAG,WAAW;AAChC,kBAAU,WAAW,MAAM,OAAO,IAAI,MAAM,sBAAsB,CAAC,GAAG,eAAe;AAAA,MACvF,CAAC;AAAA,IACH,CAAC;AAAA,EACH,UAAE;AACA,QAAI,QAAS,cAAa,OAAO;AAAA,EACnC;AACF;AAiBO,IAAM,4BAAN,MAAgC;AAAA,EACrC,YAA6B,SAA2C;AAA3C;AAAA,EAA4C;AAAA,EAA5C;AAAA,EAE7B,MAAM,OAAO,OAAwF;AACnG,UAAM,UAAU,MAAM,KAAK,QAAQ,SAAS,IAAI,EAAE,OAAO,MAAM,OAAO,IAAI,MAAM,iBAAiB,CAAC;AAClG,QAAI,CAAC,QAAS,QAAO,EAAE,QAAQ,WAAW,UAAU,EAAE;AAEtD,UAAM,QAAQ,MAAM,KAAK,QAAQ,QAAQ,KAAK,EAAE,OAAO,MAAM,OAAO,kBAAkB,MAAM,iBAAiB,CAAC;AAC9G,UAAM,mBAAmB,IAAI,IAAI,MAAM,IAAI,UAAQ,CAAC,KAAK,gBAAgB,YAAY,IAAI,CAAC,CAAC;AAC3F,UAAM,WAA4B,CAAC;AACnC,eAAW,SAAS,MAAM,QAAQ;AAChC,eAAS,KAAK,MAAM,KAAK,aAAa,OAAO,OAAO,iBAAiB,IAAI,UAAU,MAAM,UAAU,EAAE,CAAC,CAAC;AAAA,IACzG;AACA,QAAI,SAAS,KAAK,YAAU,WAAW,WAAW,EAAG,QAAO,EAAE,QAAQ,aAAa,UAAU,SAAS,OAAO;AAC7G,QAAI,SAAS,KAAK,YAAU,WAAW,UAAU,EAAG,QAAO,EAAE,QAAQ,YAAY,UAAU,SAAS,OAAO;AAC3G,WAAO,EAAE,QAAQ,WAAW,UAAU,SAAS,OAAO;AAAA,EACxD;AAAA,EAEA,MAAM,aACJ,OACA,OACA,aACwB;AACxB,UAAM,YAAY,UAAU,MAAM,EAAE,IAAI,MAAM,SAAS;AACvD,UAAM,QAAQ,EAAE,MAAM,SAAkB,IAAI,MAAM,OAAO;AACzD,UAAM,UAAoC;AAAA,MACxC,QAAQ,EAAE,OAAO,MAAM,OAAO,WAAW,MAAM,iBAAiB;AAAA,MAChE;AAAA,MACA,SAAS,EAAE,MAAM,UAAU,IAAI,UAAU;AAAA,MACzC,OAAO;AAAA,MACP,aAAa,CAAC;AAAA,MACd,gBAAgB,KAAK,QAAQ,MAAM;AAAA,MACnC,GAAI,cACA;AAAA,QACE,MAAM;AAAA,UACJ,IAAI,YAAY;AAAA,UAChB,QAAQ;AAAA,UACR,WAAW,YAAY,gBAAgB,cAAc;AAAA,UACrD,kBAAkB,YAAY;AAAA,UAC9B,OAAO,YAAY;AAAA,UACnB,KAAK,YAAY,gBAAgB,OAAO;AAAA,UACxC,QAAQ,YAAY;AAAA,QACtB;AAAA,QACA,OAAO;AAAA,QACP,cAAc,YAAY;AAAA,MAC5B,IACA,CAAC;AAAA,MACL,OAAO;AAAA,MACP;AAAA,IACF;AAEA,UAAM,OAAO,yBAAyB,KAAK,QAAQ,OAAO,QAAQ,KAAK;AACvE,QAAI;AACJ,QAAI,YAAuC,CAAC;AAC5C,QAAI,UAA+E,EAAE,QAAQ,WAAW;AACxG,QAAI;AACF,iBAAW,OAAO,MAAM,gBAAgB,QAAQ,QAAQ,KAAK,OAAO,OAAO,OAAO,CAAC,CAAC,CAAC,IAAI;AACzF,UAAI,UAAU,SAAS,UAAU;AAC/B,kBAAU,EAAE,QAAQ,YAAY,MAAM,SAAS,MAAM,QAAQ,SAAS,OAAO;AAAA,MAC/E,WAAW,UAAU;AACnB,oBAAY,6BAA6B,CAAC,QAAQ,CAAC,EAAE,IAAI,YAAU,EAAE,GAAG,MAAM,EAAE;AAAA,MAClF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,WAAW,iBAAiB,SAAS,MAAM,YAAY;AAC7D,gBAAU;AAAA,QACR,QAAQ;AAAA,QACR,MAAM,WAAW,YAAY;AAAA,QAC7B,QAAQ,WACJ,uCACA,iBAAiB,QACf,MAAM,QAAQ,MAAM,GAAG,GAAK,IAC5B;AAAA,MACR;AAAA,IACF;AAEA,UAAM,YAAY,MAAM,KAAK,QAAQ,QAAQ,qBAAqB;AAAA,MAChE,OAAO,MAAM;AAAA,MACb,kBAAkB,MAAM;AAAA,MACxB,YAAY,aAAa,MAAM;AAAA,MAC/B,SAAS,EAAE,UAAU,WAAW,aAAa,uBAAuB;AAAA,MACpE,gBAAgB,KAAK,QAAQ,MAAM;AAAA,MACnC,kBAAkB,aAAa,YAAY;AAAA,MAC3C;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,CAAC;AAAA,MACd,KAAK,oBAAI,KAAK;AAAA,IAChB,CAAC;AACD,WAAO,UAAU;AAAA,EACnB;AACF;","names":[]}