@renseiai/agentfactory 0.8.7 → 0.8.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/config/index.d.ts +1 -1
- package/dist/src/config/index.d.ts.map +1 -1
- package/dist/src/config/index.js +1 -1
- package/dist/src/config/repository-config.d.ts +37 -0
- package/dist/src/config/repository-config.d.ts.map +1 -1
- package/dist/src/config/repository-config.js +47 -0
- package/dist/src/config/repository-config.test.js +140 -1
- package/dist/src/governor/decision-engine.d.ts +3 -0
- package/dist/src/governor/decision-engine.d.ts.map +1 -1
- package/dist/src/governor/decision-engine.js +11 -0
- package/dist/src/governor/decision-engine.test.js +33 -0
- package/dist/src/governor/event-types.d.ts +18 -1
- package/dist/src/governor/event-types.d.ts.map +1 -1
- package/dist/src/governor/event-types.js +4 -0
- package/dist/src/governor/governor-types.d.ts +1 -1
- package/dist/src/governor/governor-types.d.ts.map +1 -1
- package/dist/src/governor/governor.d.ts +17 -1
- package/dist/src/governor/governor.d.ts.map +1 -1
- package/dist/src/governor/governor.js +112 -1
- package/dist/src/governor/governor.test.js +155 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/merge-queue/adapters/github-native.d.ts +22 -0
- package/dist/src/merge-queue/adapters/github-native.d.ts.map +1 -0
- package/dist/src/merge-queue/adapters/github-native.js +243 -0
- package/dist/src/merge-queue/adapters/github-native.test.d.ts +2 -0
- package/dist/src/merge-queue/adapters/github-native.test.d.ts.map +1 -0
- package/dist/src/merge-queue/adapters/github-native.test.js +384 -0
- package/dist/src/merge-queue/index.d.ts +18 -0
- package/dist/src/merge-queue/index.d.ts.map +1 -0
- package/dist/src/merge-queue/index.js +28 -0
- package/dist/src/merge-queue/merge-queue.integration.test.d.ts +2 -0
- package/dist/src/merge-queue/merge-queue.integration.test.d.ts.map +1 -0
- package/dist/src/merge-queue/merge-queue.integration.test.js +128 -0
- package/dist/src/merge-queue/types.d.ts +48 -0
- package/dist/src/merge-queue/types.d.ts.map +1 -0
- package/dist/src/merge-queue/types.js +8 -0
- package/dist/src/orchestrator/artifact-tracker.d.ts +93 -0
- package/dist/src/orchestrator/artifact-tracker.d.ts.map +1 -0
- package/dist/src/orchestrator/artifact-tracker.js +235 -0
- package/dist/src/orchestrator/artifact-tracker.test.d.ts +2 -0
- package/dist/src/orchestrator/artifact-tracker.test.d.ts.map +1 -0
- package/dist/src/orchestrator/artifact-tracker.test.js +189 -0
- package/dist/src/orchestrator/context-manager.d.ts +72 -0
- package/dist/src/orchestrator/context-manager.d.ts.map +1 -0
- package/dist/src/orchestrator/context-manager.js +120 -0
- package/dist/src/orchestrator/context-manager.test.d.ts +2 -0
- package/dist/src/orchestrator/context-manager.test.d.ts.map +1 -0
- package/dist/src/orchestrator/context-manager.test.js +137 -0
- package/dist/src/orchestrator/index.d.ts +8 -2
- package/dist/src/orchestrator/index.d.ts.map +1 -1
- package/dist/src/orchestrator/index.js +8 -1
- package/dist/src/orchestrator/issue-tracker-client.d.ts +4 -0
- package/dist/src/orchestrator/issue-tracker-client.d.ts.map +1 -1
- package/dist/src/orchestrator/orchestrator.d.ts +12 -0
- package/dist/src/orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/src/orchestrator/orchestrator.js +282 -2
- package/dist/src/orchestrator/parse-work-result.d.ts.map +1 -1
- package/dist/src/orchestrator/parse-work-result.js +6 -0
- package/dist/src/orchestrator/parse-work-result.test.js +19 -0
- package/dist/src/orchestrator/state-recovery.d.ts +21 -2
- package/dist/src/orchestrator/state-recovery.d.ts.map +1 -1
- package/dist/src/orchestrator/state-recovery.js +54 -2
- package/dist/src/orchestrator/state-recovery.test.js +106 -2
- package/dist/src/orchestrator/state-types.d.ts +62 -0
- package/dist/src/orchestrator/state-types.d.ts.map +1 -1
- package/dist/src/orchestrator/state-types.js +5 -1
- package/dist/src/orchestrator/summary-builder.d.ts +47 -0
- package/dist/src/orchestrator/summary-builder.d.ts.map +1 -0
- package/dist/src/orchestrator/summary-builder.js +240 -0
- package/dist/src/orchestrator/summary-builder.test.d.ts +2 -0
- package/dist/src/orchestrator/summary-builder.test.d.ts.map +1 -0
- package/dist/src/orchestrator/summary-builder.test.js +236 -0
- package/dist/src/orchestrator/types.d.ts +2 -0
- package/dist/src/orchestrator/types.d.ts.map +1 -1
- package/dist/src/orchestrator/work-types.d.ts +1 -1
- package/dist/src/orchestrator/work-types.d.ts.map +1 -1
- package/dist/src/providers/index.d.ts +64 -1
- package/dist/src/providers/index.d.ts.map +1 -1
- package/dist/src/providers/index.js +132 -1
- package/dist/src/providers/index.test.js +340 -2
- package/dist/src/routing/index.d.ts +7 -0
- package/dist/src/routing/index.d.ts.map +1 -0
- package/dist/src/routing/index.js +6 -0
- package/dist/src/routing/observation-recorder.d.ts +19 -0
- package/dist/src/routing/observation-recorder.d.ts.map +1 -0
- package/dist/src/routing/observation-recorder.js +73 -0
- package/dist/src/routing/observation-recorder.test.d.ts +2 -0
- package/dist/src/routing/observation-recorder.test.d.ts.map +1 -0
- package/dist/src/routing/observation-recorder.test.js +322 -0
- package/dist/src/routing/observation-store.d.ts +40 -0
- package/dist/src/routing/observation-store.d.ts.map +1 -0
- package/dist/src/routing/observation-store.js +1 -0
- package/dist/src/routing/observation-store.test.d.ts +2 -0
- package/dist/src/routing/observation-store.test.d.ts.map +1 -0
- package/dist/src/routing/observation-store.test.js +138 -0
- package/dist/src/routing/posterior-store.d.ts +12 -0
- package/dist/src/routing/posterior-store.d.ts.map +1 -0
- package/dist/src/routing/posterior-store.js +13 -0
- package/dist/src/routing/posterior-store.test.d.ts +2 -0
- package/dist/src/routing/posterior-store.test.d.ts.map +1 -0
- package/dist/src/routing/posterior-store.test.js +37 -0
- package/dist/src/routing/reward.d.ts +16 -0
- package/dist/src/routing/reward.d.ts.map +1 -0
- package/dist/src/routing/reward.js +29 -0
- package/dist/src/routing/reward.test.d.ts +2 -0
- package/dist/src/routing/reward.test.d.ts.map +1 -0
- package/dist/src/routing/reward.test.js +210 -0
- package/dist/src/routing/routing-engine.d.ts +20 -0
- package/dist/src/routing/routing-engine.d.ts.map +1 -0
- package/dist/src/routing/routing-engine.js +113 -0
- package/dist/src/routing/routing-engine.test.d.ts +2 -0
- package/dist/src/routing/routing-engine.test.d.ts.map +1 -0
- package/dist/src/routing/routing-engine.test.js +310 -0
- package/dist/src/routing/types.d.ts +157 -0
- package/dist/src/routing/types.d.ts.map +1 -0
- package/dist/src/routing/types.js +68 -0
- package/dist/src/routing/types.test.d.ts +2 -0
- package/dist/src/routing/types.test.d.ts.map +1 -0
- package/dist/src/routing/types.test.js +184 -0
- package/dist/src/templates/registry.test.js +2 -2
- package/dist/src/templates/types.d.ts +5 -0
- package/dist/src/templates/types.d.ts.map +1 -1
- package/dist/src/templates/types.js +3 -0
- package/dist/src/workflow/agent-cancellation.d.ts +37 -0
- package/dist/src/workflow/agent-cancellation.d.ts.map +1 -0
- package/dist/src/workflow/agent-cancellation.js +41 -0
- package/dist/src/workflow/agent-cancellation.test.d.ts +2 -0
- package/dist/src/workflow/agent-cancellation.test.d.ts.map +1 -0
- package/dist/src/workflow/agent-cancellation.test.js +86 -0
- package/dist/src/workflow/branching-router.d.ts +38 -0
- package/dist/src/workflow/branching-router.d.ts.map +1 -0
- package/dist/src/workflow/branching-router.js +52 -0
- package/dist/src/workflow/branching-router.test.d.ts +2 -0
- package/dist/src/workflow/branching-router.test.d.ts.map +1 -0
- package/dist/src/workflow/branching-router.test.js +209 -0
- package/dist/src/workflow/concurrency-semaphore.d.ts +21 -0
- package/dist/src/workflow/concurrency-semaphore.d.ts.map +1 -0
- package/dist/src/workflow/concurrency-semaphore.js +46 -0
- package/dist/src/workflow/concurrency-semaphore.test.d.ts +2 -0
- package/dist/src/workflow/concurrency-semaphore.test.d.ts.map +1 -0
- package/dist/src/workflow/concurrency-semaphore.test.js +183 -0
- package/dist/src/workflow/duration.d.ts +28 -0
- package/dist/src/workflow/duration.d.ts.map +1 -0
- package/dist/src/workflow/duration.js +57 -0
- package/dist/src/workflow/duration.test.d.ts +2 -0
- package/dist/src/workflow/duration.test.d.ts.map +1 -0
- package/dist/src/workflow/duration.test.js +74 -0
- package/dist/src/workflow/expression/ast.d.ts +53 -0
- package/dist/src/workflow/expression/ast.d.ts.map +1 -0
- package/dist/src/workflow/expression/ast.js +8 -0
- package/dist/src/workflow/expression/context.d.ts +40 -0
- package/dist/src/workflow/expression/context.d.ts.map +1 -0
- package/dist/src/workflow/expression/context.js +37 -0
- package/dist/src/workflow/expression/evaluator.d.ts +28 -0
- package/dist/src/workflow/expression/evaluator.d.ts.map +1 -0
- package/dist/src/workflow/expression/evaluator.js +165 -0
- package/dist/src/workflow/expression/evaluator.test.d.ts +2 -0
- package/dist/src/workflow/expression/evaluator.test.d.ts.map +1 -0
- package/dist/src/workflow/expression/evaluator.test.js +792 -0
- package/dist/src/workflow/expression/expression.test.d.ts +2 -0
- package/dist/src/workflow/expression/expression.test.d.ts.map +1 -0
- package/dist/src/workflow/expression/expression.test.js +516 -0
- package/dist/src/workflow/expression/helpers.d.ts +21 -0
- package/dist/src/workflow/expression/helpers.d.ts.map +1 -0
- package/dist/src/workflow/expression/helpers.js +56 -0
- package/dist/src/workflow/expression/index.d.ts +55 -0
- package/dist/src/workflow/expression/index.d.ts.map +1 -0
- package/dist/src/workflow/expression/index.js +71 -0
- package/dist/src/workflow/expression/lexer.d.ts +37 -0
- package/dist/src/workflow/expression/lexer.d.ts.map +1 -0
- package/dist/src/workflow/expression/lexer.js +166 -0
- package/dist/src/workflow/expression/parser.d.ts +23 -0
- package/dist/src/workflow/expression/parser.d.ts.map +1 -0
- package/dist/src/workflow/expression/parser.js +181 -0
- package/dist/src/workflow/gate-state.d.ts +115 -0
- package/dist/src/workflow/gate-state.d.ts.map +1 -0
- package/dist/src/workflow/gate-state.js +185 -0
- package/dist/src/workflow/gate-state.test.d.ts +2 -0
- package/dist/src/workflow/gate-state.test.d.ts.map +1 -0
- package/dist/src/workflow/gate-state.test.js +251 -0
- package/dist/src/workflow/gates/gate-evaluator.d.ts +119 -0
- package/dist/src/workflow/gates/gate-evaluator.d.ts.map +1 -0
- package/dist/src/workflow/gates/gate-evaluator.js +243 -0
- package/dist/src/workflow/gates/gate-evaluator.test.d.ts +2 -0
- package/dist/src/workflow/gates/gate-evaluator.test.d.ts.map +1 -0
- package/dist/src/workflow/gates/gate-evaluator.test.js +240 -0
- package/dist/src/workflow/gates/signal-gate.d.ts +114 -0
- package/dist/src/workflow/gates/signal-gate.d.ts.map +1 -0
- package/dist/src/workflow/gates/signal-gate.js +216 -0
- package/dist/src/workflow/gates/signal-gate.test.d.ts +2 -0
- package/dist/src/workflow/gates/signal-gate.test.d.ts.map +1 -0
- package/dist/src/workflow/gates/signal-gate.test.js +199 -0
- package/dist/src/workflow/gates/timeout-engine.d.ts +96 -0
- package/dist/src/workflow/gates/timeout-engine.d.ts.map +1 -0
- package/dist/src/workflow/gates/timeout-engine.js +162 -0
- package/dist/src/workflow/gates/timeout-engine.test.d.ts +2 -0
- package/dist/src/workflow/gates/timeout-engine.test.d.ts.map +1 -0
- package/dist/src/workflow/gates/timeout-engine.test.js +186 -0
- package/dist/src/workflow/gates/timer-gate.d.ts +125 -0
- package/dist/src/workflow/gates/timer-gate.d.ts.map +1 -0
- package/dist/src/workflow/gates/timer-gate.js +381 -0
- package/dist/src/workflow/gates/timer-gate.test.d.ts +2 -0
- package/dist/src/workflow/gates/timer-gate.test.d.ts.map +1 -0
- package/dist/src/workflow/gates/timer-gate.test.js +211 -0
- package/dist/src/workflow/gates/webhook-gate.d.ts +132 -0
- package/dist/src/workflow/gates/webhook-gate.d.ts.map +1 -0
- package/dist/src/workflow/gates/webhook-gate.js +216 -0
- package/dist/src/workflow/gates/webhook-gate.test.d.ts +2 -0
- package/dist/src/workflow/gates/webhook-gate.test.d.ts.map +1 -0
- package/dist/src/workflow/gates/webhook-gate.test.js +182 -0
- package/dist/src/workflow/index.d.ts +31 -3
- package/dist/src/workflow/index.d.ts.map +1 -1
- package/dist/src/workflow/index.js +20 -1
- package/dist/src/workflow/parallelism-executor.d.ts +25 -0
- package/dist/src/workflow/parallelism-executor.d.ts.map +1 -0
- package/dist/src/workflow/parallelism-executor.js +53 -0
- package/dist/src/workflow/parallelism-executor.test.d.ts +2 -0
- package/dist/src/workflow/parallelism-executor.test.d.ts.map +1 -0
- package/dist/src/workflow/parallelism-executor.test.js +191 -0
- package/dist/src/workflow/parallelism-types.d.ts +80 -0
- package/dist/src/workflow/parallelism-types.d.ts.map +1 -0
- package/dist/src/workflow/parallelism-types.js +8 -0
- package/dist/src/workflow/phase-context-injector.d.ts +29 -0
- package/dist/src/workflow/phase-context-injector.d.ts.map +1 -0
- package/dist/src/workflow/phase-context-injector.js +43 -0
- package/dist/src/workflow/phase-context-injector.test.d.ts +2 -0
- package/dist/src/workflow/phase-context-injector.test.d.ts.map +1 -0
- package/dist/src/workflow/phase-context-injector.test.js +123 -0
- package/dist/src/workflow/phase-output-collector.d.ts +39 -0
- package/dist/src/workflow/phase-output-collector.d.ts.map +1 -0
- package/dist/src/workflow/phase-output-collector.js +141 -0
- package/dist/src/workflow/phase-output-collector.test.d.ts +2 -0
- package/dist/src/workflow/phase-output-collector.test.d.ts.map +1 -0
- package/dist/src/workflow/phase-output-collector.test.js +179 -0
- package/dist/src/workflow/retry-resolver.d.ts +51 -0
- package/dist/src/workflow/retry-resolver.d.ts.map +1 -0
- package/dist/src/workflow/retry-resolver.js +70 -0
- package/dist/src/workflow/retry-resolver.test.d.ts +2 -0
- package/dist/src/workflow/retry-resolver.test.d.ts.map +1 -0
- package/dist/src/workflow/retry-resolver.test.js +149 -0
- package/dist/src/workflow/strategies/fan-in-strategy.d.ts +21 -0
- package/dist/src/workflow/strategies/fan-in-strategy.d.ts.map +1 -0
- package/dist/src/workflow/strategies/fan-in-strategy.js +92 -0
- package/dist/src/workflow/strategies/fan-in-strategy.test.d.ts +2 -0
- package/dist/src/workflow/strategies/fan-in-strategy.test.d.ts.map +1 -0
- package/dist/src/workflow/strategies/fan-in-strategy.test.js +182 -0
- package/dist/src/workflow/strategies/fan-out-strategy.d.ts +16 -0
- package/dist/src/workflow/strategies/fan-out-strategy.d.ts.map +1 -0
- package/dist/src/workflow/strategies/fan-out-strategy.js +47 -0
- package/dist/src/workflow/strategies/fan-out-strategy.test.d.ts +2 -0
- package/dist/src/workflow/strategies/fan-out-strategy.test.d.ts.map +1 -0
- package/dist/src/workflow/strategies/fan-out-strategy.test.js +97 -0
- package/dist/src/workflow/strategies/index.d.ts +4 -0
- package/dist/src/workflow/strategies/index.d.ts.map +1 -0
- package/dist/src/workflow/strategies/index.js +3 -0
- package/dist/src/workflow/strategies/race-strategy.d.ts +19 -0
- package/dist/src/workflow/strategies/race-strategy.d.ts.map +1 -0
- package/dist/src/workflow/strategies/race-strategy.js +92 -0
- package/dist/src/workflow/strategies/race-strategy.test.d.ts +2 -0
- package/dist/src/workflow/strategies/race-strategy.test.d.ts.map +1 -0
- package/dist/src/workflow/strategies/race-strategy.test.js +318 -0
- package/dist/src/workflow/transition-engine.d.ts +3 -1
- package/dist/src/workflow/transition-engine.d.ts.map +1 -1
- package/dist/src/workflow/transition-engine.js +26 -7
- package/dist/src/workflow/transition-engine.test.js +215 -11
- package/dist/src/workflow/workflow-registry.d.ts +46 -1
- package/dist/src/workflow/workflow-registry.d.ts.map +1 -1
- package/dist/src/workflow/workflow-registry.js +74 -0
- package/dist/src/workflow/workflow-registry.test.js +54 -0
- package/dist/src/workflow/workflow-types.d.ts +330 -12
- package/dist/src/workflow/workflow-types.d.ts.map +1 -1
- package/dist/src/workflow/workflow-types.js +100 -5
- package/dist/src/workflow/workflow-types.test.js +293 -2
- package/package.json +2 -2
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expression Parser & Evaluator — Public API
|
|
3
|
+
*
|
|
4
|
+
* Parses Handlebars-style condition strings from WorkflowDefinition
|
|
5
|
+
* transitions into a typed AST, and evaluates them within a sandboxed
|
|
6
|
+
* context.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { parseExpression, evaluateCondition, buildEvaluationContext } from './expression/index.js'
|
|
11
|
+
*
|
|
12
|
+
* const ast = parseExpression("{{ hasLabel('bug') and priority gt 3 }}")
|
|
13
|
+
* // => BinaryOp(AND, FunctionCall("hasLabel", [StringLiteral("bug")]), BinaryOp(GT, ...))
|
|
14
|
+
*
|
|
15
|
+
* const ctx = buildEvaluationContext(issue, phaseState)
|
|
16
|
+
* const result = evaluateCondition("{{ hasLabel('bug') }}", ctx)
|
|
17
|
+
* // => true or false
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
import { tokenize } from './lexer.js';
|
|
21
|
+
import { parse } from './parser.js';
|
|
22
|
+
import { evaluate } from './evaluator.js';
|
|
23
|
+
export { ParseError, tokenize } from './lexer.js';
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Re-exports — Parser
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
export { parse } from './parser.js';
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Re-exports — Evaluator
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
export { evaluate, EvaluationError } from './evaluator.js';
|
|
32
|
+
export { buildEvaluationContext } from './context.js';
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Re-exports — Helpers
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
export { createBuiltinHelpers } from './helpers.js';
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Convenience entry points
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
/**
|
|
41
|
+
* Parse a condition string into an AST in a single call.
|
|
42
|
+
*
|
|
43
|
+
* Combines tokenization and parsing. Accepts strings with or without
|
|
44
|
+
* `{{ }}` delimiters.
|
|
45
|
+
*
|
|
46
|
+
* @param condition - The condition string to parse.
|
|
47
|
+
* @returns The root AST node.
|
|
48
|
+
* @throws {ParseError} on invalid input with position information.
|
|
49
|
+
*/
|
|
50
|
+
export function parseExpression(condition) {
|
|
51
|
+
const tokens = tokenize(condition);
|
|
52
|
+
return parse(tokens);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Parse and evaluate a condition string, returning a boolean result.
|
|
56
|
+
*
|
|
57
|
+
* This is the primary entry point for workflow transition evaluation.
|
|
58
|
+
* It combines parsing and evaluation in one call, and coerces the
|
|
59
|
+
* result to a boolean.
|
|
60
|
+
*
|
|
61
|
+
* @param condition - The condition string (with or without `{{ }}`).
|
|
62
|
+
* @param context - The sandboxed evaluation context.
|
|
63
|
+
* @returns `true` if the condition is satisfied, `false` otherwise.
|
|
64
|
+
* @throws {ParseError} on syntax errors.
|
|
65
|
+
* @throws {EvaluationError} on runtime errors (unknown functions, type mismatches).
|
|
66
|
+
*/
|
|
67
|
+
export function evaluateCondition(condition, context) {
|
|
68
|
+
const ast = parseExpression(condition);
|
|
69
|
+
const result = evaluate(ast, context);
|
|
70
|
+
return Boolean(result);
|
|
71
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expression Lexer (Tokenizer)
|
|
3
|
+
*
|
|
4
|
+
* Converts a condition string (with optional `{{ }}` delimiters) into a
|
|
5
|
+
* flat token stream. Each token carries source-position info for error
|
|
6
|
+
* reporting downstream.
|
|
7
|
+
*/
|
|
8
|
+
export type TokenType = 'Identifier' | 'BooleanLiteral' | 'StringLiteral' | 'NumberLiteral' | 'Operator' | 'LeftParen' | 'RightParen' | 'Comma' | 'EOF';
|
|
9
|
+
/** Source position within the *inner* expression (after delimiter stripping). */
|
|
10
|
+
export interface SourcePosition {
|
|
11
|
+
/** 0-based character offset */
|
|
12
|
+
readonly offset: number;
|
|
13
|
+
/** 1-based column (same as offset + 1 since expressions are single-line) */
|
|
14
|
+
readonly column: number;
|
|
15
|
+
}
|
|
16
|
+
export interface Token {
|
|
17
|
+
readonly type: TokenType;
|
|
18
|
+
readonly value: string;
|
|
19
|
+
readonly position: SourcePosition;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Error thrown when the lexer or parser encounters invalid input.
|
|
23
|
+
* Carries source-position information for precise error messages.
|
|
24
|
+
*/
|
|
25
|
+
export declare class ParseError extends Error {
|
|
26
|
+
readonly position: SourcePosition;
|
|
27
|
+
constructor(message: string, position: SourcePosition);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Tokenize a condition string into a flat token array.
|
|
31
|
+
*
|
|
32
|
+
* @param input - The condition string, optionally wrapped in `{{ }}`.
|
|
33
|
+
* @returns An array of tokens ending with an `EOF` token.
|
|
34
|
+
* @throws {ParseError} on unexpected characters or unterminated strings.
|
|
35
|
+
*/
|
|
36
|
+
export declare function tokenize(input: string): Token[];
|
|
37
|
+
//# sourceMappingURL=lexer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lexer.d.ts","sourceRoot":"","sources":["../../../../src/workflow/expression/lexer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,MAAM,SAAS,GACjB,YAAY,GACZ,gBAAgB,GAChB,eAAe,GACf,eAAe,GACf,UAAU,GACV,WAAW,GACX,YAAY,GACZ,OAAO,GACP,KAAK,CAAA;AAET,iFAAiF;AACjF,MAAM,WAAW,cAAc;IAC7B,+BAA+B;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;CAClC;AAMD;;;GAGG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;gBAErB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc;CAKtD;AAsED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE,CAsF/C"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expression Lexer (Tokenizer)
|
|
3
|
+
*
|
|
4
|
+
* Converts a condition string (with optional `{{ }}` delimiters) into a
|
|
5
|
+
* flat token stream. Each token carries source-position info for error
|
|
6
|
+
* reporting downstream.
|
|
7
|
+
*/
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// ParseError
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
/**
|
|
12
|
+
* Error thrown when the lexer or parser encounters invalid input.
|
|
13
|
+
* Carries source-position information for precise error messages.
|
|
14
|
+
*/
|
|
15
|
+
export class ParseError extends Error {
|
|
16
|
+
position;
|
|
17
|
+
constructor(message, position) {
|
|
18
|
+
super(`${message} at column ${position.column}`);
|
|
19
|
+
this.name = 'ParseError';
|
|
20
|
+
this.position = position;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Keyword sets
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
const OPERATORS = new Set([
|
|
27
|
+
'and', 'or', 'not',
|
|
28
|
+
'eq', 'neq', 'gt', 'lt', 'gte', 'lte',
|
|
29
|
+
]);
|
|
30
|
+
const BOOLEAN_LITERALS = new Set(['true', 'false']);
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Helpers
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
function isWhitespace(ch) {
|
|
35
|
+
return ch === ' ' || ch === '\t' || ch === '\n' || ch === '\r';
|
|
36
|
+
}
|
|
37
|
+
function isDigit(ch) {
|
|
38
|
+
return ch >= '0' && ch <= '9';
|
|
39
|
+
}
|
|
40
|
+
function isIdentStart(ch) {
|
|
41
|
+
return (ch >= 'a' && ch <= 'z') ||
|
|
42
|
+
(ch >= 'A' && ch <= 'Z') ||
|
|
43
|
+
ch === '_';
|
|
44
|
+
}
|
|
45
|
+
function isIdentChar(ch) {
|
|
46
|
+
return isIdentStart(ch) || isDigit(ch);
|
|
47
|
+
}
|
|
48
|
+
function pos(offset) {
|
|
49
|
+
return { offset, column: offset + 1 };
|
|
50
|
+
}
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
// Strip delimiters
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
/**
|
|
55
|
+
* Remove the `{{ }}` Handlebars-style delimiters from a condition string.
|
|
56
|
+
* Returns the inner content and the offset of the inner content within
|
|
57
|
+
* the original string (so positions map back correctly).
|
|
58
|
+
*/
|
|
59
|
+
function stripDelimiters(input) {
|
|
60
|
+
const trimmed = input.trim();
|
|
61
|
+
if (trimmed.startsWith('{{') && trimmed.endsWith('}}')) {
|
|
62
|
+
const openIdx = input.indexOf('{{');
|
|
63
|
+
// +2 to skip past the opening {{
|
|
64
|
+
const innerStart = openIdx + 2;
|
|
65
|
+
const closeIdx = input.lastIndexOf('}}');
|
|
66
|
+
return {
|
|
67
|
+
inner: input.slice(innerStart, closeIdx),
|
|
68
|
+
offset: innerStart,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// No delimiters — treat as raw expression
|
|
72
|
+
return { inner: input, offset: 0 };
|
|
73
|
+
}
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
// Tokenize
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
/**
|
|
78
|
+
* Tokenize a condition string into a flat token array.
|
|
79
|
+
*
|
|
80
|
+
* @param input - The condition string, optionally wrapped in `{{ }}`.
|
|
81
|
+
* @returns An array of tokens ending with an `EOF` token.
|
|
82
|
+
* @throws {ParseError} on unexpected characters or unterminated strings.
|
|
83
|
+
*/
|
|
84
|
+
export function tokenize(input) {
|
|
85
|
+
const { inner } = stripDelimiters(input);
|
|
86
|
+
const tokens = [];
|
|
87
|
+
let i = 0;
|
|
88
|
+
while (i < inner.length) {
|
|
89
|
+
const ch = inner[i];
|
|
90
|
+
// Skip whitespace
|
|
91
|
+
if (isWhitespace(ch)) {
|
|
92
|
+
i++;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
// Single-quoted string literal
|
|
96
|
+
if (ch === "'") {
|
|
97
|
+
const start = i;
|
|
98
|
+
i++; // skip opening quote
|
|
99
|
+
let value = '';
|
|
100
|
+
while (i < inner.length && inner[i] !== "'") {
|
|
101
|
+
value += inner[i];
|
|
102
|
+
i++;
|
|
103
|
+
}
|
|
104
|
+
if (i >= inner.length) {
|
|
105
|
+
throw new ParseError('Unterminated string literal', pos(start));
|
|
106
|
+
}
|
|
107
|
+
i++; // skip closing quote
|
|
108
|
+
tokens.push({ type: 'StringLiteral', value, position: pos(start) });
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
// Number literal
|
|
112
|
+
if (isDigit(ch) || (ch === '-' && i + 1 < inner.length && isDigit(inner[i + 1]))) {
|
|
113
|
+
const start = i;
|
|
114
|
+
if (ch === '-')
|
|
115
|
+
i++; // consume negative sign
|
|
116
|
+
while (i < inner.length && isDigit(inner[i]))
|
|
117
|
+
i++;
|
|
118
|
+
// Decimal part
|
|
119
|
+
if (i < inner.length && inner[i] === '.' && i + 1 < inner.length && isDigit(inner[i + 1])) {
|
|
120
|
+
i++; // skip dot
|
|
121
|
+
while (i < inner.length && isDigit(inner[i]))
|
|
122
|
+
i++;
|
|
123
|
+
}
|
|
124
|
+
tokens.push({ type: 'NumberLiteral', value: inner.slice(start, i), position: pos(start) });
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
// Identifiers, keywords, operators, boolean literals
|
|
128
|
+
if (isIdentStart(ch)) {
|
|
129
|
+
const start = i;
|
|
130
|
+
while (i < inner.length && isIdentChar(inner[i]))
|
|
131
|
+
i++;
|
|
132
|
+
const word = inner.slice(start, i);
|
|
133
|
+
if (BOOLEAN_LITERALS.has(word)) {
|
|
134
|
+
tokens.push({ type: 'BooleanLiteral', value: word, position: pos(start) });
|
|
135
|
+
}
|
|
136
|
+
else if (OPERATORS.has(word)) {
|
|
137
|
+
tokens.push({ type: 'Operator', value: word, position: pos(start) });
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
tokens.push({ type: 'Identifier', value: word, position: pos(start) });
|
|
141
|
+
}
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
// Parentheses
|
|
145
|
+
if (ch === '(') {
|
|
146
|
+
tokens.push({ type: 'LeftParen', value: '(', position: pos(i) });
|
|
147
|
+
i++;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (ch === ')') {
|
|
151
|
+
tokens.push({ type: 'RightParen', value: ')', position: pos(i) });
|
|
152
|
+
i++;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
// Comma
|
|
156
|
+
if (ch === ',') {
|
|
157
|
+
tokens.push({ type: 'Comma', value: ',', position: pos(i) });
|
|
158
|
+
i++;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
// Unknown character
|
|
162
|
+
throw new ParseError(`Unexpected character '${ch}'`, pos(i));
|
|
163
|
+
}
|
|
164
|
+
tokens.push({ type: 'EOF', value: '', position: pos(i) });
|
|
165
|
+
return tokens;
|
|
166
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expression Parser (Recursive Descent)
|
|
3
|
+
*
|
|
4
|
+
* Parses a token stream (produced by the lexer) into a typed AST.
|
|
5
|
+
*
|
|
6
|
+
* Operator precedence (lowest to highest):
|
|
7
|
+
* 1. `or`
|
|
8
|
+
* 2. `and`
|
|
9
|
+
* 3. comparisons: `eq`, `neq`, `gt`, `lt`, `gte`, `lte`
|
|
10
|
+
* 4. `not` (unary prefix)
|
|
11
|
+
* 5. primary: literals, variable refs, function calls, parenthesized exprs
|
|
12
|
+
*/
|
|
13
|
+
import type { ASTNode } from './ast.js';
|
|
14
|
+
import type { Token } from './lexer.js';
|
|
15
|
+
/**
|
|
16
|
+
* Parse a token stream into an AST.
|
|
17
|
+
*
|
|
18
|
+
* @param tokens - Token array produced by `tokenize()`.
|
|
19
|
+
* @returns The root AST node.
|
|
20
|
+
* @throws {ParseError} on syntax errors.
|
|
21
|
+
*/
|
|
22
|
+
export declare function parse(tokens: Token[]): ASTNode;
|
|
23
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../../src/workflow/expression/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAyLvC;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAkB9C"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expression Parser (Recursive Descent)
|
|
3
|
+
*
|
|
4
|
+
* Parses a token stream (produced by the lexer) into a typed AST.
|
|
5
|
+
*
|
|
6
|
+
* Operator precedence (lowest to highest):
|
|
7
|
+
* 1. `or`
|
|
8
|
+
* 2. `and`
|
|
9
|
+
* 3. comparisons: `eq`, `neq`, `gt`, `lt`, `gte`, `lte`
|
|
10
|
+
* 4. `not` (unary prefix)
|
|
11
|
+
* 5. primary: literals, variable refs, function calls, parenthesized exprs
|
|
12
|
+
*/
|
|
13
|
+
import { ParseError } from './lexer.js';
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Operator sets
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
const COMPARISON_OPERATORS = new Set(['eq', 'neq', 'gt', 'lt', 'gte', 'lte']);
|
|
18
|
+
function peek(state) {
|
|
19
|
+
return state.tokens[state.pos];
|
|
20
|
+
}
|
|
21
|
+
function advance(state) {
|
|
22
|
+
const token = state.tokens[state.pos];
|
|
23
|
+
state.pos++;
|
|
24
|
+
return token;
|
|
25
|
+
}
|
|
26
|
+
function expect(state, type, value) {
|
|
27
|
+
const token = peek(state);
|
|
28
|
+
if (token.type !== type || (value !== undefined && token.value !== value)) {
|
|
29
|
+
const expected = value ? `'${value}'` : type;
|
|
30
|
+
const got = token.type === 'EOF' ? 'end of expression' : `'${token.value}'`;
|
|
31
|
+
throw new ParseError(`Expected ${expected} but got ${got}`, token.position);
|
|
32
|
+
}
|
|
33
|
+
return advance(state);
|
|
34
|
+
}
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Grammar rules
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
/**
|
|
39
|
+
* expression := orExpr
|
|
40
|
+
*/
|
|
41
|
+
function parseExpression(state) {
|
|
42
|
+
return parseOr(state);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* orExpr := andExpr ( 'or' andExpr )*
|
|
46
|
+
*/
|
|
47
|
+
function parseOr(state) {
|
|
48
|
+
let left = parseAnd(state);
|
|
49
|
+
while (peek(state).type === 'Operator' && peek(state).value === 'or') {
|
|
50
|
+
advance(state); // consume 'or'
|
|
51
|
+
const right = parseAnd(state);
|
|
52
|
+
left = { type: 'BinaryOp', operator: 'or', left, right };
|
|
53
|
+
}
|
|
54
|
+
return left;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* andExpr := comparisonExpr ( 'and' comparisonExpr )*
|
|
58
|
+
*/
|
|
59
|
+
function parseAnd(state) {
|
|
60
|
+
let left = parseComparison(state);
|
|
61
|
+
while (peek(state).type === 'Operator' && peek(state).value === 'and') {
|
|
62
|
+
advance(state); // consume 'and'
|
|
63
|
+
const right = parseComparison(state);
|
|
64
|
+
left = { type: 'BinaryOp', operator: 'and', left, right };
|
|
65
|
+
}
|
|
66
|
+
return left;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* comparisonExpr := unaryExpr ( ('eq'|'neq'|'gt'|'lt'|'gte'|'lte') unaryExpr )?
|
|
70
|
+
*
|
|
71
|
+
* Comparisons are non-associative (no chaining).
|
|
72
|
+
*/
|
|
73
|
+
function parseComparison(state) {
|
|
74
|
+
let left = parseUnary(state);
|
|
75
|
+
const token = peek(state);
|
|
76
|
+
if (token.type === 'Operator' && COMPARISON_OPERATORS.has(token.value)) {
|
|
77
|
+
const operator = advance(state).value;
|
|
78
|
+
const right = parseUnary(state);
|
|
79
|
+
left = { type: 'BinaryOp', operator, left, right };
|
|
80
|
+
}
|
|
81
|
+
return left;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* unaryExpr := 'not' unaryExpr | primaryExpr
|
|
85
|
+
*/
|
|
86
|
+
function parseUnary(state) {
|
|
87
|
+
const token = peek(state);
|
|
88
|
+
if (token.type === 'Operator' && token.value === 'not') {
|
|
89
|
+
advance(state); // consume 'not'
|
|
90
|
+
const operand = parseUnary(state);
|
|
91
|
+
return { type: 'UnaryOp', operator: 'not', operand };
|
|
92
|
+
}
|
|
93
|
+
return parsePrimary(state);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* primaryExpr := BooleanLiteral
|
|
97
|
+
* | StringLiteral
|
|
98
|
+
* | NumberLiteral
|
|
99
|
+
* | Identifier '(' argList? ')' -- function call
|
|
100
|
+
* | Identifier -- variable ref
|
|
101
|
+
* | '(' expression ')' -- grouped sub-expression
|
|
102
|
+
*/
|
|
103
|
+
function parsePrimary(state) {
|
|
104
|
+
const token = peek(state);
|
|
105
|
+
// Boolean literal
|
|
106
|
+
if (token.type === 'BooleanLiteral') {
|
|
107
|
+
advance(state);
|
|
108
|
+
return { type: 'BooleanLiteral', value: token.value === 'true' };
|
|
109
|
+
}
|
|
110
|
+
// String literal
|
|
111
|
+
if (token.type === 'StringLiteral') {
|
|
112
|
+
advance(state);
|
|
113
|
+
return { type: 'StringLiteral', value: token.value };
|
|
114
|
+
}
|
|
115
|
+
// Number literal
|
|
116
|
+
if (token.type === 'NumberLiteral') {
|
|
117
|
+
advance(state);
|
|
118
|
+
return { type: 'NumberLiteral', value: Number(token.value) };
|
|
119
|
+
}
|
|
120
|
+
// Identifier — could be variable ref or function call
|
|
121
|
+
if (token.type === 'Identifier') {
|
|
122
|
+
advance(state);
|
|
123
|
+
// Check for function call: Identifier '(' ...
|
|
124
|
+
if (peek(state).type === 'LeftParen') {
|
|
125
|
+
advance(state); // consume '('
|
|
126
|
+
const args = parseArgList(state);
|
|
127
|
+
expect(state, 'RightParen');
|
|
128
|
+
return { type: 'FunctionCall', name: token.value, args };
|
|
129
|
+
}
|
|
130
|
+
return { type: 'VariableRef', name: token.value };
|
|
131
|
+
}
|
|
132
|
+
// Parenthesized sub-expression
|
|
133
|
+
if (token.type === 'LeftParen') {
|
|
134
|
+
advance(state); // consume '('
|
|
135
|
+
const expr = parseExpression(state);
|
|
136
|
+
expect(state, 'RightParen');
|
|
137
|
+
return expr;
|
|
138
|
+
}
|
|
139
|
+
// Error: unexpected token
|
|
140
|
+
const got = token.type === 'EOF' ? 'end of expression' : `'${token.value}'`;
|
|
141
|
+
throw new ParseError(`Unexpected ${got}`, token.position);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* argList := expression ( ',' expression )*
|
|
145
|
+
* | (empty)
|
|
146
|
+
*/
|
|
147
|
+
function parseArgList(state) {
|
|
148
|
+
const args = [];
|
|
149
|
+
if (peek(state).type === 'RightParen') {
|
|
150
|
+
return args;
|
|
151
|
+
}
|
|
152
|
+
args.push(parseExpression(state));
|
|
153
|
+
while (peek(state).type === 'Comma') {
|
|
154
|
+
advance(state); // consume ','
|
|
155
|
+
args.push(parseExpression(state));
|
|
156
|
+
}
|
|
157
|
+
return args;
|
|
158
|
+
}
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
// Public API
|
|
161
|
+
// ---------------------------------------------------------------------------
|
|
162
|
+
/**
|
|
163
|
+
* Parse a token stream into an AST.
|
|
164
|
+
*
|
|
165
|
+
* @param tokens - Token array produced by `tokenize()`.
|
|
166
|
+
* @returns The root AST node.
|
|
167
|
+
* @throws {ParseError} on syntax errors.
|
|
168
|
+
*/
|
|
169
|
+
export function parse(tokens) {
|
|
170
|
+
if (tokens.length === 0 || (tokens.length === 1 && tokens[0].type === 'EOF')) {
|
|
171
|
+
throw new ParseError('Empty expression', { offset: 0, column: 1 });
|
|
172
|
+
}
|
|
173
|
+
const state = { tokens, pos: 0 };
|
|
174
|
+
const ast = parseExpression(state);
|
|
175
|
+
// Ensure all tokens were consumed (except EOF)
|
|
176
|
+
const remaining = peek(state);
|
|
177
|
+
if (remaining.type !== 'EOF') {
|
|
178
|
+
throw new ParseError(`Unexpected '${remaining.value}' after expression`, remaining.position);
|
|
179
|
+
}
|
|
180
|
+
return ast;
|
|
181
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gate State Persistence Layer
|
|
3
|
+
*
|
|
4
|
+
* Manages gate lifecycle state for workflow execution gates (signal, timer, webhook).
|
|
5
|
+
* Uses a storage adapter pattern so that packages/core does not depend on
|
|
6
|
+
* packages/server (Redis) directly.
|
|
7
|
+
*
|
|
8
|
+
* Gates are external conditions that can pause workflow phase transitions until
|
|
9
|
+
* a condition is met (e.g., human approval signal, timer expiration, webhook callback).
|
|
10
|
+
*/
|
|
11
|
+
import type { GateDefinition } from './workflow-types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Persisted state for a single gate instance tied to an issue
|
|
14
|
+
*/
|
|
15
|
+
export interface GateState {
|
|
16
|
+
/** The issue this gate is associated with */
|
|
17
|
+
issueId: string;
|
|
18
|
+
/** Unique gate name (from GateDefinition) */
|
|
19
|
+
gateName: string;
|
|
20
|
+
/** Gate type: signal (external event), timer (time-based), webhook (HTTP callback) */
|
|
21
|
+
gateType: 'signal' | 'timer' | 'webhook';
|
|
22
|
+
/** Current gate status */
|
|
23
|
+
status: 'pending' | 'active' | 'satisfied' | 'timed-out';
|
|
24
|
+
/** When the gate was triggered (phase entered), epoch ms */
|
|
25
|
+
activatedAt: number;
|
|
26
|
+
/** When the gate condition was met, epoch ms */
|
|
27
|
+
satisfiedAt?: number;
|
|
28
|
+
/** When the timeout fired, epoch ms */
|
|
29
|
+
timedOutAt?: number;
|
|
30
|
+
/** Action to take when gate times out */
|
|
31
|
+
timeoutAction?: 'escalate' | 'skip' | 'fail';
|
|
32
|
+
/** What satisfied the gate (comment ID, webhook payload hash, timer ID) */
|
|
33
|
+
signalSource?: string;
|
|
34
|
+
/** Authentication token for webhook gates (used to validate incoming callbacks) */
|
|
35
|
+
webhookToken?: string;
|
|
36
|
+
/** Duration string from gate definition (e.g., "4h") */
|
|
37
|
+
timeoutDuration?: string;
|
|
38
|
+
/** Computed absolute timestamp for timeout deadline, epoch ms */
|
|
39
|
+
timeoutDeadline?: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Storage adapter for gate state persistence.
|
|
43
|
+
* Implementations can back this with Redis, in-memory maps, etc.
|
|
44
|
+
*/
|
|
45
|
+
export interface GateStorage {
|
|
46
|
+
/** Get the state of a specific gate for an issue */
|
|
47
|
+
getGateState(issueId: string, gateName: string): Promise<GateState | null>;
|
|
48
|
+
/** Set the state of a specific gate for an issue */
|
|
49
|
+
setGateState(issueId: string, gateName: string, state: GateState): Promise<void>;
|
|
50
|
+
/** Get all active (status === 'active') gates for an issue */
|
|
51
|
+
getActiveGates(issueId: string): Promise<GateState[]>;
|
|
52
|
+
/** Clear all gate states for an issue */
|
|
53
|
+
clearGateStates(issueId: string): Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* In-memory gate storage for testing and local development
|
|
57
|
+
*/
|
|
58
|
+
export declare class InMemoryGateStorage implements GateStorage {
|
|
59
|
+
private store;
|
|
60
|
+
/** Build a composite key from issueId and gateName */
|
|
61
|
+
private key;
|
|
62
|
+
getGateState(issueId: string, gateName: string): Promise<GateState | null>;
|
|
63
|
+
setGateState(issueId: string, gateName: string, state: GateState): Promise<void>;
|
|
64
|
+
getActiveGates(issueId: string): Promise<GateState[]>;
|
|
65
|
+
clearGateStates(issueId: string): Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Initialize the gate state manager with a storage adapter.
|
|
69
|
+
* Must be called before using gate state management functions.
|
|
70
|
+
*/
|
|
71
|
+
export declare function initGateStorage(storage: GateStorage): void;
|
|
72
|
+
/**
|
|
73
|
+
* Parse a duration string into milliseconds.
|
|
74
|
+
*
|
|
75
|
+
* Supported formats:
|
|
76
|
+
* - "15s" - seconds
|
|
77
|
+
* - "30m" - minutes
|
|
78
|
+
* - "4h" - hours
|
|
79
|
+
* - "2d" - days
|
|
80
|
+
*
|
|
81
|
+
* @param duration - Duration string (e.g., "4h", "30m", "2d", "15s")
|
|
82
|
+
* @returns Duration in milliseconds
|
|
83
|
+
* @throws Error if the duration format is invalid
|
|
84
|
+
*/
|
|
85
|
+
export declare function parseDuration(duration: string): number;
|
|
86
|
+
/**
|
|
87
|
+
* Activate a gate for an issue, creating an active gate state with a computed
|
|
88
|
+
* timeout deadline (if the gate definition includes a timeout).
|
|
89
|
+
*
|
|
90
|
+
* @param issueId - The issue identifier
|
|
91
|
+
* @param gateDef - The gate definition from the workflow
|
|
92
|
+
* @param storage - The gate storage adapter to use
|
|
93
|
+
* @returns The created GateState
|
|
94
|
+
*/
|
|
95
|
+
export declare function activateGate(issueId: string, gateDef: GateDefinition, storage: GateStorage): Promise<GateState>;
|
|
96
|
+
/**
|
|
97
|
+
* Mark a gate as satisfied, recording what source satisfied it.
|
|
98
|
+
*
|
|
99
|
+
* @param issueId - The issue identifier
|
|
100
|
+
* @param gateName - The gate name to satisfy
|
|
101
|
+
* @param source - What satisfied the gate (e.g., comment ID, webhook payload hash, timer ID)
|
|
102
|
+
* @param storage - The gate storage adapter to use
|
|
103
|
+
* @returns The updated GateState, or null if the gate was not found
|
|
104
|
+
*/
|
|
105
|
+
export declare function satisfyGate(issueId: string, gateName: string, source: string, storage: GateStorage): Promise<GateState | null>;
|
|
106
|
+
/**
|
|
107
|
+
* Mark a gate as timed-out.
|
|
108
|
+
*
|
|
109
|
+
* @param issueId - The issue identifier
|
|
110
|
+
* @param gateName - The gate name to time out
|
|
111
|
+
* @param storage - The gate storage adapter to use
|
|
112
|
+
* @returns The updated GateState, or null if the gate was not found
|
|
113
|
+
*/
|
|
114
|
+
export declare function timeoutGate(issueId: string, gateName: string, storage: GateStorage): Promise<GateState | null>;
|
|
115
|
+
//# sourceMappingURL=gate-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-state.d.ts","sourceRoot":"","sources":["../../../src/workflow/gate-state.ts"],"names":[],"mappings":"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"}
|